Skip to content

Commit

Permalink
Improve some things and update dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
coffeemakr committed Sep 12, 2017
1 parent 2c10353 commit fb7c447
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 27 deletions.
8 changes: 5 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dependencies {
})


errorprone 'com.google.errorprone:error_prone_core:2.0.5'
errorprone 'com.google.errorprone:error_prone_core:2.1.1'

compile('com.google.guava:guava:23.0-android', {
exclude group: 'com.google.code.findbugs'
Expand All @@ -101,10 +101,12 @@ dependencies {
compile 'com.android.support:preference-v7:25.3.1'
compile 'com.android.support:support-vector-drawable:25.3.1'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.8.47'
testCompile 'org.mockito:mockito-core:2.10.0'

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Because RxAndroid releases are few and far between, it is recommended you also
// explicitly depend on RxJava's latest version for bug fixes and new features.
compile 'io.reactivex.rxjava2:rxjava:2.1.2'
compile 'io.reactivex.rxjava2:rxjava:2.1.3'

compile 'io.mikael:urlbuilder:2.0.9'
}
25 changes: 12 additions & 13 deletions app/src/main/java/ch/unstable/ost/ConnectionListFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,29 @@ public class ConnectionListFragment extends Fragment {
private View mLoadingIndicator;
private RecyclerView mConnectionsList;
private ConnectionListAdapter.Listener mOverScrollListener = new ConnectionListAdapter.Listener() {
@Override
public boolean onLoadBelow(ConnectionListAdapter adapter, int pageToLoad) {
if(pageToLoad > connectionAPI.getPageMax() || pageToLoad < connectionAPI.getPageMin()) {
private boolean isLoadablePage(int pageToLoad) {
return pageToLoad <= connectionAPI.getPageMax() && pageToLoad >= connectionAPI.getPageMin();
}

private boolean loadPage(int pageToLoad) {
if(!isLoadablePage(pageToLoad)) {
return false;
}
Log.d(TAG, "on scrolled below");
Message message = backgroundHandler.obtainMessage(MESSAGE_QUERY_CONNECTION_PAGE);
message.obj = getConnectionQuery();
message.arg1 = pageToLoad;
backgroundHandler.sendMessage(message);
return true;
}

@Override
public boolean onLoadBelow(ConnectionListAdapter adapter, int pageToLoad) {
return loadPage(pageToLoad);
}

@Override
public boolean onLoadAbove(ConnectionListAdapter adapter, int pageToLoad) {
if(pageToLoad > connectionAPI.getPageMax() || pageToLoad < connectionAPI.getPageMin()) {
return false;
}
Log.d(TAG, "on scrolled above");
Message message = backgroundHandler.obtainMessage(MESSAGE_QUERY_CONNECTION_PAGE);
message.obj = getConnectionQuery();
message.arg1 = pageToLoad;
backgroundHandler.sendMessage(message);
return true;
return loadPage(pageToLoad);
}
};
private RecyclerView.OnScrollListener mConnectionListScrollListener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.google.common.base.Objects;

Expand All @@ -29,7 +30,7 @@ public PassingCheckpoint[] newArray(int size) {
private final Date departureTime;
private final Date arrivalTime;

public PassingCheckpoint(Date arrivalTime, Date departureTime, Location location, String platform) {
public PassingCheckpoint(Date arrivalTime, Date departureTime, Location location, @Nullable String platform) {
super(platform, location);
this.arrivalTime = checkNotNull(arrivalTime, "arrivalTime");
this.departureTime = checkNotNull(departureTime, "departureTime");
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/ch/unstable/ost/api/model/Section.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import static ch.unstable.ost.utils.ParcelUtils.writeNonNullTypedObject;
import static com.google.common.base.Preconditions.checkNotNull;


/**
*
* TODO: check if the stops contain the arrival and departure
*/
public class Section implements Parcelable {

public static final Creator<Section> CREATOR = new Creator<Section>() {
Expand Down
64 changes: 61 additions & 3 deletions app/src/main/java/ch/unstable/ost/api/search/SearchAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,55 @@

import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import ch.unstable.ost.api.StationsDAO;
import ch.unstable.ost.api.base.BaseHttpJsonAPI;
import ch.unstable.ost.api.model.Connection;
import ch.unstable.ost.api.model.ConnectionQuery;
import ch.unstable.ost.api.model.Location;
import ch.unstable.ost.api.model.PassingCheckpoint;
import ch.unstable.ost.api.model.Section;
import ch.unstable.ost.api.search.types.ConnectionDeserializer;
import ch.unstable.ost.api.search.types.LocationDeserializer;
import ch.unstable.ost.api.search.types.PassingCheckpointsDeserializer;
import ch.unstable.ost.api.search.types.SearchCHIconClassDeserializer;
import ch.unstable.ost.api.search.types.SectionsDeserializer;
import ch.unstable.ost.api.transport.ConnectionAPI;
import io.mikael.urlbuilder.UrlBuilder;

import static ch.unstable.ost.api.model.Location.StationType;
import static com.google.common.base.Preconditions.checkNotNull;

public class SearchAPI extends BaseHttpJsonAPI implements StationsDAO {
public class SearchAPI extends BaseHttpJsonAPI implements StationsDAO, ConnectionAPI {

private final static String BASE_URI = "https://timetable.search.ch/api/";
private final static String COMPLETION_URL = BASE_URI + "completion.json";
private final static String CONNECTIONS_URL = BASE_URI + "route.json";
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Europe/Berlin");

private static UrlBuilder addURLDate(UrlBuilder uriBuilder, Date date) {
checkNotNull(uriBuilder, "uriBuilder");
checkNotNull(date, "date");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.ROOT);
timeFormat.setTimeZone(TIME_ZONE);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
dateFormat.setTimeZone(TIME_ZONE);
return uriBuilder
.addParameter("time", timeFormat.format(date))
.addParameter("date", dateFormat.format(date));
}

@Override
protected void onBuildGsonCreated(GsonBuilder gsonBuilder) {
gsonBuilder.registerTypeAdapter(StationType.class, new SearchCHIconClassDeserializer());
gsonBuilder.registerTypeAdapter(Section[].class, new SectionsDeserializer());
gsonBuilder.registerTypeAdapter(Connection.class, new ConnectionDeserializer());
gsonBuilder.registerTypeAdapter(StationType.class, SearchCHIconClassDeserializer.INSTANCE);
gsonBuilder.registerTypeAdapter(PassingCheckpoint.class, PassingCheckpointsDeserializer.INSTANCE);
gsonBuilder.registerTypeAdapter(Location.class, LocationDeserializer.INSTANCE);
}

Expand All @@ -52,7 +81,6 @@ public Location[] getStationsByQuery(String query, @Nullable StationType[] types
return locationCompletions.toArray(new Location[locationCompletions.size()]);
}


private ArrayList<Location> filterResults(ArrayList<Location> completions, final StationType[] filter) {
final int mask = StationType.getMask(filter);
ArrayList<Location> filtered = new ArrayList<>(completions.size());
Expand All @@ -63,4 +91,34 @@ private ArrayList<Location> filterResults(ArrayList<Location> completions, final
}
return filtered;
}

@Override
public int getPageMax() {
return 0;
}

@Override
public int getPageMin() {
return 0;
}

@Override
public Connection[] getConnections(ConnectionQuery connectionQuery, int page) throws IOException {
UrlBuilder builder = UrlBuilder.fromString(CONNECTIONS_URL)
.addParameter("from", connectionQuery.getFrom())
.addParameter("to", connectionQuery.getTo());

if (connectionQuery.getArrivalTime() != null) {
builder = addURLDate(builder, connectionQuery.getArrivalTime());
builder = builder.addParameter("time_type", "arrival");
} else if (connectionQuery.getDepartureTime() != null) {
builder = addURLDate(builder, connectionQuery.getDepartureTime());
}
ConnectionsList connectionsList = loadJson(builder.toUrl(), ConnectionsList.class);
return connectionsList.connections;
}

private static class ConnectionsList {
public Connection[] connections;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ch.unstable.ost.api.search.types;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;

import ch.unstable.ost.api.model.Connection;
import ch.unstable.ost.api.model.Section;

public class ConnectionDeserializer implements JsonDeserializer<Connection> {
@Override
public Connection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject connectionObj = json.getAsJsonObject();
Section[] sections = context.deserialize(connectionObj.get("legs"), Section[].class);
return new Connection(sections);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ch.unstable.ost.api.search.types;

import android.support.annotation.Nullable;
import android.util.Log;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

import ch.unstable.ost.api.model.Location;
import ch.unstable.ost.api.model.PassingCheckpoint;
import ch.unstable.ost.utils.LogUtils;

public enum PassingCheckpointsDeserializer implements JsonDeserializer<PassingCheckpoint> {
INSTANCE;

private static final String TAG = "PassingCPDeserializer";
private static final Logger LOGGER = Logger.getLogger(TAG);

@Nullable
public static Date getDate(SimpleDateFormat dateFormat, JsonObject object, String name) {
if (!object.has(name)) {
return null;
}
JsonElement dateField = object.get(name);
if (dateField.isJsonNull()) {
return null;
}
try {
return dateFormat.parse(dateField.getAsString());
} catch (ParseException e) {
throw new JsonParseException("Unable to parse departure date", e);
}
}

public static SimpleDateFormat getDateFormat() {
SimpleDateFormat departureFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT);
departureFormat.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
return departureFormat;
}

@Override
public PassingCheckpoint deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
SimpleDateFormat dateFormat = getDateFormat();
JsonObject object = json.getAsJsonObject();
String stopId = object.get("stopid").getAsString();
String name = object.get("name").getAsString();
Date departure = getDate(dateFormat, object, "departure");
Date arrival = getDate(dateFormat, object, "arrival");

if(departure == null && arrival != null) {
Log.w(TAG, "Departure is null");
departure = arrival;
} else if(arrival == null && departure != null) {
Log.w(TAG, "Arrival is null");
arrival = departure;
} else if(arrival == null && departure == null) {
LOGGER.log(Level.WARNING, "neither arrival nor departure is set: " + LogUtils.prettyJson(object));
Log.w(TAG, "neither arrival nor departure is set: " + LogUtils.prettyJson(object));
return null;
}

Location location = new Location(name, Location.StationType.UNKNOWN, stopId);
// TODO: Find out if track is sent
String platform = null;
if(object.has("track")) {
platform = object.get("track").getAsString();
}
return new PassingCheckpoint(arrival, departure, location, platform);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

import ch.unstable.ost.api.model.Location;

public class SearchCHIconClassDeserializer implements JsonDeserializer<Location.StationType> {
public enum SearchCHIconClassDeserializer implements JsonDeserializer<Location.StationType> {
INSTANCE;
private static final String TAG = SearchCHIconClassDeserializer.class.getSimpleName();

@Override
Expand Down
Loading

0 comments on commit fb7c447

Please sign in to comment.