diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java index 739be72..c3ff0c9 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java @@ -22,7 +22,6 @@ import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.Build; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; @@ -151,7 +150,6 @@ public class MainActivity extends AppCompatActivity { overviewFragment = new DisplayOverviewFragment(); - Log.v(Helper.TAG,"active: " + active); if( active == null) { active = overviewFragment; } diff --git a/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java b/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java index 166947e..aedda59 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/SepiaSearchActivity.java @@ -16,29 +16,286 @@ package app.fedilab.fedilabtube; import android.os.Bundle; import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.RadioGroup; +import android.widget.Spinner; import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.FragmentTransaction; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.lifecycle.ViewModelProvider; -import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.entities.SepiaSearch; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.viewmodel.SepiaSearchVM; +import mabbas007.tagsedittext.TagsEditText; +import static app.fedilab.fedilabtube.MainActivity.peertubeInformation; public class SepiaSearchActivity extends AppCompatActivity { + private SepiaSearch sepiaSearchVideo; + private SepiaSearch sepiaSearchChannel; + + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sepia_search); + sepiaSearchVideo = new SepiaSearch(); + sepiaSearchChannel = new SepiaSearch(); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); + Button filter = findViewById(R.id.filter); + ConstraintLayout filter_elements = findViewById(R.id.filter_elements); + filter.setOnClickListener(view -> { + if( filter_elements.getVisibility() == View.VISIBLE) { + filter_elements.setVisibility(View.GONE); + }else{ + filter_elements.setVisibility(View.VISIBLE); + } + }); + RadioGroup sepia_element_nsfw = findViewById(R.id.sepia_element_nsfw); + sepia_element_nsfw.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == R.id.sepia_element_nsfw_no) { + sepiaSearchVideo.setNsfw(false); + } else { + sepiaSearchVideo.setNsfw(true); + } + }); + + RadioGroup radio_date = findViewById(R.id.radio_date); + radio_date.setOnCheckedChangeListener((group, checkedId) -> { + switch(checkedId){ + case R.id.sepia_element_published_date_today: + Calendar cal = GregorianCalendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + sepiaSearchVideo.setStartDate(cal.getTime()); + break; + case R.id.sepia_element_published_date_last_7_days: + cal = GregorianCalendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_YEAR, -7); + sepiaSearchVideo.setStartDate(cal.getTime()); + break; + case R.id.sepia_element_published_date_last_30_days: + cal = GregorianCalendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_YEAR, -30); + sepiaSearchVideo.setStartDate(cal.getTime()); + break; + case R.id.sepia_element_published_date_last_365_days: + cal = GregorianCalendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_YEAR, -365); + sepiaSearchVideo.setStartDate(cal.getTime()); + break; + default: + sepiaSearchVideo.setStartDate(null); + } + }); + + + RadioGroup duration = findViewById(R.id.duration); + duration.setOnCheckedChangeListener((group, checkedId) -> { + switch(checkedId){ + case R.id.sepia_element_duration_short: + sepiaSearchVideo.setDurationMin(0); + sepiaSearchVideo.setDurationMax(240); + break; + case R.id.sepia_element_duration_medium: + sepiaSearchVideo.setDurationMin(240); + sepiaSearchVideo.setDurationMax(600); + break; + case R.id.sepia_element_duration_long: + sepiaSearchVideo.setDurationMin(600); + sepiaSearchVideo.setDurationMax(999999999); + break; + default: + sepiaSearchVideo.setDurationMin(0); + sepiaSearchVideo.setDurationMax(999999999); + break; + } + }); + + + + Spinner sort_by = findViewById(R.id.sort_by); + ArrayAdapter adapterSortBy = new ArrayAdapter<>(SepiaSearchActivity.this, + android.R.layout.simple_spinner_dropdown_item, getResources().getStringArray(R.array.sort_by_array)); + sort_by.setAdapter(adapterSortBy); + sort_by.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + String orderby, channelOrderBy; + switch (position){ + case 1: + orderby = "-publishedAt"; + channelOrderBy = "-createdAt"; + break; + case 2: + orderby = "publishedAt"; + channelOrderBy = "createdAt"; + break; + default: + orderby = "-match"; + channelOrderBy = null; + } + sepiaSearchVideo.setSort(orderby); + sepiaSearchChannel.setSort(channelOrderBy); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + Spinner sepia_element_category = findViewById(R.id.sepia_element_category); + Spinner sepia_element_license = findViewById(R.id.sepia_element_license); + Spinner sepia_element_language = findViewById(R.id.sepia_element_language); + + TagsEditText sepia_element_all_of_tags = findViewById(R.id.sepia_element_all_of_tags); + TagsEditText sepia_element_one_of_tags = findViewById(R.id.sepia_element_one_of_tags); + + LinkedHashMap categories = new LinkedHashMap<>(peertubeInformation.getCategories()); + LinkedHashMap licences = new LinkedHashMap<>(peertubeInformation.getLicences()); + LinkedHashMap languages = new LinkedHashMap<>(peertubeInformation.getLanguages()); + LinkedHashMap translations = new LinkedHashMap<>(peertubeInformation.getTranslations()); + + //Populate catgories + String[] categoriesA = new String[categories.size()+1]; + categoriesA[0] = getString(R.string.display_all_categories); + Iterator> it = categories.entrySet().iterator(); + int i = 1; + while (it.hasNext()) { + Map.Entry pair = it.next(); + if (translations.size() == 0 || !translations.containsKey(pair.getValue())) + categoriesA[i] = pair.getValue(); + else + categoriesA[i] = translations.get(pair.getValue()); + it.remove(); + i++; + } + ArrayAdapter adapterCatgories = new ArrayAdapter<>(SepiaSearchActivity.this, + android.R.layout.simple_spinner_dropdown_item, categoriesA); + sepia_element_category.setAdapter(adapterCatgories); + + + //Populate licenses + String[] licensesA = new String[licences.size()+1]; + licensesA[0] = getString(R.string.display_all_licenses); + it = licences.entrySet().iterator(); + i = 1; + while (it.hasNext()) { + Map.Entry pair = it.next(); + if (translations.size() == 0 || !translations.containsKey(pair.getValue())) + licensesA[i] = pair.getValue(); + else + licensesA[i] = translations.get(pair.getValue()); + it.remove(); + i++; + } + ArrayAdapter adapterLicenses = new ArrayAdapter<>(SepiaSearchActivity.this, + android.R.layout.simple_spinner_dropdown_item, licensesA); + sepia_element_license.setAdapter(adapterLicenses); + + //Populate languages + String[] languagesA = new String[languages.size()+1]; + languagesA[0] = getString(R.string.display_all_languages); + Iterator> itl = languages.entrySet().iterator(); + i = 1; + while (itl.hasNext()) { + Map.Entry pair = itl.next(); + if (translations.size() == 0 || !translations.containsKey(pair.getValue())) + languagesA[i] = pair.getValue(); + else + languagesA[i] = translations.get(pair.getValue()); + itl.remove(); + i++; + } + ArrayAdapter adapterLanguages = new ArrayAdapter<>(SepiaSearchActivity.this, + android.R.layout.simple_spinner_dropdown_item, languagesA); + sepia_element_language.setAdapter(adapterLanguages); + + + sepia_element_license.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateLicensePosition(position); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + //Manage categories + sepia_element_category.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateCategoryPosition(position); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + //Manage languages + sepia_element_language.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateLanguagesPosition(position); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + + + Button apply_filter = findViewById(R.id.apply_filter); + apply_filter.setOnClickListener(v->{ + if( sepia_element_one_of_tags.getTags().size() > 0 ) { + sepiaSearchVideo.setTagsOneOf(sepia_element_one_of_tags.getTags()); + }else{ + sepiaSearchVideo.setTagsOneOf(null); + } + if( sepia_element_all_of_tags.getTags().size() > 0 ) { + sepiaSearchVideo.setTagsAllOf(sepia_element_all_of_tags.getTags()); + }else{ + sepiaSearchVideo.setTagsAllOf(null); + } + SepiaSearchVM sepiaSearchVM = new ViewModelProvider(SepiaSearchActivity.this).get(SepiaSearchVM.class); + sepiaSearchVM.sepiaSearch(sepiaSearchVideo).observe(SepiaSearchActivity.this, this::manageVideos); + }); } @@ -51,4 +308,65 @@ public class SepiaSearchActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } + private void manageVideos(VideoData videoData) { + + } + + private void updateLanguagesPosition(int position) { + LinkedHashMap languagesCheck = new LinkedHashMap<>(peertubeInformation.getLanguages()); + Iterator> it = languagesCheck.entrySet().iterator(); + int i = 0; + while (it.hasNext()) { + Map.Entry pair = it.next(); + if (i == position && position > 0) { + List languages = new ArrayList<>(); + languages.add(pair.getKey()); + sepiaSearchVideo.setBoostLanguages(languages); + break; + }else { + sepiaSearchVideo.setBoostLanguages(null); + } + it.remove(); + i++; + } + } + + private void updateCategoryPosition(int position) { + LinkedHashMap categoriesCheck = new LinkedHashMap<>(peertubeInformation.getCategories()); + Iterator> it = categoriesCheck.entrySet().iterator(); + int i = 0; + while (it.hasNext()) { + Map.Entry pair = it.next(); + if (i == position && position > 0 ) { + List categories = new ArrayList<>(); + categories.add(pair.getKey()); + sepiaSearchVideo.setCategoryOneOf(categories); + break; + }else { + sepiaSearchVideo.setCategoryOneOf(null); + } + it.remove(); + i++; + } + } + + private void updateLicensePosition(int position) { + LinkedHashMap licensesCheck = new LinkedHashMap<>(peertubeInformation.getLicences()); + Iterator> it = licensesCheck.entrySet().iterator(); + int i = 0; + while (it.hasNext()) { + Map.Entry pair = it.next(); + if (i == position && position > 0) { + List licenses = new ArrayList<>(); + licenses.add(pair.getKey()); + sepiaSearchVideo.setLicenceOneOf(licenses); + break; + }else { + sepiaSearchVideo.setLicenceOneOf(null); + } + it.remove(); + i++; + } + } + } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitSepiaSearchAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitSepiaSearchAPI.java index b095056..6f55875 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitSepiaSearchAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitSepiaSearchAPI.java @@ -17,26 +17,25 @@ package app.fedilab.fedilabtube.client; import android.content.Context; import android.content.SharedPreferences; -import java.util.Set; - -import app.fedilab.fedilabtube.R; +import java.io.IOException; +import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.entities.SepiaSearch; import app.fedilab.fedilabtube.helper.Helper; +import retrofit2.Call; +import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; -class RetrofitSepiaSearchAPI { +public class RetrofitSepiaSearchAPI { private String finalUrl; - private Context _context; - private Set selection; private String count; public RetrofitSepiaSearchAPI(Context context) { - _context = context; finalUrl = "https://search.joinpeertube.org/api/v1/"; - SharedPreferences sharedpreferences = _context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); count = String.valueOf(sharedpreferences.getInt(Helper.SET_VIDEOS_PER_PAGE, Helper.VIDEOS_PER_PAGE)); } @@ -45,11 +44,38 @@ class RetrofitSepiaSearchAPI { .baseUrl(finalUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); - SharedPreferences sharedpreferences = _context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - selection = sharedpreferences.getStringSet(_context.getString(R.string.set_video_language_choice), null); return retrofit.create(SepiaSearchService.class); } - + /** + * Return videos for a sepia search + * @param sepiaSearch SepiaSearch + * @return VideoData + */ + public VideoData getVideos(SepiaSearch sepiaSearch) { + SepiaSearchService sepiaSearchService = init(); + Call videoDataCall = sepiaSearchService.getVideos( + sepiaSearch.getStart(), + count, + sepiaSearch.getSearch(), + sepiaSearch.getDurationMax(), + sepiaSearch.getStartDate(), + sepiaSearch.getBoostLanguages(), + sepiaSearch.getCategoryOneOf(), + sepiaSearch.getLicenceOneOf(), + sepiaSearch.getTagsOneOf(), + sepiaSearch.getTagsAllOf(), + sepiaSearch.isNsfw(), + sepiaSearch.getSort()); + try { + Response response = videoDataCall.execute(); + if (response.isSuccessful() && response.body() != null) { + return response.body(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/SepiaSearchService.java b/app/src/main/java/app/fedilab/fedilabtube/client/SepiaSearchService.java index 69e9eb2..8c42845 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/SepiaSearchService.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/SepiaSearchService.java @@ -33,8 +33,8 @@ interface SepiaSearchService { @Query("durationMax") int durationMax, @Query("startDate") Date startDate, @Query("boostLanguages") List languageOneOf, - @Query("categoryOneOf") List categoryOneOf, - @Query("licenceOneOf") List licenceOneOf, + @Query("categoryOneOf") List categoryOneOf, + @Query("licenceOneOf") List licenceOneOf, @Query("tagsOneOf") List tagsOneOf, @Query("tagsAllOf") List tagsAllOf, @Query("nsfw") boolean nsfw, diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/SepiaSearch.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/SepiaSearch.java index 1674349..0beb8d3 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/SepiaSearch.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/SepiaSearch.java @@ -19,11 +19,12 @@ import android.os.Parcelable; import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; import java.util.Date; import java.util.List; @SuppressWarnings("unused") -class SepiaSearch implements Parcelable { +public class SepiaSearch implements Parcelable { @SerializedName("start") private String start; @@ -33,14 +34,16 @@ class SepiaSearch implements Parcelable { private String search; @SerializedName("durationMax") private int durationMax; + @SerializedName("durationMin") + private int durationMin; @SerializedName("startDate") private Date startDate; @SerializedName("boostLanguages") private List boostLanguages; @SerializedName("categoryOneOf") - private List categoryOneOf; + private List categoryOneOf; @SerializedName("licenceOneOf") - private List licenceOneOf; + private List licenceOneOf; @SerializedName("tagsOneOf") private List tagsOneOf; @SerializedName("tagsAllOf") @@ -84,6 +87,14 @@ class SepiaSearch implements Parcelable { this.durationMax = durationMax; } + public int getDurationMin() { + return durationMin; + } + + public void setDurationMin(int durationMin) { + this.durationMin = durationMin; + } + public Date getStartDate() { return startDate; } @@ -100,19 +111,19 @@ class SepiaSearch implements Parcelable { this.boostLanguages = boostLanguages; } - public List getCategoryOneOf() { + public List getCategoryOneOf() { return categoryOneOf; } - public void setCategoryOneOf(List categoryOneOf) { + public void setCategoryOneOf(List categoryOneOf) { this.categoryOneOf = categoryOneOf; } - public List getLicenceOneOf() { + public List getLicenceOneOf() { return licenceOneOf; } - public void setLicenceOneOf(List licenceOneOf) { + public void setLicenceOneOf(List licenceOneOf) { this.licenceOneOf = licenceOneOf; } @@ -159,10 +170,11 @@ class SepiaSearch implements Parcelable { dest.writeString(this.count); dest.writeString(this.search); dest.writeInt(this.durationMax); + dest.writeInt(this.durationMin); dest.writeLong(this.startDate != null ? this.startDate.getTime() : -1); dest.writeStringList(this.boostLanguages); - dest.writeStringList(this.categoryOneOf); - dest.writeStringList(this.licenceOneOf); + dest.writeList(this.categoryOneOf); + dest.writeList(this.licenceOneOf); dest.writeStringList(this.tagsOneOf); dest.writeStringList(this.tagsAllOf); dest.writeByte(this.nsfw ? (byte) 1 : (byte) 0); @@ -177,18 +189,21 @@ class SepiaSearch implements Parcelable { this.count = in.readString(); this.search = in.readString(); this.durationMax = in.readInt(); + this.durationMin = in.readInt(); long tmpStartDate = in.readLong(); this.startDate = tmpStartDate == -1 ? null : new Date(tmpStartDate); this.boostLanguages = in.createStringArrayList(); - this.categoryOneOf = in.createStringArrayList(); - this.licenceOneOf = in.createStringArrayList(); + this.categoryOneOf = new ArrayList<>(); + in.readList(this.categoryOneOf, Integer.class.getClassLoader()); + this.licenceOneOf = new ArrayList<>(); + in.readList(this.licenceOneOf, Integer.class.getClassLoader()); this.tagsOneOf = in.createStringArrayList(); this.tagsAllOf = in.createStringArrayList(); this.nsfw = in.readByte() != 0; this.sort = in.readString(); } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Creator CREATOR = new Creator() { @Override public SepiaSearch createFromParcel(Parcel source) { return new SepiaSearch(source); diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplaySepiaSearchFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplaySepiaSearchFragment.java new file mode 100644 index 0000000..cae2de2 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplaySepiaSearchFragment.java @@ -0,0 +1,319 @@ +package app.fedilab.fedilabtube.fragment; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab 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 General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.R; +import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.entities.SepiaSearch; +import app.fedilab.fedilabtube.drawer.AccountsHorizontalListAdapter; +import app.fedilab.fedilabtube.drawer.PeertubeAdapter; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.viewmodel.SepiaSearchVM; +import es.dmoral.toasty.Toasty; + + +public class DisplaySepiaSearchFragment extends Fragment implements AccountsHorizontalListAdapter.EventListener { + + + private LinearLayoutManager mLayoutManager; + private GridLayoutManager gLayoutManager; + private boolean flag_loading; + private Context context; + private PeertubeAdapter peertubeAdapater; + private String max_id; + private List peertubes; + private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; + private boolean firstLoad; + private SwipeRefreshLayout swipeRefreshLayout; + private SharedPreferences sharedpreferences; + private TextView textviewNoActionText; + private View rootView; + private RecyclerView lv_status; + private SepiaSearchVM viewModelSearch; + + public DisplaySepiaSearchFragment() { + } + + private SepiaSearch sepiaSearchVideo; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + rootView = inflater.inflate(R.layout.fragment_video, container, false); + + + peertubes = new ArrayList<>(); + context = getContext(); + Bundle bundle = this.getArguments(); + if (bundle != null) { + sepiaSearchVideo = bundle.getParcelable("sepiaSearchVideo"); + } + max_id = "0"; + lv_status = rootView.findViewById(R.id.lv_status); + flag_loading = true; + firstLoad = true; + + assert context != null; + sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); + + mainLoader = rootView.findViewById(R.id.loader); + nextElementLoader = rootView.findViewById(R.id.loading_next_status); + textviewNoAction = rootView.findViewById(R.id.no_action); + textviewNoActionText = rootView.findViewById(R.id.no_action_text); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + + peertubeAdapater = new PeertubeAdapter(this.peertubes); + lv_status.setAdapter(peertubeAdapater); + + + if (!Helper.isTablet(context)) { + mLayoutManager = new LinearLayoutManager(context); + lv_status.setLayoutManager(mLayoutManager); + } else { + gLayoutManager = new GridLayoutManager(context, 2); + int spanCount = (int) Helper.convertDpToPixel(2, context); + int spacing = (int) Helper.convertDpToPixel(5, context); + lv_status.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, true)); + lv_status.setLayoutManager(gLayoutManager); + } + viewModelSearch = new ViewModelProvider(DisplaySepiaSearchFragment.this).get(SepiaSearchVM.class); + swipeRefreshLayout.setOnRefreshListener(this::pullToRefresh); + + + + lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (mLayoutManager != null) { + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { + if (!flag_loading) { + flag_loading = true; + loadTimeline(); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } else if (gLayoutManager != null) { + int firstVisibleItem = gLayoutManager.findFirstVisibleItemPosition(); + if (dy > 0) { + int visibleItemCount = gLayoutManager.getChildCount(); + int totalItemCount = gLayoutManager.getItemCount(); + if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { + if (!flag_loading) { + flag_loading = true; + loadTimeline(); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } + } + }); + loadTimeline(); + return rootView; + } + + + + @Override + public void onPause() { + super.onPause(); + if (swipeRefreshLayout != null) { + swipeRefreshLayout.setEnabled(false); + swipeRefreshLayout.setRefreshing(false); + swipeRefreshLayout.clearAnimation(); + } + if (getActivity() != null) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null && getView() != null) { + imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); + } + } + } + + + @Override + public void onCreate(Bundle saveInstance) { + super.onCreate(saveInstance); + } + + + @Override + public void onAttach(@NotNull Context context) { + super.onAttach(context); + this.context = context; + } + + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + + private void manageVIewVideos(VideoData videoData) { + //hide loaders + mainLoader.setVisibility(View.GONE); + nextElementLoader.setVisibility(View.GONE); + //handle other API error + if (videoData == null || videoData.data == null) { + Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + swipeRefreshLayout.setRefreshing(false); + flag_loading = false; + return; + } + int previousPosition = this.peertubes.size(); + if (max_id == null) + max_id = "0"; + int videoPerPage = sharedpreferences.getInt(Helper.SET_VIDEOS_PER_PAGE, Helper.VIDEOS_PER_PAGE); + max_id = String.valueOf(Integer.parseInt(max_id) + videoPerPage); + this.peertubes.addAll(videoData.data); + //If no item were inserted previously the adapter is created + if (previousPosition == 0) { + peertubeAdapater = new PeertubeAdapter(this.peertubes); + lv_status.setAdapter(peertubeAdapater); + } else + peertubeAdapater.notifyItemRangeInserted(previousPosition, videoData.data.size()); + //remove handlers + swipeRefreshLayout.setRefreshing(false); + textviewNoAction.setVisibility(View.GONE); + if (firstLoad && (videoData.data== null || videoData.data.size() == 0)) { + textviewNoActionText.setText(R.string.no_video_to_display); + textviewNoAction.setVisibility(View.VISIBLE); + } + flag_loading = false; + firstLoad = false; + } + + @Override + public void onDestroyView() { + if (lv_status != null) { + try { + lv_status.setAdapter(null); + } catch (Exception ignored) { + } + } + super.onDestroyView(); + rootView = null; + } + + @Override + public void onResume() { + super.onResume(); + swipeRefreshLayout.setEnabled(true); + } + + + public void scrollToTop() { + if (mLayoutManager != null) { + mLayoutManager.scrollToPositionWithOffset(0, 0); + } else if (gLayoutManager != null) { + gLayoutManager.scrollToPositionWithOffset(0, 0); + } + } + + + public void pullToRefresh() { + int size = peertubes.size(); + peertubes.clear(); + peertubes = new ArrayList<>(); + peertubeAdapater.notifyItemRangeRemoved(0, size); + loadTimeline(); + } + + @Override + public void click(String forAccount) { + pullToRefresh(); + } + + private void loadTimeline() { + viewModelSearch.sepiaSearch(sepiaSearchVideo).observe(this.requireActivity(), this::manageVIewVideos); + } + + + + static class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; + private int spacing; + private boolean includeEdge; + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + this.includeEdge = includeEdge; + } + + @Override + public void getItemOffsets(@NotNull Rect outRect, @NotNull View view, RecyclerView parent, @NotNull RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); + int column = position % spanCount; + + if (includeEdge) { + outRect.left = spacing - column * spacing / spanCount; + outRect.right = (column + 1) * spacing / spanCount; + + if (position < spanCount) { + outRect.top = spacing; + } + outRect.bottom = spacing; + } else { + outRect.left = column * spacing / spanCount; + outRect.right = spacing - (column + 1) * spacing / spanCount; + if (position >= spanCount) { + outRect.top = spacing; + } + } + } + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java index 3af9cc7..d7733b0 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java @@ -119,7 +119,6 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta RecyclerView lv_accounts = rootView.findViewById(R.id.lv_accounts); Button display_all = rootView.findViewById(R.id.display_all); top_account_container = rootView.findViewById(R.id.top_account_container); - max_id = null; max_id_accounts = null; flag_loading = true; firstLoad = true; diff --git a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SepiaSearchVM.java b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SepiaSearchVM.java new file mode 100644 index 0000000..4a1d8e3 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SepiaSearchVM.java @@ -0,0 +1,58 @@ +package app.fedilab.fedilabtube.viewmodel; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab 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 General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.app.Application; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import app.fedilab.fedilabtube.client.RetrofitSepiaSearchAPI; +import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.entities.SepiaSearch; + + +public class SepiaSearchVM extends AndroidViewModel { + private MutableLiveData apiResponseMutableLiveData; + + public SepiaSearchVM(@NonNull Application application) { + super(application); + } + + public LiveData sepiaSearch(SepiaSearch sepiaSearch) { + apiResponseMutableLiveData = new MutableLiveData<>(); + getVideos(sepiaSearch); + return apiResponseMutableLiveData; + } + + private void getVideos(SepiaSearch sepiaSearch) { + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + VideoData videoData = new RetrofitSepiaSearchAPI(_mContext).getVideos(sepiaSearch); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> apiResponseMutableLiveData.setValue(videoData); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + +} diff --git a/app/src/main/res/layout/activity_sepia_search.xml b/app/src/main/res/layout/activity_sepia_search.xml index 3997d38..634f0ba 100644 --- a/app/src/main/res/layout/activity_sepia_search.xml +++ b/app/src/main/res/layout/activity_sepia_search.xml @@ -33,6 +33,7 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" android:id="@+id/header" + android:animateLayoutChanges="true" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"> @@ -141,6 +144,7 @@ app:layout_constraintTop_toBottomOf="@+id/sepia_element_published_date_label" app:layout_constraintStart_toStartOf="parent"> - - + + + @@ -281,7 +281,7 @@ android:labelFor="@+id/sepia_element_all_of_tags" android:text="@string/all_of_these_tags" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/sepia_element_category" + app:layout_constraintTop_toBottomOf="@+id/sepia_element_language" app:layout_constraintEnd_toEndOf="parent" android:id="@+id/sepia_element_all_of_tags_label" />