Convert ViewHolder Code to kotlin

This commit is contained in:
ligi 2016-10-28 17:14:18 +02:00
parent 74d4fbe409
commit 6f969f4217
No known key found for this signature in database
GPG key ID: 8E81894010ABF23D
13 changed files with 301 additions and 364 deletions

View file

@ -1,49 +1,49 @@
package org.ligi.passandroid.actions;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.provider.CalendarContract;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.view.View;
import org.ligi.passandroid.R;
import org.ligi.passandroid.model.pass.Pass;
import org.threeten.bp.ZonedDateTime;
public class AddToCalendar {
public static void tryAddDateToCalendar(final Pass pass, final Activity activity, final ZonedDateTime date) {
public static void tryAddDateToCalendar(final Pass pass, final View contextView, final ZonedDateTime date) {
if (pass.getCalendarTimespan() == null) {
new AlertDialog.Builder(activity).setMessage(R.string.expiration_date_to_calendar_warning_message)
.setTitle(R.string.expiration_date_to_calendar_warning_title)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
reallyAddToCalendar(pass, activity, date);
}
})
.show();
new AlertDialog.Builder(contextView.getContext()).setMessage(R.string.expiration_date_to_calendar_warning_message)
.setTitle(R.string.expiration_date_to_calendar_warning_title)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
reallyAddToCalendar(pass, contextView, date);
}
})
.show();
} else {
reallyAddToCalendar(pass, activity, date);
reallyAddToCalendar(pass, contextView, date);
}
}
private static void reallyAddToCalendar(Pass pass, Activity activity, ZonedDateTime date) {
private static void reallyAddToCalendar(Pass pass, View contextView, ZonedDateTime date) {
try {
final Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, date.toEpochSecond() * 1000);
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, date.plusHours(1).toEpochSecond() * 1000);
intent.putExtra("title", pass.getDescription());
activity.startActivity(intent);
contextView.getContext().startActivity(intent);
} catch (ActivityNotFoundException exception) {
// TODO maybe action to install calendar app
Snackbar.make(activity.getWindow().getDecorView(), R.string.no_calendar_app_found, Snackbar.LENGTH_LONG).show();
Snackbar.make(contextView, R.string.no_calendar_app_found, Snackbar.LENGTH_LONG).show();
}
}

View file

@ -41,7 +41,7 @@ public class PassAdapter extends RecyclerView.Adapter<PassViewHolder> {
public PassViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
final LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
final View res = inflater.inflate(R.layout.pass_list_item, viewGroup, false);
final CardView res = (CardView) inflater.inflate(R.layout.pass_list_item, viewGroup, false);
if (settings.isCondensedModeEnabled()) {
return new CondensedPassViewHolder(res);
} else {
@ -56,7 +56,7 @@ public class PassAdapter extends RecyclerView.Adapter<PassViewHolder> {
viewHolder.apply(pass, passStore, passListActivity);
final CardView root = viewHolder.root;
final CardView root = viewHolder.getView();
root.setOnClickListener(new View.OnClickListener() {
@Override

View file

@ -88,7 +88,7 @@ class PassViewActivity : PassViewActivityBase() {
Linkify.addLinks(back_fields, Linkify.ALL)
val passViewHolder = VerbosePassViewHolder(findViewById(R.id.pass_card))
val passViewHolder = VerbosePassViewHolder(pass_card)
passViewHolder.apply(pass, passStore, this)
}

View file

@ -1,31 +0,0 @@
package org.ligi.passandroid.ui.pass_view_holder;
import android.app.Activity;
import android.view.View;
import org.ligi.passandroid.model.PassStore;
import org.ligi.passandroid.model.pass.Pass;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
public class CondensedPassViewHolder extends PassViewHolder {
public CondensedPassViewHolder(View view) {
super(view);
}
@Override
public void apply(Pass pass, PassStore passStore, Activity activity) {
super.apply(pass, passStore, activity);
final String extraString = getExtraString();
if (extraString != null && !extraString.isEmpty()) {
dateOrExtraText.setText(extraString);
dateOrExtraText.setVisibility(VISIBLE);
} else {
dateOrExtraText.setVisibility(GONE);
}
addCalendar.setText(getTimeInfoString());
}
}

View file

@ -0,0 +1,27 @@
package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity
import android.support.v7.widget.CardView
import android.view.View
import kotlinx.android.synthetic.main.pass_list_item.view.*
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.Pass
class CondensedPassViewHolder(view: CardView) : PassViewHolder(view) {
override fun apply(pass: Pass, passStore: PassStore, activity: Activity) {
super.apply(pass, passStore, activity)
val extraString = getExtraString(pass)
if (extraString.isNullOrBlank()) {
view.date.text = extraString
view.date.visibility = View.VISIBLE
} else {
view.date.visibility = View.GONE
}
view.addCalendar.text = getTimeInfoString(pass)
}
}

View file

@ -1,80 +0,0 @@
package org.ligi.passandroid.ui.pass_view_holder;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.DatePicker;
import android.widget.TimePicker;
import butterknife.OnClick;
import org.ligi.passandroid.R;
import org.ligi.passandroid.model.PassStore;
import org.ligi.passandroid.model.pass.Pass;
import org.ligi.passandroid.model.pass.PassImpl;
import org.ligi.passandroid.ui.Visibility;
import org.threeten.bp.ZonedDateTime;
import static android.view.View.VISIBLE;
public class EditViewHolder extends VerbosePassViewHolder implements TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener {
private ZonedDateTime time;
private final Context context;
public EditViewHolder(final View view) {
super(view);
context = view.getContext();
}
@OnClick(R.id.addCalendar)
void onCalendarClick() {
new DatePickerDialog(context, this, time.getYear(), time.getMonth().getValue() - 1, time.getDayOfMonth()).show();
}
@OnClick(R.id.navigateTo)
void onNavigateClick() {
new AlertDialog.Builder(context).setMessage("Not yet available").setPositiveButton(android.R.string.ok, null).show();
}
@Override
public void apply(final Pass pass, final PassStore passStore, final Activity activity) {
super.apply(pass, passStore, activity);
if (pass.getCalendarTimespan() != null) {
time = pass.getCalendarTimespan().getFrom();
} else {
time = ZonedDateTime.now();
}
}
@Visibility
@Override
protected int getVisibilityForGlobalAndLocal(final boolean global, final boolean local) {
return VISIBLE;
}
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
time = time.withYear(year).withMonth(monthOfYear + 1).withDayOfMonth(dayOfMonth);
pass.setCalendarTimespan(new PassImpl.TimeSpan(time, null, null));
new TimePickerDialog(context, this, time.getHour(), time.getMinute(), true).show();
}
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
time = time.withHour(hourOfDay).withMinute(minute);
pass.setCalendarTimespan(new PassImpl.TimeSpan(time, null, null));
apply(pass, passStore, activity);
}
}

View file

@ -0,0 +1,68 @@
package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.support.v7.app.AlertDialog
import android.support.v7.widget.CardView
import android.view.View.VISIBLE
import android.widget.DatePicker
import android.widget.TimePicker
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassImpl
import org.ligi.passandroid.ui.Visibility
import org.threeten.bp.ZonedDateTime
class EditViewHolder(view: CardView) : VerbosePassViewHolder(view), TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener {
lateinit private var time: ZonedDateTime
lateinit private var pass: PassImpl
lateinit private var passStore: PassStore
override fun clickAddToCalendar(pass: Pass) {
DatePickerDialog(view.context, this, time.year, time.month.value - 1, time.dayOfMonth).show()
}
override fun performNavigate(activity: Activity, pass: Pass) {
AlertDialog.Builder(view.context).setMessage("Not yet available").setPositiveButton(android.R.string.ok, null).show()
}
override fun apply(pass: Pass, passStore: PassStore, activity: Activity) {
super.apply(pass, passStore, activity)
this.pass = pass as PassImpl
this.passStore = passStore
val calendarTimespan = pass.calendarTimespan
time = if (calendarTimespan != null && calendarTimespan.from != null) {
calendarTimespan.from
} else {
ZonedDateTime.now()
}
}
@Visibility
override fun getVisibilityForGlobalAndLocal(global: Boolean, local: Boolean): Int {
return VISIBLE
}
override fun onDateSet(view: DatePicker, year: Int, monthOfYear: Int, dayOfMonth: Int) {
time = time.withYear(year).withMonth(monthOfYear + 1).withDayOfMonth(dayOfMonth)
pass.calendarTimespan = PassImpl.TimeSpan(time, null, null)
TimePickerDialog(itemView.context, this, time.hour, time.minute, true).show()
}
override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) {
time = time.withHour(hourOfDay).withMinute(minute)
pass.calendarTimespan = PassImpl.TimeSpan(time, null, null)
refresh(pass, passStore)
}
}

View file

@ -1,167 +0,0 @@
package org.ligi.passandroid.ui.pass_view_holder;
import android.app.Activity;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateUtils;
import android.view.View;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import org.ligi.passandroid.R;
import org.ligi.passandroid.actions.AddToCalendar;
import org.ligi.passandroid.model.PassBitmapDefinitions;
import org.ligi.passandroid.model.PassStore;
import org.ligi.passandroid.model.pass.Pass;
import org.ligi.passandroid.model.pass.PassField;
import org.ligi.passandroid.ui.NavigateToLocationsDialog;
import org.ligi.passandroid.ui.Visibility;
import org.ligi.passandroid.ui.views.CategoryIndicatorViewWithIcon;
import org.threeten.bp.ZonedDateTime;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
public abstract class PassViewHolder extends RecyclerView.ViewHolder {
public final CardView root;
@BindView(R.id.date)
TextView dateOrExtraText;
@BindView(R.id.passTitle)
TextView title;
@BindView(R.id.categoryView)
CategoryIndicatorViewWithIcon category;
@BindView(R.id.actions_separator)
View actionsSeparator;
@BindView(R.id.navigateTo)
TextView navigateTo;
@OnClick(R.id.navigateTo)
void navigateTo() {
NavigateToLocationsDialog.perform(activity, pass, false);
}
@BindView(R.id.addCalendar)
TextView addCalendar;
@OnClick(R.id.addCalendar)
void onCalendarClick() {
AddToCalendar.tryAddDateToCalendar(pass, activity, getDateOrExtraText());
}
public Pass pass;
protected Activity activity;
protected PassStore passStore;
public PassViewHolder(View view) {
super(view);
root = (CardView) view;
ButterKnife.bind(this, view);
}
public void apply(final Pass pass, final PassStore passStore, final Activity activity) {
this.pass = pass;
this.activity = activity;
this.passStore = passStore;
final boolean noButtons = getDateOrExtraText() == null && !(pass.getLocations().size() > 0);
actionsSeparator.setVisibility(getVisibilityForGlobalAndLocal(noButtons, true));
navigateTo.setVisibility(getVisibilityForGlobalAndLocal(noButtons, pass.getLocations().size() > 0));
addCalendar.setVisibility(getVisibilityForGlobalAndLocal(noButtons, getDateOrExtraText() != null));
final Bitmap iconBitmap = pass.getBitmap(passStore, PassBitmapDefinitions.BITMAP_ICON);
if (iconBitmap != null) {
category.setIcon(iconBitmap);
}
category.setImageByCategory(pass.getType());
category.setAccentColor(pass.getAccentColor());
title.setText(pass.getDescription());
}
@Nullable
protected String getExtraString() {
if (pass.getFields().size() > 0) {
return getExtraStringForField(pass.getFields().get(0));
}
return null;
}
private String getExtraStringForField(final PassField passField) {
final StringBuilder stringBuilder = new StringBuilder();
if (passField.getLabel()!=null) {
stringBuilder.append(passField.getLabel());
if (passField.getValue()!=null) {
stringBuilder.append(": ");
}
}
if (passField.getValue()!=null) {
stringBuilder.append(passField.getValue());
}
return stringBuilder.toString();
}
@NonNull
private String setDateTextFromDateAndPrefix(String prefix, @NonNull final ZonedDateTime relevantDate) {
final CharSequence relativeDateTimeString = DateUtils.getRelativeDateTimeString(activity,
relevantDate.toEpochSecond() * 1000,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.WEEK_IN_MILLIS,
0);
return prefix + relativeDateTimeString;
}
@Nullable
protected String getTimeInfoString() {
if (pass.getCalendarTimespan() != null && pass.getCalendarTimespan().getFrom() != null) {
return setDateTextFromDateAndPrefix("", pass.getCalendarTimespan().getFrom());
} else if (pass.getValidTimespans() != null && pass.getValidTimespans().size() > 0 && pass.getValidTimespans().get(0).getTo() != null) {
final ZonedDateTime to = pass.getValidTimespans().get(0).getTo();
return setDateTextFromDateAndPrefix(to.isAfter(ZonedDateTime.now()) ? "expires " : " expired ", to);
} else {
return null;
}
}
@Nullable
private ZonedDateTime getDateOrExtraText() {
if (pass.getCalendarTimespan() != null && pass.getCalendarTimespan().getFrom() != null) {
return pass.getCalendarTimespan().getFrom();
}
if (pass.getValidTimespans() != null && pass.getValidTimespans().size() > 0) {
return pass.getValidTimespans().get(0).getTo();
}
return null;
}
@Visibility
protected int getVisibilityForGlobalAndLocal(final boolean global, final boolean local) {
if (global) {
return GONE;
}
return local ? VISIBLE : INVISIBLE;
}
}

View file

@ -0,0 +1,121 @@
package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity
import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView
import android.text.format.DateUtils
import android.view.View.*
import kotlinx.android.synthetic.main.pass_list_item.view.*
import org.ligi.passandroid.actions.AddToCalendar
import org.ligi.passandroid.model.PassBitmapDefinitions
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassField
import org.ligi.passandroid.ui.NavigateToLocationsDialog
import org.ligi.passandroid.ui.Visibility
import org.threeten.bp.ZonedDateTime
abstract class PassViewHolder(val view: CardView) : RecyclerView.ViewHolder(view) {
open fun apply(pass: Pass, passStore: PassStore, activity: Activity) {
view.addCalendar.setOnClickListener {
clickAddToCalendar(pass)
}
view.navigateTo.setOnClickListener {
performNavigate(activity, pass)
}
refresh(pass, passStore)
}
protected fun refresh(pass: Pass, passStore: PassStore) {
val dateOrExtraText = getDateOrExtraText(pass)
val noButtons = dateOrExtraText == null && pass.locations.size <= 0
view.actionsSeparator.visibility = getVisibilityForGlobalAndLocal(noButtons, true)
view.navigateTo.visibility = getVisibilityForGlobalAndLocal(noButtons, pass.locations.size > 0)
view.addCalendar.visibility = getVisibilityForGlobalAndLocal(noButtons, dateOrExtraText != null)
val iconBitmap = pass.getBitmap(passStore, PassBitmapDefinitions.BITMAP_ICON)
iconBitmap?.let { view.categoryView.setIcon(it) }
view.categoryView.setImageByCategory(pass.type)
view.categoryView.setAccentColor(pass.accentColor)
view.passTitle.text = pass.description
}
protected open fun performNavigate(activity: Activity, pass: Pass) {
NavigateToLocationsDialog.perform(activity, pass, false)
}
protected open fun clickAddToCalendar(pass: Pass) {
val dateOrExtraText = getDateOrExtraText(pass)
AddToCalendar.tryAddDateToCalendar(pass, view, dateOrExtraText)
}
fun getExtraString(pass: Pass) = pass.fields.firstOrNull()?.let { getExtraStringForField(it) }
private fun getExtraStringForField(passField: PassField): String {
val stringBuilder = StringBuilder()
if (passField.label != null) {
stringBuilder.append(passField.label)
if (passField.value != null) {
stringBuilder.append(": ")
}
}
if (passField.value != null) {
stringBuilder.append(passField.value)
}
return stringBuilder.toString()
}
private fun setDateTextFromDateAndPrefix(prefix: String, relevantDate: ZonedDateTime): String {
val relativeDateTimeString = DateUtils.getRelativeDateTimeString(view.context,
relevantDate.toEpochSecond() * 1000,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.WEEK_IN_MILLIS,
0)
return prefix + relativeDateTimeString
}
protected fun getTimeInfoString(pass: Pass) =
if (pass.calendarTimespan != null && pass.calendarTimespan!!.from != null) {
setDateTextFromDateAndPrefix("", pass.calendarTimespan!!.from!!)
} else if (pass.validTimespans != null && pass.validTimespans!!.size > 0 && pass.validTimespans!![0].to != null) {
val to = pass.validTimespans!![0].to
setDateTextFromDateAndPrefix(if (to!!.isAfter(ZonedDateTime.now())) "expires " else " expired ", to)
} else {
null
}
private fun getDateOrExtraText(pass: Pass): ZonedDateTime? {
if (pass.calendarTimespan != null && pass.calendarTimespan!!.from != null) {
return pass.calendarTimespan!!.from
}
if (pass.validTimespans != null && pass.validTimespans!!.size > 0) {
return pass.validTimespans!![0].to
}
return null
}
@Visibility
protected open fun getVisibilityForGlobalAndLocal(global: Boolean, local: Boolean): Int {
if (global) {
return GONE
}
return if (local) VISIBLE else INVISIBLE
}
}

View file

@ -1,32 +0,0 @@
package org.ligi.passandroid.ui.pass_view_holder;
import android.app.Activity;
import android.view.View;
import org.ligi.passandroid.model.PassStore;
import org.ligi.passandroid.model.pass.Pass;
public class VerbosePassViewHolder extends PassViewHolder {
public VerbosePassViewHolder(View view) {
super(view);
}
public void apply(final Pass pass, final PassStore passStore, final Activity activity) {
super.apply(pass, passStore, activity);
String stringToSetForDateOrExtraText = null;
if (getTimeInfoString() != null) {
stringToSetForDateOrExtraText = getTimeInfoString();
} else if (getExtraString() != null) {
stringToSetForDateOrExtraText = getExtraString();
}
if (stringToSetForDateOrExtraText != null && !stringToSetForDateOrExtraText.isEmpty()) {
dateOrExtraText.setText(stringToSetForDateOrExtraText);
dateOrExtraText.setVisibility(View.VISIBLE);
} else {
dateOrExtraText.setVisibility(View.GONE);
}
}
}

View file

@ -0,0 +1,31 @@
package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity
import android.support.v7.widget.CardView
import android.view.View
import kotlinx.android.synthetic.main.pass_list_item.view.*
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.Pass
open class VerbosePassViewHolder(view: CardView) : PassViewHolder(view) {
override fun apply(pass: Pass, passStore: PassStore, activity: Activity) {
super.apply(pass, passStore, activity)
var stringToSetForDateOrExtraText: String? = null
val timeInfoString = getTimeInfoString(pass)
if (timeInfoString != null) {
stringToSetForDateOrExtraText = timeInfoString
} else if (getExtraString(pass) != null) {
stringToSetForDateOrExtraText = getExtraString(pass)
}
if (stringToSetForDateOrExtraText != null && !stringToSetForDateOrExtraText.isEmpty()) {
view.date.text = stringToSetForDateOrExtraText
view.date.visibility = View.VISIBLE
} else {
view.date.visibility = View.GONE
}
}
}

View file

@ -66,7 +66,7 @@
<View
android:id="@+id/actions_separator"
android:id="@+id/actionsSeparator"
android:layout_width="match_parent"
android:layout_height="2dip"
android:layout_below="@id/pass_top"
@ -82,7 +82,7 @@
android:id="@+id/navigateTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/actions_separator"
android:layout_below="@id/actionsSeparator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"
@ -96,7 +96,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/actions_separator"
android:layout_below="@id/actionsSeparator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"

View file

@ -59,45 +59,45 @@
<View
android:id="@+id/actions_separator"
android:layout_width="match_parent"
android:layout_height="2dip"
android:layout_below="@id/pass_top"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#dfdfdf"
android:padding="7dp" />
android:id="@+id/actionsSeparator"
android:layout_width="match_parent"
android:layout_height="2dip"
android:layout_below="@id/pass_top"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#dfdfdf"
android:padding="7dp" />
<TextView
android:id="@+id/navigateTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/actions_separator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"
android:textColor="?android:attr/textColorPrimary"
android:drawableLeft="@drawable/ic_maps_place_wrapped"
android:padding="8dp"
android:text="@string/pass_directions" />
android:id="@+id/navigateTo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/actionsSeparator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"
android:textColor="?android:attr/textColorPrimary"
android:drawableLeft="@drawable/ic_maps_place_wrapped"
android:padding="8dp"
android:text="@string/pass_directions" />
<TextView
android:id="@+id/addCalendar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/actions_separator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"
android:drawableRight="@drawable/ic_action_perm_contact_calendar_wrapped"
android:padding="8dp"
android:text="@string/pass_to_calendar" />
android:id="@+id/addCalendar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/actionsSeparator"
android:layout_gravity="center_vertical"
android:background="@drawable/clickable_bg"
android:clickable="true"
android:drawableRight="@drawable/ic_action_perm_contact_calendar_wrapped"
android:padding="8dp"
android:text="@string/pass_to_calendar" />
<LinearLayout
android:id="@+id/passExtrasContainer"