2
0
Fork 0
mirror of https://github.com/NiciDieNase/chaosflix synced 2025-02-28 13:17:09 +00:00

make touch work with common

This commit is contained in:
Felix 2017-10-31 20:49:43 +01:00
parent dca80e2fc5
commit eb49405200
21 changed files with 288 additions and 366 deletions

View file

@ -10,7 +10,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
classpath 'com.android.tools.build:gradle:3.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
@ -20,6 +20,7 @@ buildscript {
allprojects {
repositories {
mavenLocal()
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://maven.google.com" }
@ -27,11 +28,11 @@ allprojects {
}
ext{
compileSdkVersion = 26
buildToolsVersion = "26.0.1"
supportLibraryVersion = "26.1.0"
compileSdkVersion = 27
buildToolsVersion = "27.0.0"
supportLibraryVersion = "27.0.0"
constraintLayoutVersion = "1.0.2"
archCompVersion = "1.0.0-alpha9-1"
archCompVersion = "1.0.0-rc1"
minSDK = 22
targetSDK = 26
}

View file

@ -1 +1 @@
include ':leanback', ':common', ':touch'
include ':touch'

View file

@ -46,54 +46,61 @@ android {
dataBinding {
enabled = true
}
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
implementation project(':common')
compile fileTree(include: ['*.jar'], dir: 'libs')
implementation 'de.nicidienase.chaosflix:common:1.1.0-SNAPSHOT'
implementation 'com.android.support:multidex:1.0.1'
implementation "com.android.support:support-v4:${rootProject.ext.supportLibraryVersion}"
implementation "com.android.support:recyclerview-v7:${rootProject.ext.supportLibraryVersion}"
implementation "com.android.support:cardview-v7:${rootProject.ext.supportLibraryVersion}"
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile "com.android.support:design:${rootProject.ext.supportLibraryVersion}"
implementation "com.android.support:design:${rootProject.ext.supportLibraryVersion}"
implementation "android.arch.lifecycle:runtime:1.0.3"
implementation "android.arch.lifecycle:extensions:${rootProject.ext.archCompVersion}"
implementation "android.arch.lifecycle:common-java8:1.0.0-rc1"
implementation "android.arch.persistence.room:runtime:${rootProject.ext.archCompVersion}"
implementation "android.arch.persistence.room:rxjava2:${rootProject.ext.archCompVersion}"
kapt 'com.android.databinding:compiler:3.0.0-rc2'
kapt 'com.android.databinding:compiler:3.1.0-alpha01'
kapt "android.arch.lifecycle:compiler:${rootProject.ext.archCompVersion}"
kapt "android.arch.persistence.room:compiler:${rootProject.ext.archCompVersion}"
compile "org.jetbrains.kotlin:kotlin-reflect:1.1.50"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.1.50"
compile 'com.google.android.exoplayer:exoplayer:r2.5.2'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.jakewharton:butterknife:8.5.1'
implementation 'com.squareup.retrofit2:retrofit:2.2.0'
implementation 'com.squareup.retrofit2:converter-jackson:2.2.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0'
implementation 'com.google.android.exoplayer:exoplayer:r2.5.2'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.jakewharton:butterknife:8.5.1'
kapt 'com.jakewharton:butterknife-compiler:8.5.1'
debugCompile 'com.facebook.stetho:stetho:1.4.2'
debugCompile 'com.facebook.stetho:stetho-okhttp:1.4.2'
debugCompile 'com.facebook.stetho:stetho-okhttp3:1.4.2'
implementation 'io.reactivex.rxjava2:rxjava:2.1.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
androidTestCompile('com.android.support.test:rules:0.5') {
exclude module: 'support-annotations'
}
androidTestCompile('com.android.support.test:runner:0.5') {
exclude module: 'support-annotations'
}
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.6.0'
//androidTestCompile group: 'commons-io', name: 'commons-io', version: '2.4'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
testCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2', {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
}
compile 'commons-io:commons-io:2.4'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'commons-io:commons-io:2.4'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
repositories {
mavenCentral()

View file

@ -0,0 +1,31 @@
package de.nicidienase.chaosflix
import android.arch.lifecycle.ViewModelProviders
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import android.test.ActivityInstrumentationTestCase2
import android.view.View
import de.nicidienase.chaosflix.common.entities.userdata.PlaybackProgress
import org.junit.Test
import org.junit.runner.RunWith
import de.nicidienase.chaosflix.touch.ViewModelFactory
import io.reactivex.functions.Consumer
/**
* Created by felix on 31.10.17.
*/
@RunWith(AndroidJUnit4::class)
class PersistenceTest {
@Test
fun test1() {
val playbackProgressDao = ViewModelFactory.database.playbackProgressDao()
playbackProgressDao.saveProgress(PlaybackProgress(23,1337))
playbackProgressDao.getProgressForEvent(23).subscribe({
assert(it.eventId == 23L && it.progress == 1337L)
})
}
}

View file

@ -11,7 +11,7 @@
android:icon="@drawable/icon_notext_512x512"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".ChaosflixApplication"
android:name=".touch.ChaosflixApplication"
android:theme="@style/AppTheme">
<activity android:name=".touch.activities.BrowseActivity"
android:label="@string/app_name">

View file

@ -3,16 +3,20 @@ package de.nicidienase.chaosflix.touch
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import android.arch.persistence.room.Room
import de.nicidienase.chaosflix.ChaosflixApplication
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import de.nicidienase.chaosflix.BuildConfig
import de.nicidienase.chaosflix.R
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
import de.nicidienase.chaosflix.common.network.RecordingService
import de.nicidienase.chaosflix.common.network.StreamingService
import de.nicidienase.chaosflix.touch.BrowseViewModel
import de.nicidienase.chaosflix.touch.viewmodels.PlayerViewModel
import de.nicidienase.chaosflix.touch.viewmodels.BrowseViewModel
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.jackson.JacksonConverterFactory
object ViewModelFactory: ViewModelProvider.Factory{
@ -21,18 +25,25 @@ object ViewModelFactory: ViewModelProvider.Factory{
val streamingApi: StreamingService
init {
val res = ChaosflixApplication.getContext().getResources()
val res = ChaosflixApplication.APPLICATION_CONTEXT.resources
val recordingUrl = res.getString(R.string.api_media_ccc_url)
val streamingUrl = res.getString(R.string.streaming_media_ccc_url)
val client = OkHttpClient()
val gsonConverterFactory = GsonConverterFactory.create()
val client: OkHttpClient
if(BuildConfig.DEBUG){
client = OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.build()
} else {
client = OkHttpClient()
}
val jacksonConverterFactory = JacksonConverterFactory.create(ObjectMapper().registerModule(KotlinModule()))
val rxJava2CallAdapterFactory = RxJava2CallAdapterFactory.create()
val retrofitRecordings = Retrofit.Builder()
.baseUrl(recordingUrl)
.client(client)
.addConverterFactory(gsonConverterFactory)
.addConverterFactory(jacksonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build()
recordingApi = retrofitRecordings.create(RecordingService::class.java)
@ -40,18 +51,21 @@ object ViewModelFactory: ViewModelProvider.Factory{
val retrofigStreaming = Retrofit.Builder()
.baseUrl(streamingUrl)
.client(client)
.addConverterFactory(gsonConverterFactory)
.addConverterFactory(jacksonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build()
streamingApi = retrofigStreaming.create(StreamingService::class.java)
database = Room.databaseBuilder(ChaosflixApplication.getContext(),
database = Room.databaseBuilder(ChaosflixApplication.APPLICATION_CONTEXT,
ChaosflixDatabase::class.java,"mediaccc.de").build()
}
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if(modelClass.isAssignableFrom(BrowseViewModel::class.java)){
if(modelClass.isAssignableFrom(BrowseViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return BrowseViewModel(database, recordingApi, streamingApi) as T
} else if(modelClass.isAssignableFrom(PlayerViewModel::class.java)) {
return PlayerViewModel(database, recordingApi, streamingApi) as T
} else {
throw UnsupportedOperationException("The requested ViewModel is currently unsupported. " +
"Please make sure to implement are correct creation of it. " +

View file

@ -1,98 +0,0 @@
package de.nicidienase.chaosflix.touch
import android.arch.lifecycle.ViewModel
import android.util.Log
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
import de.nicidienase.chaosflix.common.entities.PlaybackProgress
import de.nicidienase.chaosflix.common.entities.WatchlistItem
import de.nicidienase.chaosflix.common.entities.recording.Conference
import de.nicidienase.chaosflix.common.entities.recording.ConferencesWrapper
import de.nicidienase.chaosflix.common.entities.recording.Event
import de.nicidienase.chaosflix.common.entities.recording.Recording
import de.nicidienase.chaosflix.common.entities.streaming.LiveConference
import de.nicidienase.chaosflix.common.network.RecordingService
import de.nicidienase.chaosflix.common.network.StreamingService
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
/**
* Created by felix on 12.10.17.
*/
class BrowseViewModel(
val database: ChaosflixDatabase,
val recordingApi: RecordingService,
val streamingApi: StreamingService
) : ViewModel(){
private val TAG = BrowseViewModel::class.simpleName
fun getConferencesWrapper(): Observable<ConferencesWrapper> {
return recordingApi.getConferences()
.doOnError({ throwable -> Log.d(TAG, throwable.cause.toString()) })
.subscribeOn(Schedulers.io())
}
fun getConferencesByGroup(group: String): Observable<List<Conference>> {
return recordingApi.conferences!!.map { conf -> conf?.conferencesBySeries.get(group) }
}
fun getConference(mConferenceId: Int): Observable<Conference> {
return recordingApi.getConference(mConferenceId.toLong())
.subscribeOn(Schedulers.io())
}
fun getEvent(apiID: Int): Observable<Event> {
return recordingApi.getEvent(apiID.toLong())
.subscribeOn(Schedulers.io())
}
fun getRecording(id: Long): Observable<Recording> {
return recordingApi.getRecording(id)
.subscribeOn(Schedulers.io())
}
fun getStreamingConferences(): Observable<List<LiveConference>> {
return streamingApi.getStreamingConferences()
.subscribeOn(Schedulers.io())
}
fun setPlaybackProgress(apiId: Int, progress: Long) {
database.playbackProgressDao().getProgressForEvent(apiId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe { playbackProgress: PlaybackProgress? ->
if(playbackProgress != null){
playbackProgress.progress = progress
database.playbackProgressDao().saveProgress(playbackProgress)
} else {
database.playbackProgressDao().saveProgress(
PlaybackProgress(apiId,progress))
}
}
}
fun getPlaybackProgress(apiID: Int): Flowable<PlaybackProgress> {
return database.playbackProgressDao().getProgressForEvent(apiID)
}
fun createBookmark(apiId: Int) {
database.watchlistItemDao().getItemForEvent(apiId)
.subscribe { watchlistItem: WatchlistItem? ->
if (watchlistItem == null) {
database.watchlistItemDao()
.saveItem(WatchlistItem(apiId, apiId))
}
}
}
fun getBookmark(apiId: Int): Flowable<WatchlistItem> {
return database.watchlistItemDao().getItemForEvent(apiId)
}
fun removeBookmark(apiID: Int) {
getBookmark(apiID).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe { watchlistItem -> database.watchlistItemDao().deleteItem(watchlistItem) }
}
}

View file

@ -0,0 +1,21 @@
package de.nicidienase.chaosflix.touch
import android.app.Application
import android.content.Context
import com.facebook.stetho.Stetho
import de.nicidienase.chaosflix.BuildConfig
class ChaosflixApplication: Application(){
override fun onCreate() {
super.onCreate()
APPLICATION_CONTEXT = this
if(BuildConfig.DEBUG){
Stetho.initializeWithDefaults(this);
}
}
companion object {
lateinit var APPLICATION_CONTEXT: Context
}
}

View file

@ -1,157 +0,0 @@
package de.nicidienase.chaosflix.touch;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Room;
import android.content.res.Resources;
import android.util.Log;
import java.util.List;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase;
import de.nicidienase.chaosflix.common.entities.PlaybackProgress;
import de.nicidienase.chaosflix.common.entities.WatchlistItem;
import de.nicidienase.chaosflix.common.entities.recording.Conference;
import de.nicidienase.chaosflix.common.entities.recording.ConferencesWrapper;
import de.nicidienase.chaosflix.common.entities.recording.Event;
import de.nicidienase.chaosflix.common.entities.recording.Recording;
import de.nicidienase.chaosflix.common.entities.streaming.LiveConference;
import de.nicidienase.chaosflix.common.network.RecordingService;
import de.nicidienase.chaosflix.common.network.StreamingService;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by felix on 24.09.17.
*/
public class ChaosflixViewModel extends AndroidViewModel {
private static final String TAG = ChaosflixViewModel.class.getSimpleName();
private final StreamingService streamingApi;
private final RecordingService recordingApi;
private final ChaosflixDatabase database;
CompositeDisposable disposable = new CompositeDisposable();
public ChaosflixViewModel(Application application){
super(application);
Resources res = application.getResources();
String recordingUrl = res.getString(R.string.api_media_ccc_url);
String streamingUrl = res.getString(R.string.streaming_media_ccc_url);
OkHttpClient client = new OkHttpClient();
GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create();
RxJava2CallAdapterFactory rxJava2CallAdapterFactory = RxJava2CallAdapterFactory.create();
Retrofit retrofitRecordings = new Retrofit.Builder()
.baseUrl(recordingUrl)
.client(client)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build();
recordingApi = retrofitRecordings.create(RecordingService.class);
Retrofit retrofigStreaming = new Retrofit.Builder()
.baseUrl(streamingUrl)
.client(client)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.build();
streamingApi = retrofigStreaming.create(StreamingService.class);
database = Room.databaseBuilder(getApplication().getApplicationContext(), ChaosflixDatabase.class, "mediaccc.db").build();
}
public LiveData<ConferencesWrapper> getConferencesWrapperAsLiveData(){
return new LiveData<ConferencesWrapper>() {
@Override
protected void onActive() {
super.onActive();
recordingApi.getConferences()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(conferencesWrapper -> setValue(conferencesWrapper));
}
};
}
public Observable<ConferencesWrapper> getConferencesWrapper() {
return recordingApi.getConferences()
.doOnError(throwable -> Log.d(TAG, String.valueOf(throwable.getCause())))
.subscribeOn(Schedulers.io());
}
public Observable<List<Conference>> getConferencesByGroup(String group){
return recordingApi.getConferences().map(
conferencesWrapper -> conferencesWrapper.getConferencesBySeries().get(group))
.subscribeOn(Schedulers.io());
}
public Observable<Conference> getConference(int mConferenceId) {
return recordingApi.getConference(mConferenceId)
.subscribeOn(Schedulers.io());
}
public Observable<Event> getEvent(int apiID) {
return recordingApi.getEvent(apiID)
.subscribeOn(Schedulers.io());
}
public Observable<Recording> getRecording(long id) {
return recordingApi.getRecording(id)
.subscribeOn(Schedulers.io());
}
public Observable<List<LiveConference>> getStreamingConferences() {
return streamingApi.getStreamingConferences()
.subscribeOn(Schedulers.io());
}
public void setPlaybackProgress(int apiId, long progress){
database.playbackProgressDao().getProgressForEvent(apiId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(playbackProgress -> {
if(playbackProgress != null){
playbackProgress.setProgress(progress);
} else {
playbackProgress = new PlaybackProgress(apiId,progress);
}
database.playbackProgressDao().saveProgress(playbackProgress);
});
}
public Flowable<PlaybackProgress> getPlaybackProgress(int apiID) {
return database.playbackProgressDao().getProgressForEvent(apiID);
}
public void createBookmark(int apiId){
database.watchlistItemDao().getItemForEvent(apiId)
.subscribe(watchlistItem -> {
if(watchlistItem == null){
watchlistItem = new WatchlistItem(apiId,apiId);
database.watchlistItemDao().saveItem(watchlistItem);
}
});
}
public Flowable<WatchlistItem> getBookmark(int apiId){
return database.watchlistItemDao().getItemForEvent(apiId);
}
public void removeBookmark(int apiID) {
getBookmark(apiID).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(watchlistItem ->
database.watchlistItemDao().deleteItem(watchlistItem));
}
}

View file

@ -45,12 +45,12 @@ public class ConferenceGroupsFragmentPager extends FragmentPagerAdapter {
@Override
public CharSequence getPageTitle(int position) {
return ConferencesWrapper.getStringForTag(orderedConferencesList.get(position));
return ConferencesWrapper.Companion.getStringForTag(orderedConferencesList.get(position));
}
public void setContent(Map<String, List<Conference>> conferenceMap) {
orderedConferencesList = new ArrayList<>();
for (String tag : ConferencesWrapper.getOrderedConferencesList()) {
for (String tag : ConferencesWrapper.Companion.getOrderedConferencesList()) {
if (conferenceMap.keySet().contains(tag)) {
orderedConferencesList.add(tag);
}

View file

@ -20,9 +20,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* A simple {@link Fragment} subclass.
*/
public class AboutActivity extends AppCompatActivity {
private static final String TAG = AboutActivity.class.getSimpleName();

View file

@ -2,7 +2,6 @@ package de.nicidienase.chaosflix.touch.activities;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
@ -14,6 +13,7 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.transition.Slide;
import android.transition.TransitionInflater;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
@ -23,8 +23,7 @@ import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.common.entities.recording.Conference;
import de.nicidienase.chaosflix.common.entities.recording.Event;
import de.nicidienase.chaosflix.common.entities.recording.Recording;
import de.nicidienase.chaosflix.touch.BrowseViewModel;
import de.nicidienase.chaosflix.touch.ChaosflixViewModel;
import de.nicidienase.chaosflix.touch.viewmodels.BrowseViewModel;
import de.nicidienase.chaosflix.touch.ViewModelFactory;
import de.nicidienase.chaosflix.touch.fragments.ConferencesTabBrowseFragment;
import de.nicidienase.chaosflix.touch.fragments.EventDetailsFragment;
@ -40,8 +39,7 @@ import io.reactivex.disposables.CompositeDisposable;
public class BrowseActivity extends AppCompatActivity implements
ConferencesTabBrowseFragment.OnConferenceListFragmentInteractionListener,
EventsFragment.OnEventsListFragmentInteractionListener,
EventDetailsFragment.OnEventDetailsFragmentInteractionListener,
ExoPlayerFragment.OnMediaPlayerInteractionListener {
EventDetailsFragment.OnEventDetailsFragmentInteractionListener{
private static final String TAG = BrowseActivity.class.getSimpleName();
CompositeDisposable mDisposables = new CompositeDisposable();
@ -62,15 +60,18 @@ public class BrowseActivity extends AppCompatActivity implements
// ft.replace(R.id.fragment_container,browseFragment);
// ft.setReorderingAllowed(true);
// ft.commit();
// });
mDisposables.add(mViewModel.getConferencesWrapper()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(conferencesWrapper -> {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container,browseFragment);
ft.setReorderingAllowed(true);
ft.commit();
}, throwable -> Snackbar.make(findViewById(R.id.fragment_container),throwable.getMessage(),Snackbar.LENGTH_INDEFINITE).show()));
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container,browseFragment);
ft.setReorderingAllowed(true);
ft.commit();
}, throwable -> {
Snackbar.make(findViewById(R.id.fragment_container),throwable.getMessage(),Snackbar.LENGTH_INDEFINITE).show();
Log.d(TAG,throwable.getMessage(),throwable);
}));
// });
}
}

View file

@ -2,7 +2,6 @@ package de.nicidienase.chaosflix.touch.activities;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
@ -12,30 +11,29 @@ import android.support.v7.app.AppCompatActivity;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.common.entities.recording.Event;
import de.nicidienase.chaosflix.common.entities.recording.Recording;
import de.nicidienase.chaosflix.touch.ChaosflixViewModel;
import de.nicidienase.chaosflix.common.entities.userdata.PlaybackProgress;
import de.nicidienase.chaosflix.touch.ViewModelFactory;
import de.nicidienase.chaosflix.touch.fragments.ExoPlayerFragment;
import de.nicidienase.chaosflix.touch.viewmodels.PlayerViewModel;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by felix on 01.10.17.
*/
public class PlayerActivity extends AppCompatActivity implements ExoPlayerFragment.OnMediaPlayerInteractionListener {
public static final String EVENT_ID = "event_id";
public static final String RECORDING_ID = "recording_id";
private ChaosflixViewModel viewModel;
private PlayerViewModel viewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_container_layout);
viewModel = ViewModelProviders.of(this).get(ChaosflixViewModel.class);
viewModel = ViewModelProviders.of(this, ViewModelFactory.INSTANCE).get(PlayerViewModel.class);
int eventId = getIntent().getExtras().getInt(EVENT_ID);
int recordingId = getIntent().getExtras().getInt(RECORDING_ID);
long eventId = getIntent().getExtras().getLong(EVENT_ID);
long recordingId = getIntent().getExtras().getLong(RECORDING_ID);
if(savedInstanceState == null){
loadFragment(eventId, recordingId);
@ -52,7 +50,7 @@ public class PlayerActivity extends AppCompatActivity implements ExoPlayerFragme
loadFragment(eventId,recordingId);
}
private void loadFragment(int eventId, int recordingId) {
private void loadFragment(long eventId, long recordingId) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Observable.zip(viewModel.getEvent(eventId),viewModel.getRecording(recordingId),
(event, recording) -> new Object[]{event,recording})
@ -65,4 +63,14 @@ public class PlayerActivity extends AppCompatActivity implements ExoPlayerFragme
ft.commit();
});
}
@Override
public Flowable<PlaybackProgress> getPlaybackProgress(long apiId) {
return viewModel.getPlaybackProgress(apiId);
}
@Override
public void setPlaybackProgress(long apiId, long progress) {
viewModel.setPlaybackProgress(apiId,progress);
}
}

View file

@ -1,13 +1,11 @@
package de.nicidienase.chaosflix.touch.fragments;
import android.arch.lifecycle.ViewModelProviders;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.touch.ChaosflixViewModel;
import de.nicidienase.chaosflix.touch.viewmodels.BrowseViewModel;
/**
* Created by felix on 25.09.17.
@ -15,16 +13,16 @@ import de.nicidienase.chaosflix.touch.ChaosflixViewModel;
public class ChaosflixFragment extends Fragment {
private ChaosflixViewModel mViewModel;
private BrowseViewModel mViewModel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewModel = ViewModelProviders.of(getActivity()).get(ChaosflixViewModel.class);
mViewModel = ViewModelProviders.of(getActivity()).get(BrowseViewModel.class);
}
public ChaosflixViewModel getViewModel() {
public BrowseViewModel getViewModel() {
return mViewModel;
}
}

View file

@ -83,7 +83,7 @@ public class ConferencesTabBrowseFragment extends ChaosflixFragment {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(conferencesWrapper -> {
fragmentPager.setContent(conferencesWrapper.getConferencesBySeries());
fragmentPager.setContent(conferencesWrapper.getConferenceMap());
mViewPager.setCurrentItem(mCurrentTab);
});

View file

@ -1,11 +1,9 @@
package de.nicidienase.chaosflix.touch.fragments;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.transition.Transition;
import android.transition.TransitionInflater;
@ -23,10 +21,9 @@ import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.common.entities.recording.Event;
import de.nicidienase.chaosflix.common.entities.recording.Recording;
import de.nicidienase.chaosflix.databinding.FragmentEventDetailsNewBinding;
import de.nicidienase.chaosflix.touch.ChaosflixViewModel;
import io.reactivex.disposables.CompositeDisposable;
public class EventDetailsFragment extends Fragment {
public class EventDetailsFragment extends ChaosflixFragment {
private static final String TAG = EventDetailsFragment.class.getSimpleName();
private static final String EVENT_PARAM = "event_param";
@ -34,7 +31,6 @@ public class EventDetailsFragment extends Fragment {
private Event mEvent;
private boolean appBarExpanded;
private ChaosflixViewModel viewModel;
private CompositeDisposable disposable = new CompositeDisposable();
public static EventDetailsFragment newInstance(Event event) {
@ -58,7 +54,6 @@ public class EventDetailsFragment extends Fragment {
if (getArguments() != null) {
mEvent = getArguments().getParcelable(EVENT_PARAM);
}
viewModel = ViewModelProviders.of(this).get(ChaosflixViewModel.class);
}
@Override
@ -139,7 +134,7 @@ public class EventDetailsFragment extends Fragment {
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
disposable.add(viewModel.getBookmark(mEvent.getApiID())
disposable.add(getViewModel().getBookmark(mEvent.getApiID())
.subscribe(watchlistItem -> {
if (watchlistItem != null) {
menu.findItem(R.id.action_bookmark).setVisible(false);
@ -162,10 +157,10 @@ public class EventDetailsFragment extends Fragment {
play();
return true;
case R.id.action_bookmark:
viewModel.createBookmark(mEvent.getApiID());
getViewModel().createBookmark(mEvent.getApiID());
return true;
case R.id.action_unbookmark:
viewModel.removeBookmark(mEvent.getApiID());
getViewModel().removeBookmark(mEvent.getApiID());
return true;
case R.id.action_download:
Snackbar.make(item.getActionView(),"Start download",Snackbar.LENGTH_LONG).show();

View file

@ -34,16 +34,16 @@ public class EventsFragment extends ChaosflixFragment {
private Toolbar mToolbar;
private Context mContext;
private EventRecyclerViewAdapter mAdapter;
private int mConferenceId;
private long mConferenceId;
CompositeDisposable mDisposable = new CompositeDisposable();
private LinearLayoutManager layoutManager;
public static EventsFragment newInstance(int conferenceId, int columnCount) {
public static EventsFragment newInstance(long conferenceId, int columnCount) {
EventsFragment fragment = new EventsFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
args.putInt(ARG_CONFERENCE, conferenceId);
args.putLong(ARG_CONFERENCE, conferenceId);
fragment.setArguments(args);
return fragment;
}
@ -66,7 +66,7 @@ public class EventsFragment extends ChaosflixFragment {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
mConferenceId = getArguments().getInt(ARG_CONFERENCE);
mConferenceId = getArguments().getLong(ARG_CONFERENCE);
}
}

View file

@ -6,6 +6,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@ -44,9 +45,11 @@ import butterknife.ButterKnife;
import de.nicidienase.chaosflix.R;
import de.nicidienase.chaosflix.common.entities.recording.Event;
import de.nicidienase.chaosflix.common.entities.recording.Recording;
import io.reactivex.android.schedulers.AndroidSchedulers;
import de.nicidienase.chaosflix.common.entities.userdata.PlaybackProgress;
import io.reactivex.Flowable;
import io.reactivex.disposables.CompositeDisposable;
public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.PlayerStateChangeListener{
public class ExoPlayerFragment extends Fragment implements MyListener.PlayerStateChangeListener {
private static final String TAG = ExoPlayerFragment.class.getSimpleName();
public static final String PLAYBACK_STATE = "playback_state";
private static final String ARG_EVENT = "event";
@ -54,6 +57,7 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
private OnMediaPlayerInteractionListener mListener;
private final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private CompositeDisposable disposable = new CompositeDisposable();
@BindView(R.id.video_view)
SimpleExoPlayerView videoView;
@ -80,8 +84,8 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
public static ExoPlayerFragment newInstance(Event event, Recording recording) {
ExoPlayerFragment fragment = new ExoPlayerFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_EVENT,event);
args.putParcelable(ARG_RECORDING,recording);
args.putParcelable(ARG_EVENT, event);
args.putParcelable(ARG_RECORDING, recording);
fragment.setArguments(args);
return fragment;
}
@ -93,8 +97,8 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
mEvent = getArguments().getParcelable(ARG_EVENT);
mRecording = getArguments().getParcelable(ARG_RECORDING);
}
if(savedInstanceState != null){
mPlaybackState = savedInstanceState.getBoolean(PLAYBACK_STATE,true);
if (savedInstanceState != null) {
mPlaybackState = savedInstanceState.getBoolean(PLAYBACK_STATE, true);
}
}
@ -107,17 +111,17 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this,view);
if(titleText != null)
ButterKnife.bind(this, view);
if (titleText != null)
titleText.setText(mEvent.getTitle());
if(subtitleText != null)
if (subtitleText != null)
subtitleText.setText(mEvent.getSubtitle());
if(exoPlayer == null){
if (exoPlayer == null) {
exoPlayer = setupPlayer();
} else {
exoPlayer = exoPlayer;
Log.d(TAG,"Player already set up.");
Log.d(TAG, "Player already set up.");
}
}
@ -125,15 +129,14 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
@Override
public void onResume() {
super.onResume();
if(exoPlayer != null){
if (exoPlayer != null) {
exoPlayer.setPlayWhenReady(mPlaybackState);
// getViewModel().getPlaybackProgress(mEvent.getApiID())
// .observe(this,
// playbackProgress -> {
// if(playbackProgress != null) {
// exoPlayer.seekTo(playbackProgress.getProgress());
// }
// });
disposable.add(mListener.getPlaybackProgress(mEvent.getApiID())
.subscribe(playbackProgress -> {
if (playbackProgress != null) {
exoPlayer.seekTo(playbackProgress.getProgress());
}
}));
videoView.setPlayer(exoPlayer);
}
}
@ -148,10 +151,11 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
@Override
public void onPause() {
super.onPause();
if(exoPlayer != null){
getViewModel().setPlaybackProgress(mEvent.getApiID(), exoPlayer.getCurrentPosition());
if (exoPlayer != null) {
mListener.setPlaybackProgress(mEvent.getApiID(), exoPlayer.getCurrentPosition());
exoPlayer.setPlayWhenReady(false);
}
disposable.clear();
}
@Override
@ -164,13 +168,13 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(exoPlayer != null){
if (exoPlayer != null) {
outState.putBoolean(PLAYBACK_STATE, exoPlayer.getPlayWhenReady());
}
}
private SimpleExoPlayer setupPlayer(){
Log.d(TAG,"Setting up Player.");
private SimpleExoPlayer setupPlayer() {
Log.d(TAG, "Setting up Player.");
videoView.setKeepScreenOn(true);
mUserAgent = Util.getUserAgent(getContext(), getResources().getString(R.string.app_name));
@ -190,7 +194,7 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
exoPlayer.setPlayWhenReady(mPlaybackState);
exoPlayer.prepare(buildMediaSource(Uri.parse(mRecording.getRecordingUrl()),""));
exoPlayer.prepare(buildMediaSource(Uri.parse(mRecording.getRecordingUrl()), ""));
return exoPlayer;
}
@ -213,14 +217,14 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
@Override
public void notifyLoadingStart() {
if(mProgressBar != null){
if (mProgressBar != null) {
mProgressBar.setVisibility(View.VISIBLE);
}
}
@Override
public void notifyLoadingFinished() {
if(mProgressBar != null){
if (mProgressBar != null) {
mProgressBar.setVisibility(View.INVISIBLE);
}
}
@ -231,6 +235,9 @@ public class ExoPlayerFragment extends ChaosflixFragment implements MyListener.P
}
public interface OnMediaPlayerInteractionListener {
Flowable<PlaybackProgress> getPlaybackProgress(long apiId);
void setPlaybackProgress(long apiId, long progress);
}
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {

View file

@ -0,0 +1,67 @@
package de.nicidienase.chaosflix.touch.viewmodels
import android.arch.lifecycle.ViewModel
import android.util.Log
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
import de.nicidienase.chaosflix.common.entities.userdata.PlaybackProgress
import de.nicidienase.chaosflix.common.entities.userdata.WatchlistItem
import de.nicidienase.chaosflix.common.entities.recording.Conference
import de.nicidienase.chaosflix.common.entities.recording.ConferencesWrapper
import de.nicidienase.chaosflix.common.entities.recording.Event
import de.nicidienase.chaosflix.common.entities.recording.Recording
import de.nicidienase.chaosflix.common.entities.streaming.LiveConference
import de.nicidienase.chaosflix.common.network.RecordingService
import de.nicidienase.chaosflix.common.network.StreamingService
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
/**
* Created by felix on 12.10.17.
*/
class BrowseViewModel(
val database: ChaosflixDatabase,
val recordingApi: RecordingService,
val streamingApi: StreamingService
) : ViewModel(){
fun getConferencesWrapper(): Observable<ConferencesWrapper>
= recordingApi.getConferences().subscribeOn(Schedulers.io())
fun getConferencesByGroup(group: String): Observable<MutableList<Conference>>
= recordingApi.getConferences().map { t: ConferencesWrapper -> t.getListForTag(group) }
fun getConference(mConferenceId: Long): Observable<Conference>
= recordingApi.getConference(mConferenceId).subscribeOn(Schedulers.io())
fun getEvent(apiID: Long): Observable<Event>
= recordingApi.getEvent(apiID).subscribeOn(Schedulers.io())
fun getRecording(id: Long): Observable<Recording>
= recordingApi.getRecording(id).subscribeOn(Schedulers.io())
fun getStreamingConferences(): Observable<List<LiveConference>>
= streamingApi.getStreamingConferences().subscribeOn(Schedulers.io())
fun createBookmark(apiId: Long) {
database.watchlistItemDao().getItemForEvent(apiId)
.subscribe { watchlistItem: WatchlistItem? ->
if (watchlistItem == null) {
database.watchlistItemDao()
.saveItem(WatchlistItem(apiId, apiId))
}
}
}
fun getBookmark(apiId: Long): Flowable<WatchlistItem> {
return database.watchlistItemDao().getItemForEvent(apiId)
}
fun removeBookmark(apiID: Long) {
getBookmark(apiID).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe { watchlistItem -> database.watchlistItemDao().deleteItem(watchlistItem) }
}
}

View file

@ -0,0 +1,30 @@
package de.nicidienase.chaosflix.touch.viewmodels
import android.arch.lifecycle.ViewModel
import de.nicidienase.chaosflix.common.entities.ChaosflixDatabase
import de.nicidienase.chaosflix.common.entities.recording.Event
import de.nicidienase.chaosflix.common.entities.recording.Recording
import de.nicidienase.chaosflix.common.entities.userdata.PlaybackProgress
import de.nicidienase.chaosflix.common.network.RecordingService
import de.nicidienase.chaosflix.common.network.StreamingService
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
internal class PlayerViewModel(val database: ChaosflixDatabase,
val recordingApi: RecordingService,
val streamingApi: StreamingService) : ViewModel() {
fun getRecording(id: Long): Observable<Recording> = recordingApi.getRecording(id)
fun getEvent(id: Long): Observable<Event> = recordingApi.getEvent(id)
fun getPlaybackProgress(apiID: Long): Flowable<PlaybackProgress>
= database.playbackProgressDao().getProgressForEvent(apiID)
fun setPlaybackProgress(apiId: Long, progress: Long){
Single.fromCallable {
database.playbackProgressDao().saveProgress(PlaybackProgress(apiId, progress))
}.subscribeOn(Schedulers.io()).subscribe()
}
}

View file

@ -105,8 +105,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/details_text_margin"
android:layout_marginRight="@dimen/details_text_margin"
android:layout_marginLeft="@dimen/details_text_margin"
android:text="@{event.speakerString}"/>
android:layout_marginLeft="@dimen/details_text_margin"/>
<!--android:text="@{event.speakerString}"/>-->
<TextView
android:id="@+id/description_text"
@ -115,8 +115,8 @@
android:layout_marginTop="@dimen/details_text_margin"
android:layout_marginRight="@dimen/details_text_margin"
android:layout_marginLeft="@dimen/details_text_margin"
android:layout_marginBottom="@dimen/details_text_margin"
android:text="@{event.extendedDescription}"/>
android:layout_marginBottom="@dimen/details_text_margin"/>
<!--android:text="@{event.extendedDescription}"/>-->
<!--TODO Add list of related or other videos-->
</LinearLayout>