mirror of
https://github.com/mediathekview/zapp.git
synced 2024-09-19 20:02:17 +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>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
<option value="$PROJECT_DIR$/programguide" />
|
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/Zapp.iml" filepath="$PROJECT_DIR$/Zapp.iml" />
|
<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$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/programguide/programguide.iml" filepath="$PROJECT_DIR$/programguide/programguide.iml" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -37,7 +37,6 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
compile project(':programguide')
|
|
||||||
|
|
||||||
// tests
|
// tests
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
@ -82,4 +81,7 @@ dependencies {
|
|||||||
|
|
||||||
// timber logging
|
// timber logging
|
||||||
compile 'com.jakewharton.timber:timber:4.5.1'
|
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.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import de.christinecoenen.code.programguide.model.Channel;
|
import de.christinecoenen.code.zapp.app.livestream.api.model.Channel;
|
||||||
import de.christinecoenen.code.programguide.model.Show;
|
import de.christinecoenen.code.zapp.app.livestream.model.LiveShow;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache singleton for currently running show on any channel.
|
* Cache singleton for currently running show on any channel.
|
||||||
*/
|
*/
|
||||||
public class Cache {
|
class Cache {
|
||||||
|
|
||||||
private static Cache instance = null;
|
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) {
|
if (instance == null) {
|
||||||
instance = new Cache();
|
instance = new Cache();
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(Channel channel, Show show) {
|
public void save(Channel channel, LiveShow show) {
|
||||||
this.shows.put(channel, 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
|
* @return currently running show or null in case of cache miss
|
||||||
*/
|
*/
|
||||||
public Show getShow(Channel channel) {
|
LiveShow getShow(Channel channel) {
|
||||||
Show show = shows.get(channel);
|
LiveShow show = shows.get(channel);
|
||||||
|
|
||||||
if (show == null) {
|
if (show == null) {
|
||||||
Timber.d("cache miss: " + channel);
|
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 {
|
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.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
public class Show {
|
public class LiveShow {
|
||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
private String subtitle;
|
private String subtitle;
|
@ -20,24 +20,36 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import butterknife.BindInt;
|
import butterknife.BindInt;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
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.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 de.christinecoenen.code.zapp.model.ChannelModel;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public abstract class ProgramInfoViewBase extends LinearLayout {
|
public abstract class ProgramInfoViewBase extends LinearLayout {
|
||||||
|
|
||||||
protected @BindView(R.id.text_show_title) TextView showTitleView;
|
protected
|
||||||
protected @BindView(R.id.text_show_subtitle) TextView showSubtitleView;
|
@BindView(R.id.text_show_title)
|
||||||
protected @BindView(R.id.text_show_time) TextView showTimeView;
|
TextView showTitleView;
|
||||||
protected @BindView(R.id.progressbar_show_progress) ProgressBar progressBarView;
|
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
|
||||||
protected @BindInt(R.integer.view_program_info_update_show_time_interval_seconds) int updateShowTimeIntervalSeconds;
|
@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 ProgramGuideRequest currentShowInfoRequest;
|
||||||
private Show currentShow = null;
|
private LiveShow currentShow = null;
|
||||||
private ChannelModel currentChannel;
|
private ChannelModel currentChannel;
|
||||||
|
|
||||||
private final Handler handler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
@ -56,7 +68,7 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestSuccess(Show currentShow) {
|
public void onRequestSuccess(LiveShow currentShow) {
|
||||||
logMessage("show info loaded: " + currentShow);
|
logMessage("show info loaded: " + currentShow);
|
||||||
|
|
||||||
ProgramInfoViewBase.this.currentShow = currentShow;
|
ProgramInfoViewBase.this.currentShow = currentShow;
|
||||||
@ -188,7 +200,7 @@ public abstract class ProgramInfoViewBase extends LinearLayout {
|
|||||||
private void loadProgramGuide() {
|
private void loadProgramGuide() {
|
||||||
progressBarView.setEnabled(true);
|
progressBarView.setEnabled(true);
|
||||||
progressBarView.setIndeterminate(true);
|
progressBarView.setIndeterminate(true);
|
||||||
currentShowInfoRequest = new ProgramGuideRequest(getContext())
|
currentShowInfoRequest = new ProgramGuideRequest()
|
||||||
.setChannelId(currentChannel.getId())
|
.setChannelId(currentChannel.getId())
|
||||||
.setListener(programGuideListener)
|
.setListener(programGuideListener)
|
||||||
.execute();
|
.execute();
|
||||||
|
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