commit
92aca3f84f
@ -6,7 +6,8 @@
|
|||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.githubusercontent.com/sschueller/peertube-android/master/Screenshot.png" alt="screenshot" />
|
<img src="https://raw.githubusercontent.com/sschueller/peertube-android/develop/Screenshot2.png" alt="screenshot" />
|
||||||
|
<img src="https://raw.githubusercontent.com/sschueller/peertube-android/develop/Screenshot1.png" alt="screenshot" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@ -15,6 +16,7 @@
|
|||||||
- [X] Trending Videos
|
- [X] Trending Videos
|
||||||
- [X] Endless scrolling
|
- [X] Endless scrolling
|
||||||
- [X] Pull to refresh
|
- [X] Pull to refresh
|
||||||
|
- [X] Very Basic Torrent playback
|
||||||
- [ ] Video Playback via WebRTC
|
- [ ] Video Playback via WebRTC
|
||||||
- [ ] Pick Server
|
- [ ] Pick Server
|
||||||
- [ ] Login
|
- [ ] Login
|
||||||
|
BIN
Screenshot.png
BIN
Screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 628 KiB |
BIN
Screenshot1.png
Normal file
BIN
Screenshot1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
BIN
Screenshot2.png
Normal file
BIN
Screenshot2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 272 KiB |
@ -38,11 +38,15 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.google.code.gson:gson:2.8.2'
|
implementation 'com.google.code.gson:gson:2.8.2'
|
||||||
|
|
||||||
implementation 'org.webrtc:google-webrtc:1.0.+'
|
// implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||||
implementation 'com.android.support:design:27.1.0'
|
implementation 'com.android.support:design:27.1.0'
|
||||||
|
|
||||||
implementation 'com.blackboardtheory:android-iconify-fontawesome:3.0.1-SNAPSHOT'
|
implementation 'com.blackboardtheory:android-iconify-fontawesome:3.0.1-SNAPSHOT'
|
||||||
|
|
||||||
|
implementation 'com.github.TorrentStream:TorrentStream-Android:2.5.0'
|
||||||
|
implementation 'com.google.android.exoplayer:exoplayer:2.7.0'
|
||||||
|
// implementation "com.github.TorrentStream:TorrentStreamServer-Android:1.0.1"
|
||||||
|
// implementation 'com.devbrackets.android:exomedia:4.1.0'
|
||||||
|
|
||||||
implementation 'com.android.support:support-v4:27.1.0'
|
implementation 'com.android.support:support-v4:27.1.0'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
<uses-permission android:name="android.permission.READ_PROFILE" />
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -25,12 +26,14 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.LoginActivity"
|
android:name=".activity.LoginActivity"
|
||||||
android:label="@string/title_activity_login"></activity>
|
android:label="@string/title_activity_login" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.VideoPlayActivity"
|
android:name=".activity.TorrentVideoPlayActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:label="@string/title_activity_torrent_video_play"
|
||||||
android:label="@string/title_activity_vide_play"
|
android:theme="@style/AppTheme" />
|
||||||
android:theme="@style/FullscreenTheme"></activity>
|
<activity
|
||||||
|
android:name=".activity.SettingsActivity"
|
||||||
|
android:label="@string/title_activity_settings" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,109 @@
|
|||||||
|
package net.schueller.peertube.activity;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.support.annotation.LayoutRes;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.AppCompatDelegate;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
|
||||||
|
* to be used with AppCompat.
|
||||||
|
*/
|
||||||
|
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
|
||||||
|
|
||||||
|
private AppCompatDelegate mDelegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
getDelegate().installViewFactory();
|
||||||
|
getDelegate().onCreate(savedInstanceState);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
getDelegate().onPostCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionBar getSupportActionBar() {
|
||||||
|
return getDelegate().getSupportActionBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportActionBar(@Nullable Toolbar toolbar) {
|
||||||
|
getDelegate().setSupportActionBar(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MenuInflater getMenuInflater() {
|
||||||
|
return getDelegate().getMenuInflater();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(@LayoutRes int layoutResID) {
|
||||||
|
getDelegate().setContentView(layoutResID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(View view) {
|
||||||
|
getDelegate().setContentView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(View view, ViewGroup.LayoutParams params) {
|
||||||
|
getDelegate().setContentView(view, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContentView(View view, ViewGroup.LayoutParams params) {
|
||||||
|
getDelegate().addContentView(view, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostResume() {
|
||||||
|
super.onPostResume();
|
||||||
|
getDelegate().onPostResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTitleChanged(CharSequence title, int color) {
|
||||||
|
super.onTitleChanged(title, color);
|
||||||
|
getDelegate().setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
getDelegate().onConfigurationChanged(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
getDelegate().onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
getDelegate().onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateOptionsMenu() {
|
||||||
|
getDelegate().invalidateOptionsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AppCompatDelegate getDelegate() {
|
||||||
|
if (mDelegate == null) {
|
||||||
|
mDelegate = AppCompatDelegate.create(this, null);
|
||||||
|
}
|
||||||
|
return mDelegate;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package net.schueller.peertube.activity;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
|
||||||
|
import net.schueller.peertube.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
this.finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A preference value change listener that updates the preference's summary
|
||||||
|
* to reflect its new value.
|
||||||
|
*/
|
||||||
|
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = (preference, value) -> {
|
||||||
|
String stringValue = value.toString();
|
||||||
|
|
||||||
|
preference.setSummary(stringValue);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to determine if the device has an extra-large screen. For
|
||||||
|
* example, 10" tablets are extra-large.
|
||||||
|
*/
|
||||||
|
private static boolean isXLargeTablet(Context context) {
|
||||||
|
return (context.getResources().getConfiguration().screenLayout
|
||||||
|
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a preference's summary to its value. More specifically, when the
|
||||||
|
* preference's value is changed, its summary (line of text below the
|
||||||
|
* preference title) is updated to reflect the value. The summary is also
|
||||||
|
* immediately updated upon calling this method. The exact display format is
|
||||||
|
* dependent on the type of preference.
|
||||||
|
*
|
||||||
|
* @see #sBindPreferenceSummaryToValueListener
|
||||||
|
*/
|
||||||
|
private static void bindPreferenceSummaryToValue(Preference preference) {
|
||||||
|
// Set the listener to watch for value changes.
|
||||||
|
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
|
||||||
|
|
||||||
|
// Trigger the listener immediately with the preference's
|
||||||
|
// current value.
|
||||||
|
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
||||||
|
PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(preference.getContext())
|
||||||
|
.getString(preference.getKey(), ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setupActionBar();
|
||||||
|
getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the {@link android.app.ActionBar}, if the API is available.
|
||||||
|
*/
|
||||||
|
private void setupActionBar() {
|
||||||
|
ActionBar actionBar = getSupportActionBar();
|
||||||
|
if (actionBar != null) {
|
||||||
|
// Show the Up button in the action bar.
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onIsMultiPane() {
|
||||||
|
return isXLargeTablet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public void onBuildHeaders(List<Header> target) {
|
||||||
|
//loadHeadersFromResource(R.xml.pref_headers, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method stops fragment injection in malicious applications.
|
||||||
|
* Make sure to deny any unknown fragments here.
|
||||||
|
*/
|
||||||
|
protected boolean isValidFragment(String fragmentName) {
|
||||||
|
return PreferenceFragment.class.getName().equals(fragmentName)
|
||||||
|
|| GeneralPreferenceFragment.class.getName().equals(fragmentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment shows general preferences only. It is used when the
|
||||||
|
* activity is showing a two-pane mainmenu UI.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public static class GeneralPreferenceFragment extends PreferenceFragment {
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(R.xml.pref_general);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
||||||
|
// to their values. When their values change, their summaries are
|
||||||
|
// updated to reflect the new value, per the Android Design
|
||||||
|
// guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("pref_api_base"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
startActivity(new Intent(getActivity(), SettingsActivity.class));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
package net.schueller.peertube.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.github.se_bastiaan.torrentstream.StreamStatus;
|
||||||
|
import com.github.se_bastiaan.torrentstream.Torrent;
|
||||||
|
import com.github.se_bastiaan.torrentstream.TorrentOptions;
|
||||||
|
import com.github.se_bastiaan.torrentstream.TorrentStream;
|
||||||
|
import com.github.se_bastiaan.torrentstream.listeners.TorrentListener;
|
||||||
|
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||||
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||||
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
|
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||||
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
|
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
import net.schueller.peertube.R;
|
||||||
|
import net.schueller.peertube.helper.APIUrlHelper;
|
||||||
|
import net.schueller.peertube.helper.MetaDataHelper;
|
||||||
|
import net.schueller.peertube.model.Video;
|
||||||
|
|
||||||
|
import net.schueller.peertube.network.GetVideoDataService;
|
||||||
|
import net.schueller.peertube.network.RetrofitInstance;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class TorrentVideoPlayActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "TorrentVideoPlayActivity";
|
||||||
|
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
private SimpleExoPlayer player;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_torrent_video_play);
|
||||||
|
|
||||||
|
// get video ID
|
||||||
|
Intent intent = getIntent();
|
||||||
|
String videoID = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
|
||||||
|
Log.v(TAG, "click: " + videoID);
|
||||||
|
|
||||||
|
progressBar = findViewById(R.id.progress);
|
||||||
|
progressBar.setMax(100);
|
||||||
|
|
||||||
|
PlayerView videoView = findViewById(R.id.video_view);
|
||||||
|
|
||||||
|
// 1. Create a default TrackSelector
|
||||||
|
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||||
|
TrackSelection.Factory videoTrackSelectionFactory =
|
||||||
|
new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||||
|
TrackSelector trackSelector =
|
||||||
|
new DefaultTrackSelector(videoTrackSelectionFactory);
|
||||||
|
|
||||||
|
// 2. Create the player
|
||||||
|
player = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), trackSelector);
|
||||||
|
videoView.setPlayer(player);
|
||||||
|
|
||||||
|
|
||||||
|
TorrentOptions torrentOptions = new TorrentOptions.Builder()
|
||||||
|
.saveLocation(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS))
|
||||||
|
.removeFilesAfterStop(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TorrentStream torrentStream = TorrentStream.init(torrentOptions);
|
||||||
|
|
||||||
|
torrentStream.addListener(new TorrentListener() {
|
||||||
|
@Override
|
||||||
|
public void onStreamReady(Torrent torrent) {
|
||||||
|
Log.d(TAG, "Ready");
|
||||||
|
|
||||||
|
setupVideoView(torrent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStreamProgress(Torrent torrent, StreamStatus streamStatus) {
|
||||||
|
if(streamStatus.bufferProgress <= 100 && progressBar.getProgress() < 100 && progressBar.getProgress() != streamStatus.bufferProgress) {
|
||||||
|
//Log.d(TAG, "Progress: " + streamStatus.bufferProgress);
|
||||||
|
progressBar.setProgress(streamStatus.bufferProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStreamStopped() {
|
||||||
|
Log.d(TAG, "Stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStreamPrepared(Torrent torrent) {
|
||||||
|
Log.d(TAG, "Prepared");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStreamStarted(Torrent torrent) {
|
||||||
|
Log.d(TAG, "Started");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStreamError(Torrent torrent, Exception e) {
|
||||||
|
Log.d(TAG, "Error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// get video details from api
|
||||||
|
String apiBaseURL = APIUrlHelper.getUrl(this);
|
||||||
|
GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL + "/api/v1/").create(GetVideoDataService.class);
|
||||||
|
|
||||||
|
Call<Video> call = service.getVideoData(videoID);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<Video>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<Video> call, @NonNull Response<Video> response) {
|
||||||
|
|
||||||
|
// Toast.makeText(TorrentVideoPlayActivity.this, response.body().getDescription(), Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
String streamUrl = null;
|
||||||
|
|
||||||
|
TextView videoName = findViewById(R.id.name);
|
||||||
|
TextView videoDescription = findViewById(R.id.description);
|
||||||
|
TextView videoMeta = findViewById(R.id.videoMeta);
|
||||||
|
|
||||||
|
try {
|
||||||
|
streamUrl = response.body().getFiles().get(0).getTorrentUrl();
|
||||||
|
|
||||||
|
videoName.setText(response.body().getName());
|
||||||
|
videoDescription.setText(response.body().getDescription());
|
||||||
|
|
||||||
|
videoMeta.setText(
|
||||||
|
MetaDataHelper.getMetaString(
|
||||||
|
response.body().getCreatedAt(),
|
||||||
|
response.body().getViews(),
|
||||||
|
getBaseContext()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
e.getStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.v(TAG, streamUrl);
|
||||||
|
|
||||||
|
torrentStream.startStream(streamUrl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<Video> call, @NonNull Throwable t) {
|
||||||
|
Log.wtf(TAG, t.fillInStackTrace());
|
||||||
|
Toast.makeText(TorrentVideoPlayActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupVideoView(Torrent torrent) {
|
||||||
|
|
||||||
|
Log.d(TAG, "Play Video");
|
||||||
|
|
||||||
|
// Produces DataSource instances through which media data is loaded.
|
||||||
|
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getApplicationContext(),
|
||||||
|
Util.getUserAgent(getApplicationContext(), "PeerTube"), null);
|
||||||
|
|
||||||
|
// This is the MediaSource representing the media to be played.
|
||||||
|
MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
|
||||||
|
.createMediaSource(Uri.fromFile(torrent.getVideoFile()));
|
||||||
|
|
||||||
|
// Auto play
|
||||||
|
player.setPlayWhenReady(true);
|
||||||
|
|
||||||
|
// Prepare the player with the source.
|
||||||
|
player.prepare(videoSource);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
player.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
player.setPlayWhenReady(true);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package net.schueller.peertube.activity;
|
package net.schueller.peertube.activity;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.BottomNavigationView;
|
import android.support.design.widget.BottomNavigationView;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -30,6 +33,8 @@ import com.joanzapata.iconify.fonts.FontAwesomeModule;
|
|||||||
|
|
||||||
import net.schueller.peertube.R;
|
import net.schueller.peertube.R;
|
||||||
import net.schueller.peertube.adapter.VideoAdapter;
|
import net.schueller.peertube.adapter.VideoAdapter;
|
||||||
|
import net.schueller.peertube.helper.APIUrlHelper;
|
||||||
|
import net.schueller.peertube.helper.BottomNavigationViewHelper;
|
||||||
import net.schueller.peertube.model.VideoList;
|
import net.schueller.peertube.model.VideoList;
|
||||||
import net.schueller.peertube.network.GetVideoDataService;
|
import net.schueller.peertube.network.GetVideoDataService;
|
||||||
import net.schueller.peertube.network.RetrofitInstance;
|
import net.schueller.peertube.network.RetrofitInstance;
|
||||||
@ -83,7 +88,15 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
return true;
|
return true;
|
||||||
case R.id.navigation_subscriptions:
|
case R.id.navigation_subscriptions:
|
||||||
Log.v(TAG, "navigation_subscriptions");
|
Log.v(TAG, "navigation_subscriptions");
|
||||||
return true;
|
Toast.makeText(VideoListActivity.this, "Subscriptions Not Implemented", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case R.id.navigation_account:
|
||||||
|
Log.v(TAG, "navigation_account");
|
||||||
|
Toast.makeText(VideoListActivity.this, "Account Not Implemented", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -113,8 +126,15 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
new IconDrawable(this, FontAwesomeIcons.fa_fire));
|
new IconDrawable(this, FontAwesomeIcons.fa_fire));
|
||||||
navMenu.findItem(R.id.navigation_subscriptions).setIcon(
|
navMenu.findItem(R.id.navigation_subscriptions).setIcon(
|
||||||
new IconDrawable(this, FontAwesomeIcons.fa_folder));
|
new IconDrawable(this, FontAwesomeIcons.fa_folder));
|
||||||
|
navMenu.findItem(R.id.navigation_account).setIcon(
|
||||||
|
new IconDrawable(this, FontAwesomeIcons.fa_user_circle));
|
||||||
|
|
||||||
|
BottomNavigationViewHelper.removeShiftMode(navigation);
|
||||||
|
|
||||||
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
|
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
|
||||||
|
|
||||||
|
|
||||||
|
// load Video List
|
||||||
createList();
|
createList();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -125,8 +145,8 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
inflater.inflate(R.menu.menu_main, menu);
|
inflater.inflate(R.menu.menu_main, menu);
|
||||||
|
|
||||||
// Set an icon in the ActionBar
|
// Set an icon in the ActionBar
|
||||||
menu.findItem(R.id.action_user).setIcon(
|
menu.findItem(R.id.action_settings).setIcon(
|
||||||
new IconDrawable(this, FontAwesomeIcons.fa_user_o)
|
new IconDrawable(this, FontAwesomeIcons.fa_cog)
|
||||||
.colorRes(R.color.cardview_light_background)
|
.colorRes(R.color.cardview_light_background)
|
||||||
.actionBarSize());
|
.actionBarSize());
|
||||||
|
|
||||||
@ -142,9 +162,9 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
// action with ID action_refresh was selected
|
// action with ID action_refresh was selected
|
||||||
case R.id.action_user:
|
case R.id.action_settings:
|
||||||
// Toast.makeText(this, "Login Selected", Toast.LENGTH_SHORT).show();
|
// Toast.makeText(this, "Login Selected", Toast.LENGTH_SHORT).show();
|
||||||
Intent intent = new Intent(this, LoginActivity.class);
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
this.startActivity(intent);
|
this.startActivity(intent);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -203,13 +223,11 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);
|
String apiBaseURL = APIUrlHelper.getUrl(this);
|
||||||
String defaultApiURL = getResources().getString(R.string.api_base_url);
|
|
||||||
String apiURL = sharedPref.getString(getString(R.string.api_url_key_key), defaultApiURL);
|
|
||||||
|
|
||||||
GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiURL).create(GetVideoDataService.class);
|
GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL + "/api/v1/").create(GetVideoDataService.class);
|
||||||
|
|
||||||
Call<VideoList> call = service.getVideoData(start, count, sort);
|
Call<VideoList> call = service.getVideosData(start, count, sort);
|
||||||
|
|
||||||
/*Log the URL called*/
|
/*Log the URL called*/
|
||||||
Log.d("URL Called", call.request().url() + "");
|
Log.d("URL Called", call.request().url() + "");
|
||||||
@ -254,4 +272,13 @@ public class VideoListActivity extends AppCompatActivity {
|
|||||||
Log.e("SecurityException", "Google Play Services not available.");
|
Log.e("SecurityException", "Google Play Services not available.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,176 +0,0 @@
|
|||||||
package net.schueller.peertube.activity;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.support.v7.app.ActionBar;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import net.schueller.peertube.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An example full-screen activity that shows and hides the system UI (i.e.
|
|
||||||
* status bar and navigation/system bar) with user interaction.
|
|
||||||
*/
|
|
||||||
public class VideoPlayActivity extends AppCompatActivity {
|
|
||||||
/**
|
|
||||||
* Whether or not the system UI should be auto-hidden after
|
|
||||||
* {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
|
|
||||||
*/
|
|
||||||
private static final boolean AUTO_HIDE = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
|
|
||||||
* user interaction before hiding the system UI.
|
|
||||||
*/
|
|
||||||
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some older devices needs a small delay between UI widget updates
|
|
||||||
* and a change of the status and navigation bar.
|
|
||||||
*/
|
|
||||||
private static final int UI_ANIMATION_DELAY = 300;
|
|
||||||
private final Handler mHideHandler = new Handler();
|
|
||||||
private View mContentView;
|
|
||||||
private final Runnable mHidePart2Runnable = new Runnable() {
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Delayed removal of status and navigation bar
|
|
||||||
|
|
||||||
// Note that some of these constants are new as of API 16 (Jelly Bean)
|
|
||||||
// and API 19 (KitKat). It is safe to use them, as they are inlined
|
|
||||||
// at compile-time and do nothing on earlier devices.
|
|
||||||
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
|
|
||||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
||||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
||||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private View mControlsView;
|
|
||||||
private final Runnable mShowPart2Runnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Delayed display of UI elements
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
|
||||||
if (actionBar != null) {
|
|
||||||
actionBar.show();
|
|
||||||
}
|
|
||||||
mControlsView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private boolean mVisible;
|
|
||||||
private final Runnable mHideRunnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Touch listener to use for in-layout UI controls to delay hiding the
|
|
||||||
* system UI. This is to prevent the jarring behavior of controls going away
|
|
||||||
* while interacting with activity UI.
|
|
||||||
*/
|
|
||||||
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
|
||||||
if (AUTO_HIDE) {
|
|
||||||
delayedHide(AUTO_HIDE_DELAY_MILLIS);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_vide_play);
|
|
||||||
|
|
||||||
// get video ID
|
|
||||||
Intent intent = getIntent();
|
|
||||||
String videoID = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
|
|
||||||
|
|
||||||
Log.v("VideoPlayActivity", "click: " + videoID);
|
|
||||||
|
|
||||||
mVisible = true;
|
|
||||||
mControlsView = findViewById(R.id.fullscreen_content_controls);
|
|
||||||
mContentView = findViewById(R.id.fullscreen_content);
|
|
||||||
|
|
||||||
TextView textView = findViewById(R.id.fullscreen_content);
|
|
||||||
textView.setText(videoID);
|
|
||||||
|
|
||||||
// Set up the user interaction to manually show or hide the system UI.
|
|
||||||
mContentView.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
toggle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upon interacting with UI controls, delay any scheduled hide()
|
|
||||||
// operations to prevent the jarring behavior of controls going away
|
|
||||||
// while interacting with the UI.
|
|
||||||
findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostCreate(Bundle savedInstanceState) {
|
|
||||||
super.onPostCreate(savedInstanceState);
|
|
||||||
|
|
||||||
// Trigger the initial hide() shortly after the activity has been
|
|
||||||
// created, to briefly hint to the user that UI controls
|
|
||||||
// are available.
|
|
||||||
delayedHide(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void toggle() {
|
|
||||||
if (mVisible) {
|
|
||||||
hide();
|
|
||||||
} else {
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hide() {
|
|
||||||
// Hide UI first
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
|
||||||
if (actionBar != null) {
|
|
||||||
actionBar.hide();
|
|
||||||
}
|
|
||||||
mControlsView.setVisibility(View.GONE);
|
|
||||||
mVisible = false;
|
|
||||||
|
|
||||||
// Schedule a runnable to remove the status and navigation bar after a delay
|
|
||||||
mHideHandler.removeCallbacks(mShowPart2Runnable);
|
|
||||||
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private void show() {
|
|
||||||
// Show the system bar
|
|
||||||
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
|
||||||
mVisible = true;
|
|
||||||
|
|
||||||
// Schedule a runnable to display UI elements after a delay
|
|
||||||
mHideHandler.removeCallbacks(mHidePart2Runnable);
|
|
||||||
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a call to hide() in delay milliseconds, canceling any
|
|
||||||
* previously scheduled calls.
|
|
||||||
*/
|
|
||||||
private void delayedHide(int delayMillis) {
|
|
||||||
mHideHandler.removeCallbacks(mHideRunnable);
|
|
||||||
mHideHandler.postDelayed(mHideRunnable, delayMillis);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,9 +2,11 @@ package net.schueller.peertube.adapter;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.text.format.DateUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -14,7 +16,9 @@ import android.widget.TextView;
|
|||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
import net.schueller.peertube.R;
|
import net.schueller.peertube.R;
|
||||||
import net.schueller.peertube.activity.VideoPlayActivity;
|
import net.schueller.peertube.activity.TorrentVideoPlayActivity;
|
||||||
|
import net.schueller.peertube.helper.APIUrlHelper;
|
||||||
|
import net.schueller.peertube.helper.MetaDataHelper;
|
||||||
import net.schueller.peertube.model.Video;
|
import net.schueller.peertube.model.Video;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -26,6 +30,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
|
|
||||||
private ArrayList<Video> videoList;
|
private ArrayList<Video> videoList;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
private String apiBaseURL;
|
||||||
|
|
||||||
public VideoAdapter(ArrayList<Video> videoList, Context context) {
|
public VideoAdapter(ArrayList<Video> videoList, Context context) {
|
||||||
this.videoList = videoList;
|
this.videoList = videoList;
|
||||||
@ -37,6 +42,9 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public VideoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||||
View view = layoutInflater.inflate(R.layout.row_video, parent, false);
|
View view = layoutInflater.inflate(R.layout.row_video, parent, false);
|
||||||
|
|
||||||
|
apiBaseURL = APIUrlHelper.getUrl(context);
|
||||||
|
|
||||||
return new VideoViewHolder(view);
|
return new VideoViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +52,32 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) {
|
||||||
|
|
||||||
Picasso.with(this.context)
|
Picasso.with(this.context)
|
||||||
.load("https://troll.tv" + videoList.get(position).getPreviewPath())
|
.load(apiBaseURL + videoList.get(position).getPreviewPath())
|
||||||
.into(holder.thumb);
|
.into(holder.thumb);
|
||||||
|
|
||||||
holder.name.setText(videoList.get(position).getName());
|
holder.name.setText(videoList.get(position).getName());
|
||||||
holder.videoMeta.setText(videoList.get(position).getAccountName()
|
|
||||||
.concat("@")
|
// set age and view count
|
||||||
.concat(videoList.get(position).getServerHost()).concat(" - ")
|
holder.videoMeta.setText(
|
||||||
.concat(videoList.get(position).getViews()+" Views"));
|
MetaDataHelper.getMetaString(videoList.get(position).getCreatedAt(),
|
||||||
|
videoList.get(position).getViews(),
|
||||||
|
context
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// set owner
|
||||||
|
holder.videoOwner.setText(
|
||||||
|
MetaDataHelper.getOwnerString(videoList.get(position).getAccountName(),
|
||||||
|
videoList.get(position).getServerHost(),
|
||||||
|
context
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
holder.mView.setOnClickListener(v -> {
|
holder.mView.setOnClickListener(v -> {
|
||||||
|
|
||||||
// Log.v("VideoAdapter", "click: " + videoList.get(position).getName());
|
// Log.v("VideoAdapter", "click: " + videoList.get(position).getName());
|
||||||
|
|
||||||
Intent intent = new Intent(context, VideoPlayActivity.class);
|
Intent intent = new Intent(context, TorrentVideoPlayActivity.class);
|
||||||
intent.putExtra(EXTRA_VIDEOID, videoList.get(position).getUuid());
|
intent.putExtra(EXTRA_VIDEOID, videoList.get(position).getUuid());
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
|
|
||||||
@ -82,7 +102,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
|
|
||||||
class VideoViewHolder extends RecyclerView.ViewHolder {
|
class VideoViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
TextView name, videoMeta;
|
TextView name, videoMeta, videoOwner;
|
||||||
ImageView thumb;
|
ImageView thumb;
|
||||||
View mView;
|
View mView;
|
||||||
|
|
||||||
@ -91,6 +111,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
name = itemView.findViewById(R.id.name);
|
name = itemView.findViewById(R.id.name);
|
||||||
thumb = itemView.findViewById(R.id.thumb);
|
thumb = itemView.findViewById(R.id.thumb);
|
||||||
videoMeta = itemView.findViewById(R.id.videoMeta);
|
videoMeta = itemView.findViewById(R.id.videoMeta);
|
||||||
|
videoOwner = itemView.findViewById(R.id.videoOwner);
|
||||||
mView = itemView;
|
mView = itemView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package net.schueller.peertube.helper;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import net.schueller.peertube.R;
|
||||||
|
|
||||||
|
public class APIUrlHelper{
|
||||||
|
|
||||||
|
public static String getUrl(Context context) {
|
||||||
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
return sharedPref.getString("pref_api_base", context.getResources().getString(R.string.pref_default_api_base_url));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.schueller.peertube.helper;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.support.design.internal.BottomNavigationItemView;
|
||||||
|
import android.support.design.internal.BottomNavigationMenuView;
|
||||||
|
import android.support.design.widget.BottomNavigationView;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public class BottomNavigationViewHelper {
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
public static void removeShiftMode(BottomNavigationView view) {
|
||||||
|
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
|
||||||
|
try {
|
||||||
|
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
|
||||||
|
shiftingMode.setAccessible(true);
|
||||||
|
shiftingMode.setBoolean(menuView, false);
|
||||||
|
shiftingMode.setAccessible(false);
|
||||||
|
for (int i = 0; i < menuView.getChildCount(); i++) {
|
||||||
|
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
|
||||||
|
//noinspection RestrictedApi
|
||||||
|
item.setShiftingMode(false);
|
||||||
|
// set once again checked value, so view will be updated
|
||||||
|
//noinspection RestrictedApi
|
||||||
|
item.setChecked(item.getItemData().isChecked());
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
Log.e("BottomNav", "Unable to get shift mode field", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e("BottomNav", "Unable to change value of shift mode", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package net.schueller.peertube.helper;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import net.schueller.peertube.R;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class MetaDataHelper {
|
||||||
|
|
||||||
|
public static String getMetaString(Date getCreatedAt, Integer viewCount, Context context) {
|
||||||
|
return DateUtils.
|
||||||
|
getRelativeTimeSpanString(getCreatedAt.getTime()).toString() +
|
||||||
|
context.getResources().getString(R.string.meta_data_seperator) +
|
||||||
|
viewCount + context.getResources().getString(R.string.meta_data_views);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getOwnerString(String accountName, String serverHost, Context context) {
|
||||||
|
return accountName +
|
||||||
|
context.getResources().getString(R.string.meta_data_owner_seperator) +
|
||||||
|
serverHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
114
app/src/main/java/net/schueller/peertube/model/Account.java
Normal file
114
app/src/main/java/net/schueller/peertube/model/Account.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package net.schueller.peertube.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Account {
|
||||||
|
private Integer id;
|
||||||
|
private String url;
|
||||||
|
private String uuid;
|
||||||
|
private String name;
|
||||||
|
private String host;
|
||||||
|
private Integer followingCount;
|
||||||
|
private Integer followersCount;
|
||||||
|
private Avatar avatar;
|
||||||
|
private Date createdAt;
|
||||||
|
private Date updatedAt;
|
||||||
|
private String displayName;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFollowingCount() {
|
||||||
|
return followingCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFollowingCount(Integer followingCount) {
|
||||||
|
this.followingCount = followingCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFollowersCount() {
|
||||||
|
return followersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFollowersCount(Integer followersCount) {
|
||||||
|
this.followersCount = followersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Avatar getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(Avatar avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
}
|
34
app/src/main/java/net/schueller/peertube/model/Avatar.java
Normal file
34
app/src/main/java/net/schueller/peertube/model/Avatar.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package net.schueller.peertube.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Avatar {
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
private Date createdAt;
|
||||||
|
private Date updatedAt;
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
132
app/src/main/java/net/schueller/peertube/model/Channel.java
Normal file
132
app/src/main/java/net/schueller/peertube/model/Channel.java
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package net.schueller.peertube.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Channel {
|
||||||
|
private Integer id;
|
||||||
|
private String url;
|
||||||
|
private String uuid;
|
||||||
|
private String name;
|
||||||
|
private String host;
|
||||||
|
private Integer followingCount;
|
||||||
|
private Integer followersCount;
|
||||||
|
private Avatar avatar;
|
||||||
|
private Date createdAt;
|
||||||
|
private Date updatedAt;
|
||||||
|
private String displayName;
|
||||||
|
private String description;
|
||||||
|
private String support;
|
||||||
|
private Boolean isLocal;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFollowingCount() {
|
||||||
|
return followingCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFollowingCount(Integer followingCount) {
|
||||||
|
this.followingCount = followingCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFollowersCount() {
|
||||||
|
return followersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFollowersCount(Integer followersCount) {
|
||||||
|
this.followersCount = followersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Avatar getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(Avatar avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupport() {
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupport(String support) {
|
||||||
|
this.support = support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getLocal() {
|
||||||
|
return isLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocal(Boolean local) {
|
||||||
|
isLocal = local;
|
||||||
|
}
|
||||||
|
}
|
58
app/src/main/java/net/schueller/peertube/model/File.java
Normal file
58
app/src/main/java/net/schueller/peertube/model/File.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package net.schueller.peertube.model;
|
||||||
|
|
||||||
|
public class File {
|
||||||
|
private Integer resolution;
|
||||||
|
private String resolutionLabel;
|
||||||
|
private String magnetUri;
|
||||||
|
private Integer size;
|
||||||
|
private String torrentUrl;
|
||||||
|
private String fileUrl;
|
||||||
|
|
||||||
|
public Integer getResolution() {
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResolution(Integer resolution) {
|
||||||
|
this.resolution = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResolutionLabel() {
|
||||||
|
return resolutionLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResolutionLabel(String resolutionLabel) {
|
||||||
|
this.resolutionLabel = resolutionLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMagnetUri() {
|
||||||
|
return magnetUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMagnetUri(String magnetUri) {
|
||||||
|
this.magnetUri = magnetUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(Integer size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTorrentUrl() {
|
||||||
|
return torrentUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTorrentUrl(String torrentUrl) {
|
||||||
|
this.torrentUrl = torrentUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileUrl() {
|
||||||
|
return fileUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileUrl(String fileUrl) {
|
||||||
|
this.fileUrl = fileUrl;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package net.schueller.peertube.model;
|
package net.schueller.peertube.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class Video {
|
public class Video {
|
||||||
@ -28,6 +29,18 @@ public class Video {
|
|||||||
private Date createdAt;
|
private Date createdAt;
|
||||||
private Date updatedAt;
|
private Date updatedAt;
|
||||||
|
|
||||||
|
private String privacyLabel;
|
||||||
|
private Integer privacy;
|
||||||
|
private String support;
|
||||||
|
private String descriptionPath;
|
||||||
|
|
||||||
|
private Channel channel;
|
||||||
|
private Account account;
|
||||||
|
private ArrayList tags;
|
||||||
|
|
||||||
|
private Boolean commentsEnabled;
|
||||||
|
private ArrayList<File> files;
|
||||||
|
|
||||||
public Video() {
|
public Video() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -215,4 +228,76 @@ public class Video {
|
|||||||
public void setUpdatedAt(Date updatedAt) {
|
public void setUpdatedAt(Date updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPrivacyLabel() {
|
||||||
|
return privacyLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivacyLabel(String privacyLabel) {
|
||||||
|
this.privacyLabel = privacyLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPrivacy() {
|
||||||
|
return privacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivacy(Integer privacy) {
|
||||||
|
this.privacy = privacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupport() {
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupport(String support) {
|
||||||
|
this.support = support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescriptionPath() {
|
||||||
|
return descriptionPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescriptionPath(String descriptionPath) {
|
||||||
|
this.descriptionPath = descriptionPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChannel(Channel channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccount(Account account) {
|
||||||
|
this.account = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTags(ArrayList tags) {
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getCommentsEnabled() {
|
||||||
|
return commentsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommentsEnabled(Boolean commentsEnabled) {
|
||||||
|
this.commentsEnabled = commentsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<File> getFiles() {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFiles(ArrayList<File> files) {
|
||||||
|
this.files = files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,4 @@ public class VideoList {
|
|||||||
return videoList;
|
return videoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmployeeArrayList(ArrayList<Video> videoArrayList) {
|
|
||||||
this.videoList = videoArrayList;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,16 +1,23 @@
|
|||||||
package net.schueller.peertube.network;
|
package net.schueller.peertube.network;
|
||||||
|
|
||||||
|
import net.schueller.peertube.model.Video;
|
||||||
import net.schueller.peertube.model.VideoList;
|
import net.schueller.peertube.model.VideoList;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.GET;
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.Path;
|
||||||
import retrofit2.http.Query;
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
public interface GetVideoDataService {
|
public interface GetVideoDataService {
|
||||||
@GET("videos/")
|
@GET("videos/")
|
||||||
Call<VideoList> getVideoData(
|
Call<VideoList> getVideosData(
|
||||||
@Query("start") int start,
|
@Query("start") int start,
|
||||||
@Query("count") int count,
|
@Query("count") int count,
|
||||||
@Query("sort") String sort
|
@Query("sort") String sort
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@GET("videos/{id}")
|
||||||
|
Call<Video> getVideoData(
|
||||||
|
@Path(value = "id", encoded = true) String id
|
||||||
|
);
|
||||||
}
|
}
|
@ -1,44 +0,0 @@
|
|||||||
package net.schueller.peertube.services;
|
|
||||||
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
import net.schueller.peertube.model.Video;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Retrofit;
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
import retrofit2.http.GET;
|
|
||||||
|
|
||||||
public final class RecentlyAddedVideosService {
|
|
||||||
public static final String API_URL = "https://troll.tv/api/v1";
|
|
||||||
|
|
||||||
public interface RecentlyAddedVideos {
|
|
||||||
@GET("/videos/?start=0&count=12&sort=-createdAt")
|
|
||||||
@SerializedName("data")
|
|
||||||
Call<List<Video>> videos();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String... args) throws IOException {
|
|
||||||
// Create a very simple REST adapter which points the PeerTube API.
|
|
||||||
Retrofit retrofit = new Retrofit.Builder()
|
|
||||||
.baseUrl(API_URL)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Create an instance of our GitHub API interface.
|
|
||||||
RecentlyAddedVideos recentlyAddedVideos = retrofit.create(RecentlyAddedVideos.class);
|
|
||||||
|
|
||||||
// Create a call instance for looking up Retrofit contributors.
|
|
||||||
Call<List<Video>> call = recentlyAddedVideos.videos();
|
|
||||||
|
|
||||||
// Fetch and print a list of the contributors to the library.
|
|
||||||
List<Video> videos = call.execute().body();
|
|
||||||
for (Video video : videos) {
|
|
||||||
System.out.println(video.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
9
app/src/main/res/drawable/ic_info_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_info_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_sync_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_sync_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z" />
|
||||||
|
</vector>
|
70
app/src/main/res/layout/activity_torrent_video_play.xml
Normal file
70
app/src/main/res/layout/activity_torrent_video_play.xml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="net.schueller.peertube.activity.TorrentVideoPlayActivity">
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.PlayerView
|
||||||
|
android:id="@+id/video_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="250dp"
|
||||||
|
android:background="@color/black"
|
||||||
|
|
||||||
|
app:layout_constraintDimensionRatio="H,3:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
|
||||||
|
>
|
||||||
|
|
||||||
|
</com.google.android.exoplayer2.ui.PlayerView>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/video_view"
|
||||||
|
android:background="@color/black"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/progress"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/videoMeta"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Body1" />
|
||||||
|
|
||||||
|
</android.support.v7.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
@ -1,50 +0,0 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#0099cc"
|
|
||||||
tools:context="net.schueller.peertube.activity.VideoPlayActivity">
|
|
||||||
|
|
||||||
<!-- The primary full-screen view. This can be replaced with whatever view
|
|
||||||
is needed to present your content, e.g. VideoView, SurfaceView,
|
|
||||||
TextureView, etc. -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/fullscreen_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:keepScreenOn="true"
|
|
||||||
android:text="@string/dummy_content"
|
|
||||||
android:textColor="#33b5e5"
|
|
||||||
android:textSize="50sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<!-- This FrameLayout insets its children based on system windows using
|
|
||||||
android:fitsSystemWindows. -->
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/fullscreen_content_controls"
|
|
||||||
style="?metaButtonBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|center_horizontal"
|
|
||||||
android:background="@color/black_overlay"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
tools:ignore="UselessParent">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/dummy_button"
|
|
||||||
style="?metaButtonBarButtonStyle"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/dummy_button" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
@ -47,7 +47,7 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:menu="@menu/navigation"
|
app:menu="@menu/menu_bottom"
|
||||||
android:layout_gravity="bottom" />
|
android:layout_gravity="bottom" />
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
@ -37,6 +37,14 @@
|
|||||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption"
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_marginStart="75dp"
|
||||||
|
android:id="@+id/videoOwner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
|
25
app/src/main/res/menu/menu_bottom.xml
Normal file
25
app/src/main/res/menu/menu_bottom.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_home"
|
||||||
|
android:title="@string/bottom_nav_title_home"
|
||||||
|
app:showAsAction="always|withText" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_trending"
|
||||||
|
android:title="@string/bottom_nav_title_trending"
|
||||||
|
app:showAsAction="always|withText"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_subscriptions"
|
||||||
|
android:title="@string/bottom_nav_title_subscriptions"
|
||||||
|
app:showAsAction="ifRoom|withText"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_account"
|
||||||
|
android:title="@string/bottom_nav_title_account"
|
||||||
|
app:showAsAction="ifRoom|withText"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -5,10 +5,9 @@
|
|||||||
tools:context="activity.VideoListActivity">
|
tools:context="activity.VideoListActivity">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_user"
|
android:id="@+id/action_settings"
|
||||||
android:icon="@drawable/googleg_standard_color_18"
|
|
||||||
android:orderInCategory="300"
|
android:orderInCategory="300"
|
||||||
android:title="User"
|
android:title="@string/action_bar_title_settings"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/navigation_home"
|
|
||||||
android:title="@string/title_home" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/navigation_trending"
|
|
||||||
android:title="@string/title_trending" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/navigation_subscriptions"
|
|
||||||
android:title="@string/title_subscriptions" />
|
|
||||||
|
|
||||||
</menu>
|
|
@ -7,4 +7,5 @@
|
|||||||
<color name="album_title">#4c4c4c</color>
|
<color name="album_title">#4c4c4c</color>
|
||||||
|
|
||||||
<color name="black_overlay">#66000000</color>
|
<color name="black_overlay">#66000000</color>
|
||||||
|
<color name="black">#000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
<dimen name="fab_margin">16dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">PeerTube</string>
|
<string name="app_name">PeerTube</string>
|
||||||
|
|
||||||
|
<string name="title_activity_torrent_video_play">TorrentVideoPlayActivity</string>
|
||||||
|
<string name="title_activity_settings">Settings</string>
|
||||||
<string name="title_activity_login">Sign in</string>
|
<string name="title_activity_login">Sign in</string>
|
||||||
|
|
||||||
<!-- Strings related to login -->
|
<!-- Strings related to login -->
|
||||||
@ -16,15 +19,23 @@
|
|||||||
completions."
|
completions."
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="title_home">Home</string>
|
<!-- Action bar -->
|
||||||
<string name="title_trending">Trending</string>
|
<string name="action_bar_title_settings">Settings</string>
|
||||||
<string name="title_subscriptions">Subscriptions</string>
|
|
||||||
|
|
||||||
<string name="title_activity_vide_play">VidePlayActivity</string>
|
<!-- Bottom navigation bar -->
|
||||||
<string name="dummy_button">Dummy Button</string>
|
<string name="bottom_nav_title_home">Home</string>
|
||||||
<string name="dummy_content">DUMMY\nCONTENT</string>
|
<string name="bottom_nav_title_trending">Trending</string>
|
||||||
|
<string name="bottom_nav_title_subscriptions">Subscriptions</string>
|
||||||
|
<string name="bottom_nav_title_account">Account</string>
|
||||||
|
|
||||||
<string name="api_base_url" formatted="false">https://troll.tv/api/v1/</string>
|
<!-- Strings related to Settings -->
|
||||||
<string name="api_url_key_key">api_url</string>
|
<string name="pref_default_api_base_url" formatted="false">https://troll.tv</string>
|
||||||
|
<string name="pref_title_peertube_server">PeerTube Server</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Strings related to Video meta data -->
|
||||||
|
<string name="meta_data_seperator">\u0020-\u0020</string>
|
||||||
|
<string name="meta_data_views">\u0020Views</string>
|
||||||
|
<string name="meta_data_owner_seperator">\@</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -19,4 +19,8 @@
|
|||||||
<item name="android:background">@color/black_overlay</item>
|
<item name="android:background">@color/black_overlay</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
13
app/src/main/res/xml/pref_general.xml
Normal file
13
app/src/main/res/xml/pref_general.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:capitalize="words"
|
||||||
|
android:defaultValue="@string/pref_default_api_base_url"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:key="pref_api_base"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:title="@string/pref_title_peertube_server" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
@ -20,9 +20,8 @@ allprojects {
|
|||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven {
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||||
url 'https://oss.sonatype.org/content/repositories/snapshots'
|
maven { url 'https://jitpack.io' }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user