mirror of
https://github.com/mediathekview/zapp.git
synced 2024-09-19 11:52:15 +02:00
Heavily simplified show info api by using retrofit and removing separate module
This commit is contained in:
parent
0e6b2262a2
commit
d3cec03c94
@ -10,7 +10,6 @@
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/programguide" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
@ -4,7 +4,6 @@
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Zapp.iml" filepath="$PROJECT_DIR$/Zapp.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/programguide/programguide.iml" filepath="$PROJECT_DIR$/programguide/programguide.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -37,7 +37,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
compile project(':programguide')
|
||||
|
||||
// tests
|
||||
testCompile 'junit:junit:4.12'
|
||||
@ -82,4 +81,7 @@ dependencies {
|
||||
|
||||
// timber logging
|
||||
compile 'com.jakewharton.timber:timber:4.5.1'
|
||||
|
||||
// joda time
|
||||
compile 'joda-time:joda-time:2.9.4'
|
||||
}
|
||||
|
@ -1,42 +1,38 @@
|
||||
package de.christinecoenen.code.programguide;
|
||||
package de.christinecoenen.code.zapp.app.livestream.api;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.christinecoenen.code.programguide.model.Channel;
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
import de.christinecoenen.code.zapp.app.livestream.api.model.Channel;
|
||||
import de.christinecoenen.code.zapp.app.livestream.model.LiveShow;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Cache singleton for currently running show on any channel.
|
||||
*/
|
||||
public class Cache {
|
||||
class Cache {
|
||||
|
||||
private static Cache instance = null;
|
||||
|
||||
private final Map<Channel, Show> shows = new HashMap<>();
|
||||
private final Map<Channel, LiveShow> shows = new HashMap<>();
|
||||
|
||||
public static Cache getInstance() {
|
||||
static Cache getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Cache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void save(Channel channel, Show show) {
|
||||
public void save(Channel channel, LiveShow show) {
|
||||
this.shows.put(channel, show);
|
||||
}
|
||||
|
||||
public void save(Map<Channel, Show> shows) {
|
||||
this.shows.putAll(shows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return currently running show or null in case of cache miss
|
||||
*/
|
||||
public Show getShow(Channel channel) {
|
||||
Show show = shows.get(channel);
|
||||
LiveShow getShow(Channel channel) {
|
||||
LiveShow show = shows.get(channel);
|
||||
|
||||
if (show == null) {
|
||||
Timber.d("cache miss: " + channel);
|
@ -0,0 +1,100 @@
|
||||
package de.christinecoenen.code.zapp.app.livestream.api;
|
||||
|
||||
|
||||
import de.christinecoenen.code.zapp.app.livestream.api.model.Channel;
|
||||
import de.christinecoenen.code.zapp.app.livestream.api.model.ShowResponse;
|
||||
import de.christinecoenen.code.zapp.app.livestream.model.LiveShow;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ProgramGuideRequest implements Callback<ShowResponse> {
|
||||
|
||||
private final static ProgramInfoService service = new Retrofit.Builder()
|
||||
.baseUrl("https://zappbackend.herokuapp.com/v1/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(ProgramInfoService.class);
|
||||
|
||||
private Listener listener;
|
||||
private Channel channelId;
|
||||
private Call<ShowResponse> showCall;
|
||||
|
||||
public ProgramGuideRequest setListener(Listener listener) {
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public ProgramGuideRequest setChannelId(Channel channelId) {
|
||||
this.channelId = channelId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgramGuideRequest setChannelId(String channelId) {
|
||||
Channel newChannel = null;
|
||||
try {
|
||||
newChannel = Channel.getById(channelId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Timber.w(channelId + " is no valid channel id");
|
||||
}
|
||||
|
||||
return setChannelId(newChannel);
|
||||
}
|
||||
|
||||
public ProgramGuideRequest execute() {
|
||||
if (listener == null) {
|
||||
throw new RuntimeException("listener not set");
|
||||
}
|
||||
|
||||
if (channelId == null) {
|
||||
Timber.w("no valid channel id set");
|
||||
listener.onRequestError();
|
||||
return this;
|
||||
}
|
||||
|
||||
LiveShow cachedShow = Cache.getInstance().getShow(channelId);
|
||||
|
||||
if (cachedShow != null) {
|
||||
listener.onRequestSuccess(cachedShow);
|
||||
} else {
|
||||
showCall = service.getShows(channelId.toString());
|
||||
showCall.enqueue(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (showCall != null) {
|
||||
showCall.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<ShowResponse> call, Response<ShowResponse> response) {
|
||||
//noinspection ConstantConditions
|
||||
if (response.body() == null || !response.body().isSuccess()) {
|
||||
listener.onRequestError();
|
||||
} else {
|
||||
//noinspection ConstantConditions
|
||||
LiveShow liveShow = response.body().getShow().toLiveShow();
|
||||
Cache.getInstance().save(channelId, liveShow);
|
||||
listener.onRequestSuccess(liveShow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ShowResponse> call, Throwable t) {
|
||||
listener.onRequestError();
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onRequestError();
|
||||
|
||||
void onRequestSuccess(LiveShow currentShow);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package de.christinecoenen.code.zapp.app.livestream.api;
|
||||
|
||||
|
||||
import de.christinecoenen.code.zapp.app.livestream.api.model.ShowResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
interface ProgramInfoService {
|
||||
|
||||
@GET("shows/{channelName}")
|
||||
Call<ShowResponse> getShows(@Path("channelName") String channelName);
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package de.christinecoenen.code.programguide.model;
|
||||
package de.christinecoenen.code.zapp.app.livestream.api.model;
|
||||
|
||||
|
||||
public enum Channel {
|
@ -0,0 +1,43 @@
|
||||
package de.christinecoenen.code.zapp.app.livestream.api.model;
|
||||
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import de.christinecoenen.code.zapp.app.livestream.model.LiveShow;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public class Show {
|
||||
|
||||
private static final DateTimeFormatter formatter = ISODateTimeFormat.dateTimeParser();
|
||||
|
||||
private String title;
|
||||
private String subtitle;
|
||||
private String description;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
|
||||
public LiveShow toLiveShow() {
|
||||
LiveShow liveShow = new LiveShow();
|
||||
liveShow.setTitle(title);
|
||||
liveShow.setSubtitle(subtitle);
|
||||
liveShow.setDescription(description);
|
||||
|
||||
if (startTime != null && endTime != null) {
|
||||
liveShow.setStartTime(formatter.parseDateTime(startTime));
|
||||
liveShow.setEndTime(formatter.parseDateTime(endTime));
|
||||
}
|
||||
|
||||
return liveShow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Show{" +
|
||||
"title='" + title + '\'' +
|
||||
", subtitle='" + subtitle + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", endTime=" + endTime +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package de.christinecoenen.code.zapp.app.livestream.api.model;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "unused", "CanBeFinal"})
|
||||
public class ShowResponse {
|
||||
|
||||
private List<Show> shows;
|
||||
|
||||
public Show getShow() {
|
||||
return shows.get(0);
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return shows != null && !shows.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ShowResponse{" +
|
||||
"shows=" + shows +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package de.christinecoenen.code.programguide.model;
|
||||
package de.christinecoenen.code.zapp.app.livestream.model;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
public class Show {
|
||||
public class LiveShow {
|
||||
|
||||
private String title;
|
||||
private String subtitle;
|
@ -20,24 +20,36 @@ import java.util.concurrent.TimeUnit;
|
||||
import butterknife.BindInt;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.christinecoenen.code.programguide.ProgramGuideRequest;
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
import de.christinecoenen.code.zapp.R;
|
||||
import de.christinecoenen.code.zapp.app.livestream.api.ProgramGuideRequest;
|
||||
import de.christinecoenen.code.zapp.app.livestream.model.LiveShow;
|
||||
import de.christinecoenen.code.zapp.model.ChannelModel;
|
||||
import timber.log.Timber;
|
||||
|
||||
public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
|
||||
protected @BindView(R.id.text_show_title) TextView showTitleView;
|
||||
protected @BindView(R.id.text_show_subtitle) TextView showSubtitleView;
|
||||
protected @BindView(R.id.text_show_time) TextView showTimeView;
|
||||
protected @BindView(R.id.progressbar_show_progress) ProgressBar progressBarView;
|
||||
protected
|
||||
@BindView(R.id.text_show_title)
|
||||
TextView showTitleView;
|
||||
protected
|
||||
@BindView(R.id.text_show_subtitle)
|
||||
TextView showSubtitleView;
|
||||
protected
|
||||
@BindView(R.id.text_show_time)
|
||||
TextView showTimeView;
|
||||
protected
|
||||
@BindView(R.id.progressbar_show_progress)
|
||||
ProgressBar progressBarView;
|
||||
|
||||
protected @BindInt(R.integer.view_program_info_update_show_info_interval_seconds) int updateShowInfoIntervalSeconds;
|
||||
protected @BindInt(R.integer.view_program_info_update_show_time_interval_seconds) int updateShowTimeIntervalSeconds;
|
||||
protected
|
||||
@BindInt(R.integer.view_program_info_update_show_info_interval_seconds)
|
||||
int updateShowInfoIntervalSeconds;
|
||||
protected
|
||||
@BindInt(R.integer.view_program_info_update_show_time_interval_seconds)
|
||||
int updateShowTimeIntervalSeconds;
|
||||
|
||||
private ProgramGuideRequest currentShowInfoRequest;
|
||||
private Show currentShow = null;
|
||||
private LiveShow currentShow = null;
|
||||
private ChannelModel currentChannel;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
@ -56,7 +68,7 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestSuccess(Show currentShow) {
|
||||
public void onRequestSuccess(LiveShow currentShow) {
|
||||
logMessage("show info loaded: " + currentShow);
|
||||
|
||||
ProgramInfoViewBase.this.currentShow = currentShow;
|
||||
@ -72,13 +84,13 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(getViewId(), this, true);
|
||||
|
||||
ButterKnife.bind(this, this);
|
||||
|
||||
showProgressAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(context,
|
||||
R.animator.view_program_info_show_progress);
|
||||
R.animator.view_program_info_show_progress);
|
||||
showProgressAnimator.setTarget(progressBarView);
|
||||
}
|
||||
|
||||
@ -117,17 +129,17 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
|
||||
timer = new Timer();
|
||||
timer.scheduleAtFixedRate(new UpdateShowInfoTask(), 0,
|
||||
TimeUnit.SECONDS.toMillis(updateShowInfoIntervalSeconds));
|
||||
TimeUnit.SECONDS.toMillis(updateShowInfoIntervalSeconds));
|
||||
timer.scheduleAtFixedRate(new UpdateShowTimeTask(), 0,
|
||||
TimeUnit.SECONDS.toMillis(updateShowTimeIntervalSeconds));
|
||||
TimeUnit.SECONDS.toMillis(updateShowTimeIntervalSeconds));
|
||||
}
|
||||
|
||||
protected abstract int getViewId();
|
||||
|
||||
private void updateShowInfo() {
|
||||
if (currentShow == null ||
|
||||
currentShow.getEndTime() == null ||
|
||||
currentShow.getEndTime().isBeforeNow()) {
|
||||
currentShow.getEndTime() == null ||
|
||||
currentShow.getEndTime().isBeforeNow()) {
|
||||
reloadProgramGuide();
|
||||
}
|
||||
}
|
||||
@ -141,9 +153,9 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
float progressPercent = currentShow.getProgressPercent();
|
||||
int progress = Math.round(progressPercent * progressBarView.getMax());
|
||||
String startTime = DateUtils.formatDateTime(getContext(),
|
||||
currentShow.getStartTime().getMillis(), DateUtils.FORMAT_SHOW_TIME);
|
||||
currentShow.getStartTime().getMillis(), DateUtils.FORMAT_SHOW_TIME);
|
||||
String endTime = DateUtils.formatDateTime(getContext(),
|
||||
currentShow.getEndTime().getMillis(), DateUtils.FORMAT_SHOW_TIME);
|
||||
currentShow.getEndTime().getMillis(), DateUtils.FORMAT_SHOW_TIME);
|
||||
String fullTime = getContext().getString(R.string.view_program_info_show_time, startTime, endTime);
|
||||
showTimeView.setText(fullTime);
|
||||
showTimeView.setVisibility(VISIBLE);
|
||||
@ -188,10 +200,10 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||
private void loadProgramGuide() {
|
||||
progressBarView.setEnabled(true);
|
||||
progressBarView.setIndeterminate(true);
|
||||
currentShowInfoRequest = new ProgramGuideRequest(getContext())
|
||||
.setChannelId(currentChannel.getId())
|
||||
.setListener(programGuideListener)
|
||||
.execute();
|
||||
currentShowInfoRequest = new ProgramGuideRequest()
|
||||
.setChannelId(currentChannel.getId())
|
||||
.setListener(programGuideListener)
|
||||
.execute();
|
||||
}
|
||||
|
||||
private void chancelProgramGuideLoading() {
|
||||
|
1
programguide/.gitignore
vendored
1
programguide/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/build
|
@ -1,36 +0,0 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.1'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
compile 'com.android.support:appcompat-v7:26.0.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
||||
compile 'com.android.volley:volley:1.0.0'
|
||||
compile 'joda-time:joda-time:2.9.4'
|
||||
compile 'org.jsoup:jsoup:1.9.2'
|
||||
compile 'com.jakewharton.timber:timber:4.5.1'
|
||||
}
|
17
programguide/proguard-rules.pro
vendored
17
programguide/proguard-rules.pro
vendored
@ -1,17 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\tools\android-sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@ -1,12 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.christinecoenen.code.programguide">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application android:allowBackup="false"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="false">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -1,78 +0,0 @@
|
||||
package de.christinecoenen.code.programguide;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import de.christinecoenen.code.programguide.model.Channel;
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
import de.christinecoenen.code.programguide.plugins.IProgramGuideDownloader;
|
||||
import de.christinecoenen.code.programguide.plugins.PluginRegistry;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ProgramGuideRequest {
|
||||
|
||||
private final Context context;
|
||||
private Listener listener;
|
||||
private Channel channelId;
|
||||
private IProgramGuideDownloader downloader;
|
||||
|
||||
public ProgramGuideRequest(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ProgramGuideRequest setListener(Listener listener) {
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public ProgramGuideRequest setChannelId(Channel channelId) {
|
||||
this.channelId = channelId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgramGuideRequest setChannelId(String channelId) {
|
||||
Channel newChannel = null;
|
||||
try {
|
||||
newChannel = Channel.getById(channelId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Timber.w(channelId + " is no valid channel id");
|
||||
}
|
||||
|
||||
return setChannelId(newChannel);
|
||||
}
|
||||
|
||||
public ProgramGuideRequest execute() {
|
||||
if (listener == null) {
|
||||
throw new RuntimeException("listener not set");
|
||||
}
|
||||
|
||||
if (channelId == null) {
|
||||
Timber.w("no valid channel id set");
|
||||
listener.onRequestError();
|
||||
return this;
|
||||
}
|
||||
|
||||
downloader = PluginRegistry.getInstance(context).getDownloader(channelId, listener);
|
||||
|
||||
if (downloader == null) {
|
||||
listener.onRequestError();
|
||||
} else {
|
||||
downloader.download();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (downloader != null) {
|
||||
downloader.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onRequestError();
|
||||
|
||||
void onRequestSuccess(Show currentShow);
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package de.christinecoenen.code.programguide.plugins;
|
||||
|
||||
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import de.christinecoenen.code.programguide.Cache;
|
||||
import de.christinecoenen.code.programguide.model.Channel;
|
||||
import de.christinecoenen.code.programguide.ProgramGuideRequest;
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
|
||||
public abstract class BaseProgramGuideDownloader implements IProgramGuideDownloader {
|
||||
|
||||
protected final DownloaderListener downloaderListener = new DownloaderListener() {
|
||||
@Override
|
||||
public void onRequestError() {
|
||||
listener.onRequestError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestSuccess(Map<Channel, Show> shows) {
|
||||
Cache.getInstance().save(shows);
|
||||
onRequestSuccess(shows.get(channel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestSuccess(Show show) {
|
||||
if (show == null) {
|
||||
onRequestError();
|
||||
return;
|
||||
}
|
||||
|
||||
listener.onRequestSuccess(show);
|
||||
Cache.getInstance().save(channel, show);
|
||||
}
|
||||
};
|
||||
|
||||
protected final RequestQueue queue;
|
||||
protected Request<?> request;
|
||||
protected final Channel channel;
|
||||
|
||||
private final ProgramGuideRequest.Listener listener;
|
||||
|
||||
|
||||
protected BaseProgramGuideDownloader(RequestQueue queue, Channel channel, ProgramGuideRequest.Listener listener) {
|
||||
this.queue = queue;
|
||||
this.channel = channel;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download() {
|
||||
Show show = Cache.getInstance().getShow(this.channel);
|
||||
|
||||
if (show == null) {
|
||||
downloadWithoutCache();
|
||||
} else {
|
||||
listener.onRequestSuccess(show);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (request != null) {
|
||||
request.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void downloadWithoutCache();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected interface DownloaderListener {
|
||||
void onRequestError();
|
||||
void onRequestSuccess(Map<Channel, Show> shows);
|
||||
void onRequestSuccess(Show shows);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package de.christinecoenen.code.programguide.plugins;
|
||||
|
||||
|
||||
public interface IProgramGuideDownloader {
|
||||
void download();
|
||||
void cancel();
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package de.christinecoenen.code.programguide.plugins;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
|
||||
import de.christinecoenen.code.programguide.ProgramGuideRequest;
|
||||
import de.christinecoenen.code.programguide.model.Channel;
|
||||
import de.christinecoenen.code.programguide.plugins.zappbackend.ZappBackendDownloader;
|
||||
|
||||
public class PluginRegistry {
|
||||
|
||||
private static PluginRegistry instance = null;
|
||||
|
||||
public static PluginRegistry getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
instance = new PluginRegistry(context);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private final RequestQueue queue;
|
||||
|
||||
private PluginRegistry(Context context) {
|
||||
queue = Volley.newRequestQueue(context);
|
||||
}
|
||||
|
||||
public IProgramGuideDownloader getDownloader(Channel channel, ProgramGuideRequest.Listener listener) {
|
||||
switch (channel) {
|
||||
case DAS_ERSTE:
|
||||
case BR_NORD:
|
||||
case BR_SUED:
|
||||
case HR:
|
||||
case MDR_SACHSEN:
|
||||
case MDR_SACHSEN_ANHALT:
|
||||
case MDR_THUERINGEN:
|
||||
case NDR_HAMBURG:
|
||||
case NDR_MECKLENBURG_VORPOMMERN:
|
||||
case NDR_NIEDERSACHSEN:
|
||||
case NDR_SCHLESWIG_HOLSTEIN:
|
||||
case RBB_BERLIN:
|
||||
case RBB_BRANDENBURG:
|
||||
case SR:
|
||||
case SWR_BADEN_WUERTTEMBERG:
|
||||
case SWR_RHEINLAND_PFALZ:
|
||||
case WDR:
|
||||
case ARD_ALPHA:
|
||||
case TAGESSCHAU24:
|
||||
case ONE:
|
||||
|
||||
case ZDF:
|
||||
case KIKA:
|
||||
case PHOENIX:
|
||||
case ZDF_INFO:
|
||||
case ZDF_NEO:
|
||||
case DREISAT:
|
||||
case ARTE:
|
||||
|
||||
case DEUTSCHE_WELLE:
|
||||
case DEUTSCHE_WELLE_PLUS:
|
||||
|
||||
case PARLAMENTSFERNSEHEN_1:
|
||||
case PARLAMENTSFERNSEHEN_2:
|
||||
return new ZappBackendDownloader(queue, channel, listener);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package de.christinecoenen.code.programguide.plugins.zappbackend;
|
||||
|
||||
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.JsonObjectRequest;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.christinecoenen.code.programguide.ProgramGuideRequest;
|
||||
import de.christinecoenen.code.programguide.model.Channel;
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
import de.christinecoenen.code.programguide.plugins.BaseProgramGuideDownloader;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ZappBackendDownloader extends BaseProgramGuideDownloader {
|
||||
|
||||
private static final String API_URL = "https://zappbackend.herokuapp.com/v1/shows/";
|
||||
|
||||
public ZappBackendDownloader(RequestQueue queue, Channel channel, ProgramGuideRequest.Listener listener) {
|
||||
super(queue, channel, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadWithoutCache() {
|
||||
String url = API_URL + channel.toString();
|
||||
request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
|
||||
@Override
|
||||
public void onResponse(JSONObject response) {
|
||||
Timber.d("json loaded");
|
||||
parse(response);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
Timber.d("error loading json: " + error.getMessage());
|
||||
downloaderListener.onRequestError();
|
||||
}
|
||||
});
|
||||
|
||||
queue.add(request);
|
||||
}
|
||||
|
||||
private void parse(JSONObject json) {
|
||||
Show show;
|
||||
|
||||
try {
|
||||
show = ZappBackendParser.parse(json);
|
||||
} catch (JSONException e) {
|
||||
Timber.d(e);
|
||||
downloaderListener.onRequestError();
|
||||
return;
|
||||
}
|
||||
|
||||
downloaderListener.onRequestSuccess(show);
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package de.christinecoenen.code.programguide.plugins.zappbackend;
|
||||
|
||||
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.christinecoenen.code.programguide.model.Show;
|
||||
import timber.log.Timber;
|
||||
|
||||
class ZappBackendParser {
|
||||
|
||||
// 2017-03-11T17:27:00+01:00
|
||||
private static final DateTimeFormatter formatter = ISODateTimeFormat.dateTimeParser();
|
||||
|
||||
static Show parse(JSONObject json) throws JSONException {
|
||||
Show show = new Show();
|
||||
|
||||
JSONArray shows = json.getJSONArray("shows");
|
||||
JSONObject showJson = shows.getJSONObject(0);
|
||||
|
||||
String title = showJson.getString("title");
|
||||
String subtitle = getOptionalString(showJson, "subtitle");
|
||||
String startTime = getOptionalString(showJson, "startTime");
|
||||
String endTime = getOptionalString(showJson, "endTime");
|
||||
|
||||
show.setTitle(title);
|
||||
show.setSubtitle(subtitle);
|
||||
if (startTime != null && endTime != null) {
|
||||
show.setStartTime(formatter.parseDateTime(startTime));
|
||||
show.setEndTime(formatter.parseDateTime(endTime));
|
||||
}
|
||||
|
||||
return show;
|
||||
}
|
||||
|
||||
private static String getOptionalString(JSONObject json, String key) {
|
||||
try {
|
||||
String value = json.getString(key);
|
||||
return value.equals("null") ? null : value;
|
||||
} catch (JSONException e) {
|
||||
Timber.d("optional json key is not present: " + key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">Program Guide</string>
|
||||
</resources>
|
@ -1,18 +0,0 @@
|
||||
package de.christinecoenen.code.programguide;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
include ':app', ':programguide'
|
||||
include ':app'
|
||||
|
Loading…
Reference in New Issue
Block a user