Reorganize the your_train and departure_listing layouts (and corresponding custom views) for easier editing, greater flexibility for different screens, and to fix a layout bug that was introduced when updating the libraries where the "Your Train" section would be too wide.

General code cleanup, warnings fixes, and readability improvements.
This commit is contained in:
Danny Weinberg 2015-08-12 07:41:16 -07:00
parent 4ee80b3f90
commit 2481f0c229
13 changed files with 424 additions and 350 deletions

View File

@ -17,6 +17,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.Vibrator;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.text.format.DateFormat;
@ -48,6 +49,7 @@ import com.dougkeen.bart.services.EtdService;
import com.dougkeen.bart.services.EtdService.EtdServiceBinder;
import com.dougkeen.bart.services.EtdService.EtdServiceListener;
import com.dougkeen.bart.services.EtdService_;
import com.dougkeen.util.Assert;
import com.dougkeen.util.Observer;
import com.dougkeen.util.WakeLocker;
@ -86,8 +88,7 @@ public class ViewDeparturesActivity extends AppCompatActivity implements
mProgress = (ProgressBar) findViewById(android.R.id.progress);
mDeparturesAdapter = new DepartureArrayAdapter(this,
R.layout.departure_listing);
mDeparturesAdapter = new DepartureArrayAdapter(this);
setListAdapter(mDeparturesAdapter);
final ListView listView = getListView();
@ -127,9 +128,9 @@ public class ViewDeparturesActivity extends AppCompatActivity implements
}
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("departures")) {
for (Parcelable departure : savedInstanceState
.getParcelableArray("departures")) {
Parcelable[] departuresArray = savedInstanceState.getParcelableArray("departures");
if (departuresArray != null) {
for (Parcelable departure : departuresArray) {
mDeparturesAdapter.add((Departure) departure);
}
mDeparturesAdapter.notifyDataSetChanged();
@ -151,8 +152,9 @@ public class ViewDeparturesActivity extends AppCompatActivity implements
}
refreshBoardedDeparture(false);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ActionBar supportActionBar = Assert.notNull(getSupportActionBar());
supportActionBar.setHomeButtonEnabled(true);
supportActionBar.setDisplayHomeAsUpEnabled(true);
if (bartRunnerApplication.shouldPlayAlarmRingtone()) {
soundTheAlarm();
@ -440,7 +442,7 @@ public class ViewDeparturesActivity extends AppCompatActivity implements
return;
}
mYourTrainSection.updateFromBoardedDeparture();
mYourTrainSection.updateFromBoardedDeparture(boardedDeparture);
if (currentVisibility != View.VISIBLE) {
showYourTrainSection(animate);

View File

@ -0,0 +1,46 @@
package com.dougkeen.bart.controls;
import android.content.Context;
import android.support.v7.widget.LinearLayoutCompat;
import android.util.AttributeSet;
import android.widget.Checkable;
import com.dougkeen.bart.R;
/**
* A {@link android.widget.LinearLayout} that implements {@link Checkable} and changes
* its background color when checked.
*/
public class CheckableLinearLayout extends LinearLayoutCompat implements Checkable {
private boolean mChecked;
public CheckableLinearLayout(Context context) {
super(context);
}
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void setChecked(boolean checked) {
mChecked = checked;
int colorRes = isChecked() ? R.color.blue_selection : android.R.color.transparent;
setBackgroundResource(colorRes);
}
@Override
public void toggle() {
setChecked(!isChecked());
}
}

View File

@ -1,42 +0,0 @@
package com.dougkeen.bart.controls;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.Checkable;
import android.widget.RelativeLayout;
import com.dougkeen.bart.R;
public class DepartureListItemLayout extends RelativeLayout implements
Checkable {
public DepartureListItemLayout(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.departure_listing, this,
true);
}
private boolean mChecked;
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void setChecked(boolean checked) {
mChecked = checked;
if (isChecked()) {
setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.blue_selection));
} else {
setBackgroundDrawable(getContext().getResources().getDrawable(
android.R.color.transparent));
}
}
@Override
public void toggle() {
setChecked(!isChecked());
}
}

View File

@ -10,8 +10,7 @@ import android.widget.TextSwitcher;
import com.dougkeen.bart.R;
import com.dougkeen.bart.model.TextProvider;
public class TimedTextSwitcher extends TextSwitcher implements
Ticker.TickSubscriber {
public class TimedTextSwitcher extends TextSwitcher implements Ticker.TickSubscriber {
public TimedTextSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);

View File

@ -2,41 +2,51 @@ package com.dougkeen.bart.controls;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Checkable;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.dougkeen.bart.BartRunnerApplication;
import com.dougkeen.bart.R;
import com.dougkeen.bart.model.Departure;
import com.dougkeen.bart.model.TextProvider;
import com.dougkeen.util.Observer;
public class YourTrainLayout extends RelativeLayout implements Checkable {
public class YourTrainLayout extends FrameLayout implements Checkable {
private final TextView destinationText;
private final TextView trainLength;
private final View colorBar;
private final ImageView bikeIcon;
private final View xferIcon;
private final CountdownTextView departureCountdown;
private final CountdownTextView arrivalCountdown;
private final TextView alarmText;
public YourTrainLayout(Context context) {
super(context);
assignLayout(context);
this(context, null);
}
public YourTrainLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public YourTrainLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
assignLayout(context);
}
public YourTrainLayout(Context context, AttributeSet attrs) {
super(context, attrs);
assignLayout(context);
}
public void assignLayout(Context context) {
LayoutInflater.from(context).inflate(R.layout.your_train, this, true);
destinationText = (TextView) findViewById(R.id.yourTrainDestinationText);
trainLength = (TextView) findViewById(R.id.yourTrainTrainLengthText);
colorBar = findViewById(R.id.yourTrainDestinationColorBar);
bikeIcon = (ImageView) findViewById(R.id.yourTrainBikeIcon);
xferIcon = findViewById(R.id.yourTrainXferIcon);
departureCountdown = (CountdownTextView) findViewById(R.id.yourTrainDepartureCountdown);
arrivalCountdown = (CountdownTextView) findViewById(R.id.yourTrainArrivalCountdown);
alarmText = (TextView) findViewById(R.id.alarmText);
}
private boolean mChecked;
@ -75,13 +85,8 @@ public class YourTrainLayout extends RelativeLayout implements Checkable {
}
private void setBackground() {
if (isChecked()) {
setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.blue_selection));
} else {
setBackgroundDrawable(getContext().getResources().getDrawable(
R.color.gray));
}
int colorRes = isChecked() ? R.color.blue_selection : R.color.gray;
setBackgroundResource(colorRes);
}
@Override
@ -89,11 +94,10 @@ public class YourTrainLayout extends RelativeLayout implements Checkable {
setChecked(!isChecked());
}
public void updateFromBoardedDeparture() {
final Departure boardedDeparture = ((BartRunnerApplication) ((Activity) getContext())
.getApplication()).getBoardedDeparture();
if (boardedDeparture == null)
public void updateFromBoardedDeparture(final Departure boardedDeparture) {
if (boardedDeparture == null) {
return;
}
if (!boardedDeparture.equals(mDeparture)) {
if (mDeparture != null) {
@ -110,36 +114,23 @@ public class YourTrainLayout extends RelativeLayout implements Checkable {
mDeparture = boardedDeparture;
((TextView) findViewById(R.id.yourTrainDestinationText))
.setText(boardedDeparture.getTrainDestination().toString());
destinationText.setText(boardedDeparture.getTrainDestination().toString());
trainLength.setText(boardedDeparture.getTrainLengthAndPlatform());
((TextView) findViewById(R.id.yourTrainTrainLengthText))
.setText(boardedDeparture.getTrainLengthAndPlatform());
ImageView colorBar = (ImageView) findViewById(R.id.yourTrainDestinationColorBar);
((GradientDrawable) colorBar.getDrawable()).setColor(Color
.parseColor(boardedDeparture.getTrainDestinationColor()));
ImageView bikeIcon = (ImageView) findViewById(R.id.yourTrainBikeIcon);
colorBar.setBackgroundColor(boardedDeparture.getTrainDestinationColor());
if (boardedDeparture.isBikeAllowed()) {
bikeIcon.setImageDrawable(getResources().getDrawable(
R.drawable.bike));
bikeIcon.setImageResource(R.drawable.bike);
} else {
bikeIcon.setImageDrawable(getResources().getDrawable(
R.drawable.nobike));
bikeIcon.setImageResource(R.drawable.nobike);
}
if (boardedDeparture.getRequiresTransfer()) {
findViewById(R.id.yourTrainXferIcon)
.setVisibility(View.VISIBLE);
xferIcon.setVisibility(View.VISIBLE);
} else {
findViewById(R.id.yourTrainXferIcon)
.setVisibility(View.INVISIBLE);
xferIcon.setVisibility(View.INVISIBLE);
}
updateAlarmIndicator();
CountdownTextView departureCountdown = (CountdownTextView) findViewById(R.id.yourTrainDepartureCountdown);
CountdownTextView arrivalCountdown = (CountdownTextView) findViewById(R.id.yourTrainArrivalCountdown);
final TextProvider textProvider = new TextProvider() {
@Override
public String getText(long tickNumber) {
@ -169,11 +160,10 @@ public class YourTrainLayout extends RelativeLayout implements Checkable {
private void updateAlarmIndicator() {
if (!mDeparture.isAlarmPending()) {
findViewById(R.id.alarmText).setVisibility(GONE);
alarmText.setVisibility(GONE);
} else {
findViewById(R.id.alarmText).setVisibility(VISIBLE);
((TextView) findViewById(R.id.alarmText)).setText(String
.valueOf(mDeparture.getAlarmLeadTimeMinutes()));
alarmText.setVisibility(VISIBLE);
alarmText.setText(String.valueOf(mDeparture.getAlarmLeadTimeMinutes()));
}
}

View File

@ -1,13 +1,8 @@
package com.dougkeen.bart.data;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.graphics.Color;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -21,65 +16,36 @@ import android.widget.ViewSwitcher.ViewFactory;
import com.dougkeen.bart.R;
import com.dougkeen.bart.controls.CountdownTextView;
import com.dougkeen.bart.controls.DepartureListItemLayout;
import com.dougkeen.bart.controls.CheckableLinearLayout;
import com.dougkeen.bart.controls.TimedTextSwitcher;
import com.dougkeen.bart.model.Departure;
import com.dougkeen.bart.model.TextProvider;
import org.apache.commons.lang3.StringUtils;
public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
private Drawable noBikeDrawable;
private Drawable bikeDrawable;
public DepartureArrayAdapter(Context context, int textViewResourceId,
Departure[] objects) {
super(context, textViewResourceId, objects);
assignBikeDrawables();
}
private void assignBikeDrawables() {
noBikeDrawable = getContext().getResources().getDrawable(
R.drawable.nobike);
bikeDrawable = getContext().getResources().getDrawable(R.drawable.bike);
}
public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId, Departure[] objects) {
super(context, resource, textViewResourceId, objects);
assignBikeDrawables();
}
public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId, List<Departure> objects) {
super(context, resource, textViewResourceId, objects);
assignBikeDrawables();
}
public DepartureArrayAdapter(Context context, int resource,
int textViewResourceId) {
super(context, resource, textViewResourceId);
assignBikeDrawables();
}
public DepartureArrayAdapter(Context context, int textViewResourceId,
List<Departure> objects) {
super(context, textViewResourceId, objects);
assignBikeDrawables();
}
public DepartureArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
assignBikeDrawables();
@SuppressWarnings("deprecation")
public DepartureArrayAdapter(Context context) {
super(context, 0 /* resource, unused since we override getView */);
Resources resources = context.getResources();
// We need to use the deprecated getDrawable since the newer version that
// replaces it was only made available in API 21.
noBikeDrawable = resources.getDrawable(R.drawable.nobike);
bikeDrawable = resources.getDrawable(R.drawable.bike);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView != null
&& convertView instanceof DepartureListItemLayout) {
if (convertView != null && convertView instanceof CheckableLinearLayout) {
view = convertView;
} else {
view = new DepartureListItemLayout(getContext());
view = LayoutInflater.from(getContext()).inflate(
R.layout.departure_listing, parent, false /* attachToRoot */);
}
final Departure departure = getItem(position);
@ -132,10 +98,8 @@ public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
});
}
ImageView colorBar = (ImageView) view
.findViewById(R.id.destinationColorBar);
((GradientDrawable) colorBar.getDrawable()).setColor(Color
.parseColor(departure.getTrainDestinationColor()));
view.findViewById(R.id.destinationColorBar)
.setBackgroundColor(departure.getTrainDestinationColor());
CountdownTextView countdownTextView = (CountdownTextView) view
.findViewById(R.id.countdown);
countdownTextView.setText(departure.getCountdownText());
@ -171,7 +135,7 @@ public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
}
});
}
ImageView bikeIcon = (ImageView) view.findViewById(R.id.bikeIcon);
if (departure.isBikeAllowed()) {
bikeIcon.setImageDrawable(bikeDrawable);
@ -179,11 +143,9 @@ public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
bikeIcon.setImageDrawable(noBikeDrawable);
}
if (departure.getRequiresTransfer()) {
view.findViewById(R.id.xferIcon)
.setVisibility(View.VISIBLE);
view.findViewById(R.id.xferIcon).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.xferIcon)
.setVisibility(View.INVISIBLE);
view.findViewById(R.id.xferIcon).setVisibility(View.INVISIBLE);
}
return view;

View File

@ -1,18 +1,14 @@
package com.dougkeen.bart.model;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.util.Log;
@ -23,6 +19,12 @@ import com.dougkeen.bart.activities.ViewDeparturesActivity;
import com.dougkeen.bart.services.BoardedDepartureService;
import com.dougkeen.util.Observable;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Departure implements Parcelable, Comparable<Departure> {
private static final int MINIMUM_MERGE_OVERLAP_MILLIS = 5000;
private static final int EXPIRE_MINUTES_AFTER_ARRIVAL = 1;
@ -133,8 +135,9 @@ public class Departure implements Parcelable, Comparable<Departure> {
this.line = line;
}
public String getTrainDestinationColor() {
return destinationColor;
@ColorInt
public int getTrainDestinationColor() {
return Color.parseColor(destinationColor);
}
public void setTrainDestinationColor(String destinationColor) {
@ -627,33 +630,36 @@ public class Departure implements Parcelable, Comparable<Departure> {
final Intent cancelAlarmIntent = new Intent(context,
BoardedDepartureService.class);
cancelAlarmIntent.putExtra("cancelNotifications", true);
String title = getOrigin().shortName + " to " + getPassengerDestination().shortName;
Builder notificationBuilder = new NotificationCompat.Builder(context)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_stat_notification)
.setContentTitle(
getOrigin().shortName + " to "
+ getPassengerDestination().shortName)
.setContentTitle(title)
.setContentIntent(getNotificationIntent(context)).setWhen(0);
if (android.os.Build.VERSION.SDK_INT >= 16) {
notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH)
notificationBuilder
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentText(minutesText + " until departure");
if (isAlarmPending()) {
notificationBuilder.addAction(
R.drawable.ic_action_cancel_alarm,
"Cancel alarm",
PendingIntent.getService(context, 0, cancelAlarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT)).setSubText(
"Alarm " + getAlarmLeadTimeMinutes()
+ " minutes before departure");
PendingIntent pendingIntent = PendingIntent.getService(
context, 0, cancelAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
String subText = "Alarm " + getAlarmLeadTimeMinutes() + " minutes before departure";
notificationBuilder
.addAction(R.drawable.ic_action_cancel_alarm, "Cancel alarm", pendingIntent)
.setSubText(subText);
}
} else if (isAlarmPending()) {
notificationBuilder.setContentText(minutesText
String text = minutesText
+ " to departure (alarm at " + getAlarmLeadTimeMinutes()
+ " min" + ((getAlarmLeadTimeMinutes() == 1) ? "" : "s")
+ ")");
+ ")";
notificationBuilder.setContentText(text);
} else {
notificationBuilder
.setContentText(minutesText + " until departure");
notificationBuilder.setContentText(minutesText + " until departure");
}
return notificationBuilder.build();

View File

@ -4,7 +4,6 @@ import java.lang.ref.WeakReference;
import java.util.List;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
@ -15,6 +14,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.support.v4.app.NotificationManagerCompat;
import com.dougkeen.bart.BartRunnerApplication;
import com.dougkeen.bart.model.Departure;
@ -34,7 +34,7 @@ public class BoardedDepartureService extends Service implements
private boolean mBound = false;
private EtdService mEtdService;
private StationPair mStationPair;
private NotificationManager mNotificationManager;
private NotificationManagerCompat mNotificationManager;
private AlarmManager mAlarmManager;
private Handler mHandler;
private boolean mHasShutDown = false;
@ -91,7 +91,7 @@ public class BoardedDepartureService extends Service implements
bindService(EtdService_.intent(this).get(), mConnection,
Context.BIND_AUTO_CREATE);
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager = NotificationManagerCompat.from(this);
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mHandler = new Handler();
super.onCreate();
@ -302,8 +302,7 @@ public class BoardedDepartureService extends Service implements
.getBoardedDeparture();
if (boardedDeparture != null) {
mNotificationManager.notify(DEPARTURE_NOTIFICATION_ID,
boardedDeparture
.createNotification(getApplicationContext()));
boardedDeparture.createNotification(getApplicationContext()));
}
}

View File

@ -0,0 +1,13 @@
package com.dougkeen.util;
public final class Assert {
// Uninstantiable
private Assert() {}
public static <T> T notNull(T obj) {
if (obj == null) {
throw new AssertionError("Expected object to be non-null");
}
return obj;
}
}

View File

@ -1,77 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
<com.dougkeen.bart.controls.CheckableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<ImageView
<!-- This layout is used when the height is >= 480 dp, eg usually in portrait mode. -->
<View
android:id="@+id/destinationColorBar"
android:layout_width="wrap_content"
android:layout_width="15dp"
android:layout_height="64dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/basic_rectangle" />
tools:background="#F00"
/>
<!-- Holds the destination, the train info, and the arrival time -->
<LinearLayout
android:id="@+id/topRow"
android:layout_width="fill_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/destinationColorBar">
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:orientation="vertical"
>
<TextView
android:id="@+id/destinationText"
style="@style/DepartureDestinationText"
android:layout_weight="1"
android:ellipsize="marquee"
android:singleLine="true" />
android:singleLine="true"
tools:text="Richmond"
/>
<TextView
android:id="@+id/trainLengthText"
style="@style/DepartureUncertaintyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="9 cars, platform 2"
/>
<TextView
android:id="@+id/estimatedArrival"
style="@style/DepartureUncertaintyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Arrives ~11:12 AM (20 mins)"
/>
</LinearLayout>
<!-- Holds the bike and xfer icons -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/bikeIcon"
style="@style/BikeIcon" />
style="@style/TrainInfoIcon"
tools:src="@drawable/bike"
/>
<ImageView
android:id="@+id/xferIcon"
style="@style/TrainInfoIcon"
android:src="@drawable/xfer"
/>
</LinearLayout>
<!-- Holds the departure countdown, uncertainty, and departure time -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="right"
android:orientation="vertical"
>
<com.dougkeen.bart.controls.CountdownTextView
android:id="@+id/countdown"
style="@style/DepartureCountdownText"
android:gravity="right"
android:width="90dp"
bart:tickInterval="1" />
android:gravity="right"
bart:tickInterval="1"
tools:text="9m, 57s"
/>
<TextView
android:id="@+id/uncertainty"
style="@style/DepartureUncertaintyText"
tools:text="(+8s)"
/>
<TextView
android:id="@+id/departureTime"
style="@style/DepartureUncertaintyText"
tools:text="11:20 AM"
/>
</LinearLayout>
<ImageView
android:id="@+id/xferIcon"
style="@style/XferIcon"
android:layout_alignParentRight="true"
android:layout_below="@id/topRow"
android:src="@drawable/xfer" />
<TextView
android:id="@+id/trainLengthText"
style="@style/DepartureUncertaintyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/topRow"
android:layout_toRightOf="@id/destinationColorBar" />
<TextView
android:id="@+id/uncertainty"
style="@style/DepartureUncertaintyText"
android:layout_alignParentRight="true"
android:layout_below="@id/topRow" />
<TextView
android:id="@+id/estimatedArrival"
style="@style/DepartureUncertaintyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/trainLengthText"
android:layout_toRightOf="@id/destinationColorBar" />
<TextView
android:id="@+id/departureTime"
style="@style/DepartureUncertaintyText"
android:layout_alignParentRight="true"
android:layout_below="@id/uncertainty" />
</merge>
</com.dougkeen.bart.controls.CheckableLinearLayout>

View File

@ -1,64 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
<com.dougkeen.bart.controls.CheckableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<ImageView
<!-- This layout is used when the height is less than 480 dp (eg usually in landscape mode) -->
<View
android:id="@+id/destinationColorBar"
android:layout_width="wrap_content"
android:layout_width="15dp"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/basic_rectangle" />
tools:background="#F00"
/>
<!-- Holds destination and train info/arrival -->
<LinearLayout
android:id="@+id/topRow"
android:layout_width="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/destinationColorBar">
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:orientation="vertical"
>
<TextView
android:id="@+id/destinationText"
style="@style/DepartureDestinationText"
android:layout_weight="1"
android:ellipsize="marquee"
android:singleLine="true" />
android:singleLine="true"
tools:text="Richmond"
/>
<com.dougkeen.bart.controls.TimedTextSwitcher
android:id="@+id/trainLengthText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
bart:tickInterval="1"
tools:text="9 cars, platform 2"
/>
</LinearLayout>
<!-- Holds bike and xfer icons -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/bikeIcon"
style="@style/BikeIcon" />
style="@style/TrainInfoIcon"
tools:src="@drawable/bike"
/>
<ImageView
android:id="@+id/xferIcon"
style="@style/TrainInfoIcon"
android:src="@drawable/xfer"
/>
</LinearLayout>
<!-- Holds departure countdown and uncertainty/departure time-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="right"
android:orientation="vertical"
>
<com.dougkeen.bart.controls.CountdownTextView
android:id="@+id/countdown"
style="@style/DepartureCountdownText"
android:gravity="right"
android:width="90dp"
bart:tickInterval="1" />
android:gravity="right"
bart:tickInterval="1"
tools:text="9m, 57s"
/>
<com.dougkeen.bart.controls.TimedTextSwitcher
android:id="@+id/uncertainty"
style="@style/DepartureUncertaintyText"
bart:tickInterval="1"
tools:text="(+8s)"
/>
</LinearLayout>
<ImageView
android:id="@+id/xferIcon"
style="@style/XferIcon"
android:layout_alignParentRight="true"
android:layout_below="@id/topRow"
android:src="@drawable/xfer" />
<com.dougkeen.bart.controls.TimedTextSwitcher
android:id="@+id/trainLengthText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/topRow"
android:layout_toRightOf="@id/destinationColorBar"
bart:tickInterval="1" />
<com.dougkeen.bart.controls.TimedTextSwitcher
android:id="@+id/uncertainty"
style="@style/DepartureUncertaintyText"
android:layout_alignParentRight="true"
android:layout_below="@id/topRow"
bart:tickInterval="1" />
</merge>
</com.dougkeen.bart.controls.CheckableLinearLayout>

View File

@ -1,82 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bart="http://schemas.android.com/apk/res-auto" >
xmlns:bart="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/alarmText"
<!-- Holds the "Your Train" title and the alarm indicator -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/yourTrainHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/your_train"
android:textAllCaps="true"
android:textSize="20dp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/alarmText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:drawableLeft="@drawable/ic_action_alarm"
android:gravity="center_vertical"
android:textSize="16dp"
android:visibility="gone"
tools:text="5"
/>
</FrameLayout>
<!-- Holds the color bar, destination text, train info, bike icon, and xfer icon -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:drawableLeft="@drawable/ic_action_alarm"
android:gravity="center_vertical"
android:textSize="16dp"
android:visibility="gone"></TextView>
android:orientation="horizontal"
>
<TextView
android:id="@+id/yourTrainHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="@string/your_train"
android:textAllCaps="true"
android:textSize="20dp"
android:textStyle="bold" />
<View
android:id="@+id/yourTrainDestinationColorBar"
android:layout_width="15dp"
android:layout_height="45dp"
android:layout_gravity="center_vertical"
tools:background="#F00"
/>
<ImageView
android:id="@+id/yourTrainDestinationColorBar"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_below="@id/yourTrainHeader"
android:src="@drawable/basic_rectangle" />
<!-- Holds the destination text and train info -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
android:padding="5dp"
>
<TextView
android:id="@+id/yourTrainDestinationText"
style="@style/DepartureDestinationText"
android:layout_below="@id/yourTrainHeader"
android:layout_toRightOf="@id/yourTrainDestinationColorBar"
android:ellipsize="marquee"
android:singleLine="true" />
<TextView
android:id="@+id/yourTrainDestinationText"
style="@style/DepartureDestinationText"
android:ellipsize="marquee"
android:singleLine="true"
tools:text="Richmond"
/>
<ImageView
android:id="@+id/yourTrainBikeIcon"
style="@style/BikeIcon"
android:layout_below="@id/yourTrainHeader"
android:layout_toRightOf="@id/yourTrainDestinationText" />
<TextView
android:id="@+id/yourTrainTrainLengthText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="9 cars, platform 2"
/>
<ImageView
android:id="@+id/yourTrainXferIcon"
style="@style/XferIcon"
android:layout_below="@id/yourTrainBikeIcon"
android:layout_toRightOf="@id/yourTrainDestinationText"
android:src="@drawable/xfer" />
</LinearLayout>
<TextView
android:id="@+id/yourTrainTrainLengthText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/yourTrainDestinationText"
android:layout_toRightOf="@id/yourTrainDestinationColorBar"
android:paddingLeft="5dp" />
<!-- Holds the bike icon and xfer icon -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/yourTrainBikeIcon"
style="@style/TrainInfoIcon"
tools:src="@drawable/bike"
/>
<ImageView
android:id="@+id/yourTrainXferIcon"
style="@style/TrainInfoIcon"
android:src="@drawable/xfer"
/>
</LinearLayout>
</LinearLayout>
<com.dougkeen.bart.controls.CountdownTextView
android:id="@+id/yourTrainDepartureCountdown"
style="@style/DepartureCountdownText"
android:layout_alignLeft="@id/yourTrainSection"
android:layout_alignRight="@id/yourTrainSection"
android:layout_below="@id/yourTrainTrainLengthText"
bart:tickInterval="1" />
bart:tickInterval="1"
tools:text="Leaves in 15 min, 20s (+8s)"
/>
<com.dougkeen.bart.controls.CountdownTextView
android:id="@+id/yourTrainArrivalCountdown"
style="@style/DepartureCountdownText"
android:layout_alignLeft="@id/yourTrainSection"
android:layout_alignRight="@id/yourTrainSection"
android:layout_below="@id/yourTrainDepartureCountdown"
android:ellipsize="end"
bart:tickInterval="5" />
bart:tickInterval="5"
tools:text="Arrives ~11:12 AM (20 mins)"
/>
</merge>
</LinearLayout>

View File

@ -92,18 +92,10 @@
<item name="android:gravity">center</item>
</style>
<style name="BikeIcon">
<style name="TrainInfoIcon">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">5dp</item>
<item name="android:layout_marginLeft">5dp</item>
</style>
<style name="XferIcon">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginRight">87dp</item>
<item name="android:layout_marginBottom">5dp</item>
<item name="android:layout_margin">5dp</item>
</style>
</resources>