package de.tum.in.tumcampusapp.cards.generic;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import de.tum.in.tumcampusapp.R;
import de.tum.in.tumcampusapp.activities.UserPreferencesActivity;
import de.tum.in.tumcampusapp.auxiliary.Const;
import de.tum.in.tumcampusapp.auxiliary.ImplicitCounter;
import de.tum.in.tumcampusapp.managers.CardManager;
/**
* Base class for all cards
*/
public abstract class Card {
public static final String DISCARD_SETTINGS_START = "discard_settings_start";
public static final String DISCARD_SETTINGS_PHONE = "discard_settings_phone";
// Context related stuff
protected Context mContext;
// UI Elements
protected View mCard;
protected LinearLayout mLinearLayout;
protected TextView mTitleView;
private final String mSettings;
// Settings for showing this card on start page or as notification
// Default values set for restore card, no internet card, etc.
private boolean mShowStart = true;
protected boolean mShowWear;
protected boolean mShowPhone;
private final int cardType;
/**
* Card constructor for special cards that don't have a preference screen
*
* @param context Context
*/
public Card(int cardType, Context context) {
this(cardType, context, null);
}
/**
* Standard card constructor.
*
* @param context Context
* @param settings Preference key prefix used for all preferences belonging to that card
*/
public Card(int cardType, Context context, String settings) {
this.cardType = cardType;
mSettings = settings;
mContext = context;
}
/**
* Card constructor that can set special default values for wear and phone
*
* @param context Context
* @param settings Preference key prefix used for all preferences belonging to that card
* @param wearDefault True if notifications should by default be displayed on android wear
* @param phoneDefault True if notifications should by default be displayed on the phone
*/
public Card(int cardType, Context context, String settings, boolean wearDefault, boolean phoneDefault) {
this(cardType, context, settings);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
mShowStart = prefs.getBoolean(settings + "_start", true);
mShowWear = prefs.getBoolean(settings + "_wear", wearDefault);
mShowPhone = prefs.getBoolean(settings + "_phone", phoneDefault);
}
/**
* Gets the card type
*
* @return Returns an individual integer for each card type
*/
public final int getType() {
return cardType;
}
/**
* Updates the Cards content.
* Override this method, if the card contains any dynamic content, that is not already in its XML
*
* @param viewHolder The Card specific view holder
*/
public void updateViewHolder(RecyclerView.ViewHolder viewHolder) {
mContext = viewHolder.itemView.getContext();
ImplicitCounter.countCard(mContext, this);
}
/**
* Adds a new text view to the main card layout
*
* @param text Text that should be shown
* @return Handle to the {@link TextView}
*/
protected TextView addTextView(CharSequence text) {
TextView textview = new TextView(mContext);
textview.setText(text);
//Give some space to the other stuff on the card
int padding = (int) mContext.getResources().getDimension(R.dimen.card_text_padding);
textview.setPadding(padding, 0, padding, 0);
mLinearLayout.addView(textview);
return textview;
}
/**
* Should be called after the user has dismissed the card
*/
public void discardCard() {
SharedPreferences prefs = mContext.getSharedPreferences(DISCARD_SETTINGS_START, 0);
Editor editor = prefs.edit();
discard(editor);
editor.apply();
}
/**
* Save information about the dismissed card/notification to decide later if the card should be shown again
*
* @param editor Editor to be used for saving values
*/
protected abstract void discard(Editor editor);
/**
* Must be called after information has been set
* Adds the card to CardManager if not dismissed before and notifies the user
*/
public void apply() {
// Should be shown on start page?
if (mShowStart) {
SharedPreferences prefs = mContext.getSharedPreferences(DISCARD_SETTINGS_START, 0);
if (shouldShow(prefs)) {
CardManager.addCard(this);
}
}
}
/**
* Determines if the card should be shown. Decision is based on the given SharedPreferences.
* This method should be overridden in most cases.
*
* @return returns true if the card should be shown
*/
protected boolean shouldShow(SharedPreferences prefs) {
return true;
}
/**
* @return Should return the intent that should be launched if the card
* or the notification gets clicked, null if nothing should happen
*/
public abstract Intent getIntent();
/**
* Tells the list adapter and indirectly the
* SwipeDismissList if the item is dismissible
* The restore card is not dismissible.
*/
public boolean isDismissible() {
return true;
}
/**
* Gets the prefix that is used for all preference key's belonging to that card
*
* @return Key prefix e.g. "card_cafeteria"
*/
public String getSettings() {
return mSettings;
}
/**
* Sets preferences so that this card does not show up again until
* reactivated manually by the user
*/
public void hideAlways() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
Editor e = prefs.edit();
e.putBoolean(mSettings + "_start", false);
e.putBoolean(mSettings + "_wear", false);
e.putBoolean(mSettings + "_phone", false);
e.apply();
}
/**
* @return a unique identifier among the type of the card
*/
public abstract int getId();
@Nullable
public RemoteViews getRemoteViews(Context context) {
return null;
}
/**
* Interface which has to be implemented by a manager class to add cards to the stream
*/
public interface ProvidesCard {
/**
* Gets called whenever cards need to be shown or refreshed.
* This method should decide whether a card can be displayed and if so
* call {@link Card#apply()} to tell the card manager.
*
* @param context Context
*/
void onRequestCard(Context context);
}
public static class CardViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener, PopupMenu.OnMenuItemClickListener {
private Card current;
private List<View> addedViews = new ArrayList<>();
private final Activity mActivity;
public CardViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
mActivity = (Activity) itemView.getContext();
}
public Card getCurrentCard() {
return current;
}
public void setCurrentCard(Card current) {
this.current = current;
}
public List<View> getAddedViews() {
return addedViews;
}
public void setAddedViews(List<View> addedViews) {
this.addedViews = addedViews;
}
@Override
public void onClick(View v) {
Intent i = current.getIntent();
String transitionName = mActivity.getString(R.string.transition_card);
if (i != null) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
mActivity, v, transitionName
);
ActivityCompat.startActivity(mActivity, i, options.toBundle());
}
}
@Override
public boolean onLongClick(View v) {
String key = current.getSettings();
if (key == null) {
return false;
}
PopupMenu menu = new PopupMenu(v.getContext(), v, Gravity.CENTER_HORIZONTAL);
MenuInflater inf = menu.getMenuInflater();
inf.inflate(R.menu.card_popup_menu, menu.getMenu());
menu.setOnMenuItemClickListener(this);
menu.show();
return true;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
int i = item.getItemId();
if (i == R.id.open_card_setting) {// Open card's preference screen
String key = current.getSettings();
if (key == null) {
return true;
}
Intent intent = new Intent(itemView.getContext(), UserPreferencesActivity.class);
intent.putExtra(Const.PREFERENCE_SCREEN, key);
itemView.getContext().startActivity(intent);
return true;
} else if (i == R.id.always_hide_card) {
current.hideAlways();
current.discardCard();
return true;
} else {
return false;
}
}
}
}