Merge branch 'develop' into 'master'
Release See merge request sschueller/peertube!21
This commit is contained in:
commit
74bb45a3fc
@ -1,590 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.schueller.peertube.activity;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.SearchManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.provider.SearchRecentSuggestions;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
|
||||||
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
|
||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.appcompat.widget.SearchView;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.mikepenz.iconics.IconicsDrawable;
|
|
||||||
|
|
||||||
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome;
|
|
||||||
import net.schueller.peertube.R;
|
|
||||||
import net.schueller.peertube.adapter.VideoAdapter;
|
|
||||||
import net.schueller.peertube.helper.APIUrlHelper;
|
|
||||||
import net.schueller.peertube.helper.ErrorHelper;
|
|
||||||
import net.schueller.peertube.model.Video;
|
|
||||||
import net.schueller.peertube.model.VideoList;
|
|
||||||
import net.schueller.peertube.network.GetUserService;
|
|
||||||
import net.schueller.peertube.network.GetVideoDataService;
|
|
||||||
import net.schueller.peertube.network.RetrofitInstance;
|
|
||||||
import net.schueller.peertube.network.Session;
|
|
||||||
import net.schueller.peertube.provider.SearchSuggestionsProvider;
|
|
||||||
import net.schueller.peertube.service.VideoPlayerService;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
public class VideoListActivity extends CommonActivity {
|
|
||||||
|
|
||||||
private String TAG = "VideoListActivity";
|
|
||||||
|
|
||||||
public static final String EXTRA_VIDEOID = "VIDEOID";
|
|
||||||
public static final String EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST";
|
|
||||||
public static final Integer SWITCH_INSTANCE = 2;
|
|
||||||
|
|
||||||
private VideoAdapter videoAdapter;
|
|
||||||
private SwipeRefreshLayout swipeRefreshLayout;
|
|
||||||
|
|
||||||
private int currentStart = 0;
|
|
||||||
private int count = 12;
|
|
||||||
private String sort = "-createdAt";
|
|
||||||
private String filter = null;
|
|
||||||
private String searchQuery = "";
|
|
||||||
private Boolean subscriptions = false;
|
|
||||||
|
|
||||||
private TextView emptyView;
|
|
||||||
private RecyclerView recyclerView;
|
|
||||||
|
|
||||||
private boolean isLoading = false;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_video_list);
|
|
||||||
|
|
||||||
filter = null;
|
|
||||||
|
|
||||||
createBottomBarNavigation();
|
|
||||||
|
|
||||||
// Attaching the layout to the toolbar object
|
|
||||||
Toolbar toolbar = findViewById(R.id.tool_bar);
|
|
||||||
// Setting toolbar as the ActionBar with setSupportActionBar() call
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
|
|
||||||
// load Video List
|
|
||||||
createList();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
|
||||||
inflater.inflate(R.menu.menu_top_videolist, menu);
|
|
||||||
|
|
||||||
// Set an icon in the ActionBar
|
|
||||||
menu.findItem(R.id.action_account).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle));
|
|
||||||
|
|
||||||
menu.findItem(R.id.action_server_address_book).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_server));
|
|
||||||
|
|
||||||
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
|
|
||||||
|
|
||||||
searchMenuItem.setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_search));
|
|
||||||
|
|
||||||
// Get the SearchView and set the searchable configuration
|
|
||||||
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
|
|
||||||
SearchView searchView = (SearchView) searchMenuItem.getActionView();
|
|
||||||
|
|
||||||
// Assumes current activity is the searchable activity
|
|
||||||
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
|
|
||||||
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
|
|
||||||
searchView.setQueryRefinementEnabled(true);
|
|
||||||
|
|
||||||
searchMenuItem.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onLongClick(View v) {
|
|
||||||
new AlertDialog.Builder(VideoListActivity.this)
|
|
||||||
.setTitle(getString(R.string.clear_search_history))
|
|
||||||
.setMessage(getString(R.string.clear_search_history_prompt))
|
|
||||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getApplicationContext(),
|
|
||||||
SearchSuggestionsProvider.AUTHORITY,
|
|
||||||
SearchSuggestionsProvider.MODE);
|
|
||||||
suggestions.clearHistory();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.no, null)
|
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
|
||||||
.show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
searchMenuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemActionExpand(MenuItem menuItem) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemActionCollapse(MenuItem menuItem) {
|
|
||||||
searchQuery = "";
|
|
||||||
Log.d(TAG, "onMenuItemActionCollapse: ");
|
|
||||||
loadVideos(0, count, sort, filter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO, this doesn't work
|
|
||||||
searchManager.setOnDismissListener(() -> {
|
|
||||||
searchQuery = "";
|
|
||||||
Log.d(TAG, "onDismiss: ");
|
|
||||||
loadVideos(0, count, sort, filter);
|
|
||||||
});
|
|
||||||
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onSuggestionClick(int position) {
|
|
||||||
String suggestion = getSuggestion(position);
|
|
||||||
searchView.setQuery(suggestion, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSuggestion(int position) {
|
|
||||||
Cursor cursor = (Cursor) searchView.getSuggestionsAdapter().getItem(
|
|
||||||
position);
|
|
||||||
return cursor.getString(cursor
|
|
||||||
.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSuggestionSelect(int position) {
|
|
||||||
/* Required to implement */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
stopService(new Intent(this, VideoPlayerService.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (requestCode == SWITCH_INSTANCE) {
|
|
||||||
if(resultCode == RESULT_OK) {
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
// Handle action bar item clicks here. The action bar will
|
|
||||||
// automatically handle clicks on the Home/Up button, so long
|
|
||||||
// as you specify a parent activity in AndroidManifest.xml.
|
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
// action with ID action_refresh was selected
|
|
||||||
case R.id.action_search:
|
|
||||||
//Toast.makeText(this, "Search Selected", Toast.LENGTH_SHORT).show();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
case R.id.action_account:
|
|
||||||
// if (!Session.getInstance().isLoggedIn()) {
|
|
||||||
|
|
||||||
//Intent intentLogin = new Intent(this, ServerAddressBookActivity.class);
|
|
||||||
|
|
||||||
Intent intentMe = new Intent(this, MeActivity.class);
|
|
||||||
this.startActivity(intentMe);
|
|
||||||
|
|
||||||
//overridePendingTransition(R.anim.slide_in_bottom, 0);
|
|
||||||
|
|
||||||
|
|
||||||
// this.startActivity(intentLogin);
|
|
||||||
|
|
||||||
// } else {
|
|
||||||
// Intent intentMe = new Intent(this, MeActivity.class);
|
|
||||||
// this.startActivity(intentMe);
|
|
||||||
// }
|
|
||||||
return false;
|
|
||||||
case R.id.action_server_address_book:
|
|
||||||
Intent addressBookActivityIntent = new Intent(this, ServerAddressBookActivity.class);
|
|
||||||
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE);
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createList() {
|
|
||||||
recyclerView = findViewById(R.id.recyclerView);
|
|
||||||
swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
|
|
||||||
|
|
||||||
emptyView = findViewById(R.id.empty_view);
|
|
||||||
|
|
||||||
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(VideoListActivity.this);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
videoAdapter = new VideoAdapter(new ArrayList<>(), VideoListActivity.this);
|
|
||||||
recyclerView.setAdapter(videoAdapter);
|
|
||||||
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
|
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
|
||||||
@Override
|
|
||||||
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
|
||||||
super.onScrollStateChanged(recyclerView, newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
|
||||||
|
|
||||||
if (dy > 0) {
|
|
||||||
// is at end of list?
|
|
||||||
if (!recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN)) {
|
|
||||||
if (!isLoading) {
|
|
||||||
currentStart = currentStart + count;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
swipeRefreshLayout.setOnRefreshListener(() -> {
|
|
||||||
// Refresh items
|
|
||||||
if (!isLoading) {
|
|
||||||
currentStart = 0;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadVideos(int start, int count, String sort, String filter) {
|
|
||||||
|
|
||||||
isLoading = true;
|
|
||||||
|
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
String nsfw = sharedPref.getBoolean(getString(R.string.pref_show_nsfw_key), false) ? "both" : "false";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Locale locale = getResources().getConfiguration().locale;
|
|
||||||
// String country = locale.getLanguage();
|
|
||||||
//
|
|
||||||
// HashSet<String> countries = new HashSet<>(1);
|
|
||||||
// countries.add(country);
|
|
||||||
|
|
||||||
// We set this to default to null so that on initial start there are videos listed.
|
|
||||||
Set<String> languages = sharedPref.getStringSet(getString(R.string.pref_video_language_key), null);
|
|
||||||
|
|
||||||
String apiBaseURL = APIUrlHelper.getUrlWithVersion(this);
|
|
||||||
|
|
||||||
GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetVideoDataService.class);
|
|
||||||
|
|
||||||
Call<VideoList> call;
|
|
||||||
if (!searchQuery.equals("")) {
|
|
||||||
call = service.searchVideosData(start, count, sort, nsfw, searchQuery, filter, languages);
|
|
||||||
} else if (subscriptions) {
|
|
||||||
GetUserService userService = RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(GetUserService.class);
|
|
||||||
call = userService.getVideosSubscripions(start, count, sort);
|
|
||||||
} else {
|
|
||||||
call = service.getVideosData(start, count, sort, nsfw, filter, languages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Log the URL called*/
|
|
||||||
Log.d("URL Called", call.request().url() + "");
|
|
||||||
// Toast.makeText(VideoListActivity.this, "URL Called: " + call.request().url(), Toast.LENGTH_SHORT).show();
|
|
||||||
|
|
||||||
call.enqueue(new Callback<VideoList>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull Call<VideoList> call, @NonNull Response<VideoList> response) {
|
|
||||||
|
|
||||||
if (currentStart == 0) {
|
|
||||||
videoAdapter.clearData();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.body() != null) {
|
|
||||||
ArrayList<Video> videoList = response.body().getVideoArrayList();
|
|
||||||
if (videoList != null) {
|
|
||||||
videoAdapter.setData(response.body().getVideoArrayList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no results show no results message
|
|
||||||
if (currentStart == 0 && videoAdapter.getItemCount() == 0) {
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
emptyView.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading = false;
|
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull Call<VideoList> call, @NonNull Throwable t) {
|
|
||||||
Log.wtf("err", t.fillInStackTrace());
|
|
||||||
ErrorHelper.showToastFromCommunicationError( VideoListActivity.this, t );
|
|
||||||
isLoading = false;
|
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
// only check when we actually need the permission
|
|
||||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
|
||||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
|
|
||||||
sharedPref.getBoolean(getString(R.string.pref_torrent_player_key), false)) {
|
|
||||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onNewIntent(Intent intent) {
|
|
||||||
super.onNewIntent(intent);
|
|
||||||
setIntent(intent);
|
|
||||||
handleIntent(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleIntent(Intent intent) {
|
|
||||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
|
||||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
|
||||||
|
|
||||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
|
|
||||||
SearchSuggestionsProvider.AUTHORITY,
|
|
||||||
SearchSuggestionsProvider.MODE);
|
|
||||||
|
|
||||||
// Save recent searches
|
|
||||||
suggestions.saveRecentQuery(query, null);
|
|
||||||
|
|
||||||
searchQuery = query;
|
|
||||||
|
|
||||||
loadVideos(0, count, sort, filter);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSearchRequested() {
|
|
||||||
Bundle appData = new Bundle();
|
|
||||||
startSearch(null, false, appData, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void createBottomBarNavigation() {
|
|
||||||
|
|
||||||
// Get Bottom Navigation
|
|
||||||
BottomNavigationView navigation = findViewById(R.id.navigation);
|
|
||||||
|
|
||||||
// Always show text label
|
|
||||||
navigation.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
|
|
||||||
|
|
||||||
// Add Icon font
|
|
||||||
Menu navMenu = navigation.getMenu();
|
|
||||||
navMenu.findItem(R.id.navigation_overview).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_globe));
|
|
||||||
navMenu.findItem(R.id.navigation_trending).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_fire));
|
|
||||||
navMenu.findItem(R.id.navigation_recent).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_plus_circle));
|
|
||||||
navMenu.findItem(R.id.navigation_local).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_home));
|
|
||||||
navMenu.findItem(R.id.navigation_subscriptions).setIcon(
|
|
||||||
new IconicsDrawable(this, FontAwesome.Icon.faw_folder));
|
|
||||||
// navMenu.findItem(R.id.navigation_account).setIcon(
|
|
||||||
// new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle));
|
|
||||||
|
|
||||||
// Click Listener
|
|
||||||
navigation.setOnNavigationItemSelectedListener(menuItem -> {
|
|
||||||
switch (menuItem.getItemId()) {
|
|
||||||
case R.id.navigation_overview:
|
|
||||||
// TODO
|
|
||||||
if (!isLoading) {
|
|
||||||
sort = "-createdAt";
|
|
||||||
currentStart = 0;
|
|
||||||
filter = null;
|
|
||||||
subscriptions = false;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case R.id.navigation_trending:
|
|
||||||
//Log.v(TAG, "navigation_trending");
|
|
||||||
|
|
||||||
if (!isLoading) {
|
|
||||||
sort = "-trending";
|
|
||||||
currentStart = 0;
|
|
||||||
filter = null;
|
|
||||||
subscriptions = false;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case R.id.navigation_recent:
|
|
||||||
if (!isLoading) {
|
|
||||||
sort = "-createdAt";
|
|
||||||
currentStart = 0;
|
|
||||||
filter = null;
|
|
||||||
subscriptions = false;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case R.id.navigation_local:
|
|
||||||
//Log.v(TAG, "navigation_trending");
|
|
||||||
|
|
||||||
if (!isLoading) {
|
|
||||||
sort = "-publishedAt";
|
|
||||||
filter = "local";
|
|
||||||
currentStart = 0;
|
|
||||||
subscriptions = false;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case R.id.navigation_subscriptions:
|
|
||||||
//Log.v(TAG, "navigation_subscriptions");
|
|
||||||
|
|
||||||
if (!Session.getInstance().isLoggedIn()) {
|
|
||||||
// Intent intent = new Intent(this, LoginActivity.class);
|
|
||||||
// this.startActivity(intent);
|
|
||||||
Intent addressBookActivityIntent = new Intent(this, ServerAddressBookActivity.class);
|
|
||||||
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (!isLoading) {
|
|
||||||
sort = "-publishedAt";
|
|
||||||
filter = null;
|
|
||||||
currentStart = 0;
|
|
||||||
subscriptions = true;
|
|
||||||
loadVideos(currentStart, count, sort, filter);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// case R.id.navigation_account:
|
|
||||||
// //Log.v(TAG, "navigation_account");
|
|
||||||
// //Toast.makeText(VideoListActivity.this, "Account Not Implemented", Toast.LENGTH_SHORT).show();
|
|
||||||
//
|
|
||||||
// if (!Session.getInstance().isLoggedIn()) {
|
|
||||||
// Intent intent = new Intent(this, LoginActivity.class);
|
|
||||||
// this.startActivity(intent);
|
|
||||||
// } else {
|
|
||||||
// Intent intent = new Intent(this, MeActivity.class);
|
|
||||||
// this.startActivity(intent);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: on double click jump to top and reload
|
|
||||||
// navigation.setOnNavigationItemReselectedListener(menuItemReselected -> {
|
|
||||||
// switch (menuItemReselected.getItemId()) {
|
|
||||||
// case R.id.navigation_home:
|
|
||||||
// if (!isLoading) {
|
|
||||||
// sort = "-createdAt";
|
|
||||||
// currentStart = 0;
|
|
||||||
// filter = null;
|
|
||||||
// subscriptions = false;
|
|
||||||
// loadVideos(currentStart, count, sort, filter);
|
|
||||||
// }
|
|
||||||
// case R.id.navigation_trending:
|
|
||||||
// if (!isLoading) {
|
|
||||||
// sort = "-trending";
|
|
||||||
// currentStart = 0;
|
|
||||||
// filter = null;
|
|
||||||
// subscriptions = false;
|
|
||||||
// loadVideos(currentStart, count, sort, filter);
|
|
||||||
// }
|
|
||||||
// case R.id.navigation_local:
|
|
||||||
// if (!isLoading) {
|
|
||||||
// sort = "-publishedAt";
|
|
||||||
// filter = "local";
|
|
||||||
// currentStart = 0;
|
|
||||||
// subscriptions = false;
|
|
||||||
// loadVideos(currentStart, count, sort, filter);
|
|
||||||
// }
|
|
||||||
// case R.id.navigation_subscriptions:
|
|
||||||
// if (Session.getInstance().isLoggedIn()) {
|
|
||||||
// if (!isLoading) {
|
|
||||||
// sort = "-publishedAt";
|
|
||||||
// filter = null;
|
|
||||||
// currentStart = 0;
|
|
||||||
// subscriptions = true;
|
|
||||||
// loadVideos(currentStart, count, sort, filter);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package net.schueller.peertube.activity
|
||||||
|
|
||||||
|
import android.Manifest.permission
|
||||||
|
import android.R.drawable
|
||||||
|
import android.R.string
|
||||||
|
import android.app.AlertDialog.Builder
|
||||||
|
import android.app.SearchManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.SearchRecentSuggestions
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.MenuItem.OnActionExpandListener
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.appcompat.widget.SearchView.OnSuggestionListener
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.LayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
import com.google.android.material.bottomnavigation.LabelVisibilityMode
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_fire
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_folder
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_globe
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_home
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_plus_circle
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_search
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_server
|
||||||
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome.Icon.faw_user_circle
|
||||||
|
import com.mikepenz.iconics.utils.actionBar
|
||||||
|
import net.schueller.peertube.R
|
||||||
|
import net.schueller.peertube.R.id
|
||||||
|
import net.schueller.peertube.R.layout
|
||||||
|
import net.schueller.peertube.adapter.VideoAdapter
|
||||||
|
import net.schueller.peertube.helper.APIUrlHelper
|
||||||
|
import net.schueller.peertube.helper.ErrorHelper
|
||||||
|
import net.schueller.peertube.model.VideoList
|
||||||
|
import net.schueller.peertube.network.GetUserService
|
||||||
|
import net.schueller.peertube.network.GetVideoDataService
|
||||||
|
import net.schueller.peertube.network.RetrofitInstance
|
||||||
|
import net.schueller.peertube.network.Session
|
||||||
|
import net.schueller.peertube.provider.SearchSuggestionsProvider
|
||||||
|
import net.schueller.peertube.service.VideoPlayerService
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
private const val TAG = "_VideoListActivity"
|
||||||
|
|
||||||
|
class VideoListActivity : CommonActivity() {
|
||||||
|
|
||||||
|
private var videoAdapter: VideoAdapter? = null
|
||||||
|
private var swipeRefreshLayout: SwipeRefreshLayout? = null
|
||||||
|
private var currentStart = 0
|
||||||
|
private val count = 12
|
||||||
|
private var sort = "-createdAt"
|
||||||
|
private var filter: String? = null
|
||||||
|
private var searchQuery = ""
|
||||||
|
private var subscriptions = false
|
||||||
|
private var emptyView: TextView? = null
|
||||||
|
private var recyclerView: RecyclerView? = null
|
||||||
|
private var isLoading = false
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(layout.activity_video_list)
|
||||||
|
filter = null
|
||||||
|
createBottomBarNavigation()
|
||||||
|
|
||||||
|
// Attaching the layout to the toolbar object
|
||||||
|
val toolbar = findViewById<Toolbar>(id.tool_bar)
|
||||||
|
// Setting toolbar as the ActionBar with setSupportActionBar() call
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
|
// load Video List
|
||||||
|
createList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
val inflater = menuInflater
|
||||||
|
inflater.inflate(R.menu.menu_top_videolist, menu)
|
||||||
|
|
||||||
|
// Set an icon in the ActionBar
|
||||||
|
menu.findItem(id.action_account).icon = IconicsDrawable(this, faw_user_circle).actionBar()
|
||||||
|
menu.findItem(id.action_server_address_book).icon = IconicsDrawable(this, faw_server).actionBar()
|
||||||
|
val searchMenuItem = menu.findItem(id.action_search)
|
||||||
|
searchMenuItem.icon = IconicsDrawable(this, faw_search).actionBar()
|
||||||
|
|
||||||
|
// Get the SearchView and set the searchable configuration
|
||||||
|
val searchManager = getSystemService(SEARCH_SERVICE) as SearchManager
|
||||||
|
val searchView = searchMenuItem.actionView as SearchView
|
||||||
|
|
||||||
|
// Assumes current activity is the searchable activity
|
||||||
|
searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
|
||||||
|
searchView.setIconifiedByDefault(false) // Do not iconify the widget; expand it by default
|
||||||
|
searchView.isQueryRefinementEnabled = true
|
||||||
|
searchMenuItem.actionView.setOnLongClickListener {
|
||||||
|
Builder(this@VideoListActivity)
|
||||||
|
.setTitle(getString(R.string.clear_search_history))
|
||||||
|
.setMessage(getString(R.string.clear_search_history_prompt))
|
||||||
|
.setPositiveButton(string.yes) { _, _ ->
|
||||||
|
val suggestions = SearchRecentSuggestions(
|
||||||
|
applicationContext,
|
||||||
|
SearchSuggestionsProvider.AUTHORITY,
|
||||||
|
SearchSuggestionsProvider.MODE
|
||||||
|
)
|
||||||
|
suggestions.clearHistory()
|
||||||
|
}
|
||||||
|
.setNegativeButton(string.no, null)
|
||||||
|
.setIcon(drawable.ic_dialog_alert)
|
||||||
|
.show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
searchMenuItem.setOnActionExpandListener(object : OnActionExpandListener {
|
||||||
|
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
|
||||||
|
searchQuery = ""
|
||||||
|
Log.d(TAG, "onMenuItemActionCollapse: ")
|
||||||
|
loadVideos(0, count, sort, filter)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO, this doesn't work
|
||||||
|
searchManager.setOnDismissListener {
|
||||||
|
searchQuery = ""
|
||||||
|
Log.d(TAG, "onDismiss: ")
|
||||||
|
loadVideos(0, count, sort, filter)
|
||||||
|
}
|
||||||
|
searchView.setOnSuggestionListener(object : OnSuggestionListener {
|
||||||
|
override fun onSuggestionClick(position: Int): Boolean {
|
||||||
|
val suggestion = getSuggestion(position)
|
||||||
|
searchView.setQuery(suggestion, true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSuggestion(position: Int): String {
|
||||||
|
val cursor = searchView.suggestionsAdapter.getItem(
|
||||||
|
position
|
||||||
|
) as Cursor
|
||||||
|
return cursor.getString(
|
||||||
|
cursor
|
||||||
|
.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuggestionSelect(position: Int): Boolean {
|
||||||
|
/* Required to implement */
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
stopService(Intent(this, VideoPlayerService::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (requestCode == SWITCH_INSTANCE) {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
|
when (item.itemId) {
|
||||||
|
id.action_search -> //Toast.makeText(this, "Search Selected", Toast.LENGTH_SHORT).show();
|
||||||
|
return false
|
||||||
|
id.action_account -> {
|
||||||
|
// if (!Session.getInstance().isLoggedIn()) {
|
||||||
|
|
||||||
|
//Intent intentLogin = new Intent(this, ServerAddressBookActivity.class);
|
||||||
|
val intentMe = Intent(this, MeActivity::class.java)
|
||||||
|
this.startActivity(intentMe)
|
||||||
|
|
||||||
|
//overridePendingTransition(R.anim.slide_in_bottom, 0);
|
||||||
|
|
||||||
|
// this.startActivity(intentLogin);
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// Intent intentMe = new Intent(this, MeActivity.class);
|
||||||
|
// this.startActivity(intentMe);
|
||||||
|
// }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
id.action_server_address_book -> {
|
||||||
|
val addressBookActivityIntent = Intent(this, ServerAddressBookActivity::class.java)
|
||||||
|
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createList() {
|
||||||
|
recyclerView = findViewById(id.recyclerView)
|
||||||
|
swipeRefreshLayout = findViewById(id.swipeRefreshLayout)
|
||||||
|
emptyView = findViewById(id.empty_view)
|
||||||
|
val layoutManager: LayoutManager = LinearLayoutManager(this@VideoListActivity)
|
||||||
|
recyclerView?.layoutManager = layoutManager
|
||||||
|
videoAdapter = VideoAdapter(ArrayList(), this@VideoListActivity)
|
||||||
|
recyclerView?.adapter = videoAdapter
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
recyclerView?.addOnScrollListener(object : OnScrollListener() {
|
||||||
|
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
if (dy > 0) {
|
||||||
|
// is at end of list?
|
||||||
|
if (!recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN)) {
|
||||||
|
if (!isLoading) {
|
||||||
|
currentStart += count
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
swipeRefreshLayout?.setOnRefreshListener {
|
||||||
|
// Refresh items
|
||||||
|
if (!isLoading) {
|
||||||
|
currentStart = 0
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadVideos(start: Int, count: Int, sort: String, filter: String?) {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
val sharedPref = getSharedPreferences(packageName + "_preferences", Context.MODE_PRIVATE)
|
||||||
|
val nsfw = if (sharedPref.getBoolean(getString(R.string.pref_show_nsfw_key), false)) "both" else "false"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Locale locale = getResources().getConfiguration().locale;
|
||||||
|
// String country = locale.getLanguage();
|
||||||
|
//
|
||||||
|
// HashSet<String> countries = new HashSet<>(1);
|
||||||
|
// countries.add(country);
|
||||||
|
|
||||||
|
// We set this to default to null so that on initial start there are videos listed.
|
||||||
|
val languages = sharedPref.getStringSet(getString(R.string.pref_video_language_key), null)
|
||||||
|
val apiBaseURL = APIUrlHelper.getUrlWithVersion(this)
|
||||||
|
val service =
|
||||||
|
RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(
|
||||||
|
GetVideoDataService::class.java
|
||||||
|
)
|
||||||
|
val call: Call<VideoList> = when {
|
||||||
|
searchQuery != "" -> {
|
||||||
|
service.searchVideosData(start, count, sort, nsfw, searchQuery, filter, languages)
|
||||||
|
}
|
||||||
|
subscriptions -> {
|
||||||
|
val userService =
|
||||||
|
RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(this)).create(
|
||||||
|
GetUserService::class.java
|
||||||
|
)
|
||||||
|
userService.getVideosSubscripions(start, count, sort)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
service.getVideosData(start, count, sort, nsfw, filter, languages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Log the URL called*/Log.d("URL Called", call.request().url.toString() + "")
|
||||||
|
// Toast.makeText(VideoListActivity.this, "URL Called: " + call.request().url(), Toast.LENGTH_SHORT).show();
|
||||||
|
call.enqueue(object : Callback<VideoList?> {
|
||||||
|
override fun onResponse(call: Call<VideoList?>, response: Response<VideoList?>) {
|
||||||
|
if (currentStart == 0) {
|
||||||
|
videoAdapter!!.clearData()
|
||||||
|
}
|
||||||
|
if (response.body() != null) {
|
||||||
|
val videoList = response.body()!!.videoArrayList
|
||||||
|
if (videoList != null) {
|
||||||
|
videoAdapter!!.setData(response.body()!!.videoArrayList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no results show no results message
|
||||||
|
if (currentStart == 0 && videoAdapter!!.itemCount == 0) {
|
||||||
|
emptyView!!.visibility = View.VISIBLE
|
||||||
|
recyclerView!!.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
emptyView!!.visibility = View.GONE
|
||||||
|
recyclerView!!.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
isLoading = false
|
||||||
|
swipeRefreshLayout!!.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<VideoList?>, t: Throwable) {
|
||||||
|
Log.wtf("err", t.fillInStackTrace())
|
||||||
|
ErrorHelper.showToastFromCommunicationError(this@VideoListActivity, t)
|
||||||
|
isLoading = false
|
||||||
|
swipeRefreshLayout!!.isRefreshing = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
// only check when we actually need the permission
|
||||||
|
val sharedPref = getSharedPreferences(packageName + "_preferences", Context.MODE_PRIVATE)
|
||||||
|
if (ActivityCompat.checkSelfPermission(
|
||||||
|
this,
|
||||||
|
permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
) != PackageManager.PERMISSION_GRANTED &&
|
||||||
|
sharedPref.getBoolean(getString(R.string.pref_torrent_player_key), false)
|
||||||
|
) {
|
||||||
|
ActivityCompat.requestPermissions(this, arrayOf(permission.WRITE_EXTERNAL_STORAGE), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
setIntent(intent)
|
||||||
|
handleIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleIntent(intent: Intent) {
|
||||||
|
if (Intent.ACTION_SEARCH == intent.action) {
|
||||||
|
val query = intent.getStringExtra(SearchManager.QUERY)
|
||||||
|
val suggestions = SearchRecentSuggestions(
|
||||||
|
this,
|
||||||
|
SearchSuggestionsProvider.AUTHORITY,
|
||||||
|
SearchSuggestionsProvider.MODE
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save recent searches
|
||||||
|
suggestions.saveRecentQuery(query, null)
|
||||||
|
if (query != null) {
|
||||||
|
searchQuery = query
|
||||||
|
}
|
||||||
|
loadVideos(0, count, sort, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSearchRequested(): Boolean {
|
||||||
|
val appData = Bundle()
|
||||||
|
startSearch(null, false, appData, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createBottomBarNavigation() {
|
||||||
|
|
||||||
|
// Get Bottom Navigation
|
||||||
|
val navigation = findViewById<BottomNavigationView>(id.navigation)
|
||||||
|
|
||||||
|
// Always show text label
|
||||||
|
navigation.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED
|
||||||
|
|
||||||
|
// Add Icon font
|
||||||
|
val navMenu = navigation.menu
|
||||||
|
navMenu.findItem(id.navigation_overview).icon = IconicsDrawable(this, faw_globe)
|
||||||
|
navMenu.findItem(id.navigation_trending).icon = IconicsDrawable(this, faw_fire)
|
||||||
|
navMenu.findItem(id.navigation_recent).icon = IconicsDrawable(this, faw_plus_circle)
|
||||||
|
navMenu.findItem(id.navigation_local).icon = IconicsDrawable(this, faw_home)
|
||||||
|
navMenu.findItem(id.navigation_subscriptions).icon = IconicsDrawable(this, faw_folder)
|
||||||
|
// navMenu.findItem(R.id.navigation_account).setIcon(
|
||||||
|
// new IconicsDrawable(this, FontAwesome.Icon.faw_user_circle));
|
||||||
|
|
||||||
|
// Click Listener
|
||||||
|
navigation.setOnNavigationItemSelectedListener { menuItem: MenuItem ->
|
||||||
|
when (menuItem.itemId) {
|
||||||
|
id.navigation_overview -> {
|
||||||
|
// TODO
|
||||||
|
if (!isLoading) {
|
||||||
|
sort = "-createdAt"
|
||||||
|
currentStart = 0
|
||||||
|
filter = null
|
||||||
|
subscriptions = false
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
return@setOnNavigationItemSelectedListener true
|
||||||
|
}
|
||||||
|
id.navigation_trending -> {
|
||||||
|
//Log.v(TAG, "navigation_trending");
|
||||||
|
if (!isLoading) {
|
||||||
|
sort = "-trending"
|
||||||
|
currentStart = 0
|
||||||
|
filter = null
|
||||||
|
subscriptions = false
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
return@setOnNavigationItemSelectedListener true
|
||||||
|
}
|
||||||
|
id.navigation_recent -> {
|
||||||
|
if (!isLoading) {
|
||||||
|
sort = "-createdAt"
|
||||||
|
currentStart = 0
|
||||||
|
filter = null
|
||||||
|
subscriptions = false
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
return@setOnNavigationItemSelectedListener true
|
||||||
|
}
|
||||||
|
id.navigation_local -> {
|
||||||
|
//Log.v(TAG, "navigation_trending");
|
||||||
|
if (!isLoading) {
|
||||||
|
sort = "-publishedAt"
|
||||||
|
filter = "local"
|
||||||
|
currentStart = 0
|
||||||
|
subscriptions = false
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
return@setOnNavigationItemSelectedListener true
|
||||||
|
}
|
||||||
|
id.navigation_subscriptions -> //Log.v(TAG, "navigation_subscriptions");
|
||||||
|
if (!Session.getInstance().isLoggedIn) {
|
||||||
|
// Intent intent = new Intent(this, LoginActivity.class);
|
||||||
|
// this.startActivity(intent);
|
||||||
|
val addressBookActivityIntent = Intent(this, ServerAddressBookActivity::class.java)
|
||||||
|
this.startActivityForResult(addressBookActivityIntent, SWITCH_INSTANCE)
|
||||||
|
return@setOnNavigationItemSelectedListener false
|
||||||
|
} else {
|
||||||
|
if (!isLoading) {
|
||||||
|
sort = "-publishedAt"
|
||||||
|
filter = null
|
||||||
|
currentStart = 0
|
||||||
|
subscriptions = true
|
||||||
|
loadVideos(currentStart, count, sort, filter)
|
||||||
|
}
|
||||||
|
return@setOnNavigationItemSelectedListener true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: on double click jump to top and reload
|
||||||
|
// navigation.setOnNavigationItemReselectedListener(menuItemReselected -> {
|
||||||
|
// switch (menuItemReselected.getItemId()) {
|
||||||
|
// case R.id.navigation_home:
|
||||||
|
// if (!isLoading) {
|
||||||
|
// sort = "-createdAt";
|
||||||
|
// currentStart = 0;
|
||||||
|
// filter = null;
|
||||||
|
// subscriptions = false;
|
||||||
|
// loadVideos(currentStart, count, sort, filter);
|
||||||
|
// }
|
||||||
|
// case R.id.navigation_trending:
|
||||||
|
// if (!isLoading) {
|
||||||
|
// sort = "-trending";
|
||||||
|
// currentStart = 0;
|
||||||
|
// filter = null;
|
||||||
|
// subscriptions = false;
|
||||||
|
// loadVideos(currentStart, count, sort, filter);
|
||||||
|
// }
|
||||||
|
// case R.id.navigation_local:
|
||||||
|
// if (!isLoading) {
|
||||||
|
// sort = "-publishedAt";
|
||||||
|
// filter = "local";
|
||||||
|
// currentStart = 0;
|
||||||
|
// subscriptions = false;
|
||||||
|
// loadVideos(currentStart, count, sort, filter);
|
||||||
|
// }
|
||||||
|
// case R.id.navigation_subscriptions:
|
||||||
|
// if (Session.getInstance().isLoggedIn()) {
|
||||||
|
// if (!isLoading) {
|
||||||
|
// sort = "-publishedAt";
|
||||||
|
// filter = null;
|
||||||
|
// currentStart = 0;
|
||||||
|
// subscriptions = true;
|
||||||
|
// loadVideos(currentStart, count, sort, filter);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val EXTRA_VIDEOID = "VIDEOID"
|
||||||
|
const val EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST"
|
||||||
|
const val SWITCH_INSTANCE = 2
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ package net.schueller.peertube.adapter;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.widget.PopupMenu;
|
import androidx.appcompat.widget.PopupMenu;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
@ -74,9 +75,10 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoViewHol
|
|||||||
|
|
||||||
Picasso.get()
|
Picasso.get()
|
||||||
.load(baseUrl + videoList.get(position).getPreviewPath())
|
.load(baseUrl + videoList.get(position).getPreviewPath())
|
||||||
|
.placeholder(R.drawable.test_image)
|
||||||
|
.error(R.drawable.test_image)
|
||||||
.into(holder.thumb);
|
.into(holder.thumb);
|
||||||
|
|
||||||
|
|
||||||
Avatar avatar = videoList.get(position).getAccount().getAvatar();
|
Avatar avatar = videoList.get(position).getAccount().getAvatar();
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
String avatarPath = avatar.getPath();
|
String avatarPath = avatar.getPath();
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package net.schueller.peertube.helper;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import android.text.format.DateUtils;
|
|
||||||
|
|
||||||
import net.schueller.peertube.R;
|
|
||||||
|
|
||||||
import org.ocpsoft.prettytime.PrettyTime;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
|
|
||||||
public class MetaDataHelper {
|
|
||||||
|
|
||||||
|
|
||||||
public static String getMetaString(Date getCreatedAt, Integer viewCount, Context context) {
|
|
||||||
|
|
||||||
// Compatible with SDK 21+
|
|
||||||
String currentLanguage = Locale.getDefault().getDisplayLanguage();
|
|
||||||
PrettyTime p = new PrettyTime(currentLanguage);
|
|
||||||
String relativeTime = p.format(new Date(getCreatedAt.getTime()));
|
|
||||||
|
|
||||||
return (relativeTime +
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDuration(Long duration) {
|
|
||||||
return DateUtils.formatElapsedTime(duration);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package net.schueller.peertube.helper
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import net.schueller.peertube.R.string
|
||||||
|
import org.ocpsoft.prettytime.PrettyTime
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
object MetaDataHelper {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getMetaString(getCreatedAt: Date, viewCount: Int, context: Context): String {
|
||||||
|
|
||||||
|
// Compatible with SDK 21+
|
||||||
|
val currentLanguage = Locale.getDefault().displayLanguage
|
||||||
|
val p = PrettyTime(currentLanguage)
|
||||||
|
val relativeTime = p.format(Date(getCreatedAt.time))
|
||||||
|
return relativeTime +
|
||||||
|
context.resources.getString(string.meta_data_seperator) +
|
||||||
|
viewCount + context.resources.getString(string.meta_data_views)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getOwnerString(accountName: String, serverHost: String, context: Context): String {
|
||||||
|
return accountName +
|
||||||
|
context.resources.getString(string.meta_data_owner_seperator) +
|
||||||
|
serverHost
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getDuration(duration: Long?): String {
|
||||||
|
return DateUtils.formatElapsedTime(duration!!)
|
||||||
|
}
|
||||||
|
}
|
BIN
app/src/main/res/drawable/test_image.gif
Normal file
BIN
app/src/main/res/drawable/test_image.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
@ -13,7 +13,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/tool_bar"
|
android:id="@+id/tool_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -321,7 +321,7 @@
|
|||||||
<string name="network_error">Network access error, please check your connectivity</string>
|
<string name="network_error">Network access error, please check your connectivity</string>
|
||||||
<string name="action_bar_title_server_selection">Select Server</string>
|
<string name="action_bar_title_server_selection">Select Server</string>
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
<string name="action_bar_title_address_book"/>
|
<string name="action_bar_title_address_book">Address Book</string>
|
||||||
<string name="authentication_login_success">Logged in</string>
|
<string name="authentication_login_success">Logged in</string>
|
||||||
<string name="authentication_login_failed">Login Failed!</string>
|
<string name="authentication_login_failed">Login Failed!</string>
|
||||||
<string name="server_book_no_servers_found">Server Books is empty</string>
|
<string name="server_book_no_servers_found">Server Books is empty</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user