From c64217e2b485f3c6b997a55b1ef910c8b72779d3 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Fri, 26 Jun 2015 02:39:22 +0200 Subject: Add episode action fragment --- .../dialog/EpisodesApplyActionFragment.java | 415 +++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java (limited to 'app/src/main/java/de/danoeh/antennapod/dialog') diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java new file mode 100644 index 000000000..d40cee37d --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -0,0 +1,415 @@ +package de.danoeh.antennapod.dialog; + +import android.app.ProgressDialog; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.Toast; + +import com.joanzapata.android.iconify.IconDrawable; +import com.joanzapata.android.iconify.Iconify; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.storage.DBTasks; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.util.LongList; + +public class EpisodesApplyActionFragment extends Fragment { + + public String TAG = "EpisodeActionFragment"; + + private ListView mListView; + private ArrayAdapter mAdapter; + + private Button btnAddToQueue; + private Button btnMarkAsPlayed; + private Button btnMarkAsUnplayed; + private Button btnDownload; + private Button btnDelete; + + private final List episodes; + private final List titles = new ArrayList(); + private final LongList checkedIds = new LongList(); + + private MenuItem mSelectToggle; + + private int textColor; + + private ProgressDialog pd; + + public EpisodesApplyActionFragment(List episodes) { + this.episodes = episodes; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActionBar bar = ((ActionBarActivity)getActivity()).getSupportActionBar(); + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.episodes_apply_action_fragment, container, false); + + mListView = (ListView) view.findViewById(android.R.id.list); + mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView ListView, View view, int position, long rowId) { + long id = episodes.get(position).getId(); + if (checkedIds.contains(id)) { + checkedIds.remove(id); + } else { + checkedIds.add(id); + } + refreshCheckboxes(); + } + }); + + for(FeedItem episode : episodes) { + titles.add(episode.getTitle()); + } + + mAdapter = new ArrayAdapter<>(getActivity(), + android.R.layout.simple_list_item_multiple_choice, titles); + mListView.setAdapter(mAdapter); + checkAll(); + + btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue); + btnAddToQueue.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + queueChecked(); + } + }); + btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed); + btnMarkAsPlayed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + markedCheckedPlayed(); + } + }); + btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed); + btnMarkAsUnplayed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + markedCheckedUnplayed(); + } + }); + btnDownload = (Button) view.findViewById(R.id.btnDownload); + btnDownload.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + downloadChecked(); + } + }); + btnDelete = (Button) view.findViewById(R.id.btnDelete); + btnDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + deleteChecked(); + } + }); + + return view; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.episodes_apply_action_options, menu); + + int[] attrs = { android.R.attr.textColor }; + TypedArray ta = getActivity().obtainStyledAttributes(attrs); + textColor = ta.getColor(0, Color.GRAY); + ta.recycle(); + + menu.findItem(R.id.sort).setIcon(new IconDrawable(getActivity(), + Iconify.IconValue.fa_sort).color(textColor).actionBarSize()); + + mSelectToggle = menu.findItem(R.id.select_toggle); + mSelectToggle.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (checkedIds.size() == episodes.size()) { + checkNone(); + } else { + checkAll(); + } + return true; + } + }); + + menu.findItem(R.id.select_options).setIcon(new IconDrawable(getActivity(), + Iconify.IconValue.fa_caret_down).color(textColor).actionBarSize()); + } + + @Override + public void onPrepareOptionsMenu (Menu menu) { + Iconify.IconValue iVal; + if(checkedIds.size() == episodes.size()) { + iVal = Iconify.IconValue.fa_check_square_o; + } else if(checkedIds.size() == 0) { + iVal = Iconify.IconValue.fa_square_o; + } else { + iVal = Iconify.IconValue.fa_minus_square_o; + } + mSelectToggle.setIcon(new IconDrawable(getActivity(), iVal).color(textColor).actionBarSize()); + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int resId = 0; + switch(item.getItemId()) { + case R.id.select_options: + return true; + case R.id.check_all: + checkAll(); + resId = R.string.selected_all_label; + break; + case R.id.check_none: + checkNone(); + resId = R.string.deselected_all_label; + break; + case R.id.check_played: + checkPlayed(true); + resId = R.string.selected_played_label; + break; + case R.id.check_unplayed: + checkPlayed(false); + resId = R.string.selected_unplayed_label; + break; + case R.id.check_downloaded: + checkDownloaded(true); + resId = R.string.selected_downloaded_label; + break; + case R.id.check_not_downloaded: + checkDownloaded(false); + resId = R.string.selected_not_downloaded_label; + break; + case R.id.sort_title_a_z: + sortByTitle(false); + return true; + case R.id.sort_title_z_a: + sortByTitle(true); + return true; + case R.id.sort_date_new_old: + sortByDate(true); + return true; + case R.id.sort_date_old_new: + sortByDate(false); + return true; + case R.id.sort_duration_long_short: + sortByDuration(true); + return true; + case R.id.sort_duration_short_long: + sortByDuration(false); + return true; + } + if(resId != 0) { + Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show(); + return true; + } else { + return false; + } + } + + private void sortByTitle(final boolean reverse) { + Log.d(TAG, "sortByTitle()"); + Collections.sort(episodes, new Comparator() { + @Override + public int compare(FeedItem lhs, FeedItem rhs) { + if (reverse) { + return -1 * lhs.getTitle().compareTo(rhs.getTitle()); + } else { + return lhs.getTitle().compareTo(rhs.getTitle()); + } + } + }); + refreshTitles(); + refreshCheckboxes(); + } + + private void sortByDate(final boolean reverse) { + Collections.sort(episodes, new Comparator() { + @Override + public int compare(FeedItem lhs, FeedItem rhs) { + if (lhs.getPubDate() == null) { + return -1; + } else if (rhs.getPubDate() == null) { + return 1; + } + int code = lhs.getPubDate().compareTo(rhs.getPubDate()); + if (reverse) { + return -1 * code; + } else { + return code; + } + } + }); + refreshTitles(); + refreshCheckboxes(); + } + + private void sortByDuration(final boolean reverse) { + Collections.sort(episodes, new Comparator() { + @Override + public int compare(FeedItem lhs, FeedItem rhs) { + int code = lhs.getMedia().getDuration() - rhs.getMedia().getDuration(); + if (reverse) { + return -1 * code; + } else { + return code; + } + } + }); + refreshTitles(); + refreshCheckboxes(); + } + + private void checkAll() { + for(int i=0; i < episodes.size(); i++) { + FeedItem episode = episodes.get(i); + if(false == checkedIds.contains(episode.getId())) { + checkedIds.add(episode.getId()); + } + } + refreshCheckboxes(); + } + + private void checkNone() { + checkedIds.clear(); + refreshCheckboxes(); + } + + private void checkPlayed(boolean isPlayed) { + for (int i = 0; i < episodes.size(); i++) { + FeedItem episode = episodes.get(i); + if(episode.isRead() == isPlayed) { + if(!checkedIds.contains(episode.getId())) { + checkedIds.add(episode.getId()); + } + } else { + if(checkedIds.contains(episode.getId())) { + checkedIds.remove(episode.getId()); + } + } + } + refreshCheckboxes(); + } + + private void checkDownloaded(boolean isDownloaded) { + for (int i = 0; i < episodes.size(); i++) { + FeedItem episode = episodes.get(i); + if(episode.getMedia().isDownloaded() == isDownloaded) { + if(!checkedIds.contains(episode.getId())) { + checkedIds.add(episode.getId()); + } + } else { + if(checkedIds.contains(episode.getId())) { + checkedIds.remove(episode.getId()); + } + } + } + refreshCheckboxes(); + } + + private void refreshTitles() { + titles.clear(); + for(FeedItem episode : episodes) { + titles.add(episode.getTitle()); + } + mAdapter.notifyDataSetChanged(); + } + + private void refreshCheckboxes() { + for (int i = 0; i < episodes.size(); i++) { + FeedItem episode = episodes.get(i); + boolean checked = checkedIds.contains(episode.getId()); + mListView.setItemChecked(i, checked); + } + ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity()); + } + + private void queueChecked() { + DBWriter.addQueueItem(getActivity(), false, checkedIds.toArray()); + close(); + } + + private void markedCheckedPlayed() { + for(long id : checkedIds.toArray()) { + DBWriter.markItemRead(getActivity(), id, true); + } + close(); + } + + private void markedCheckedUnplayed() { + for(long id : checkedIds.toArray()) { + DBWriter.markItemRead(getActivity(), id, false); + } + close(); + } + + private void downloadChecked() { + FeedItem[] items = new FeedItem[checkedIds.size()]; + for(int i=0; i < checkedIds.size(); i++) { + long id = checkedIds.get(i); + items[i] = findById(id); + } + try { + DBTasks.downloadFeedItems(getActivity(), items); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); + } + close(); + } + + private void deleteChecked() { + for(long id : checkedIds.toArray()) { + FeedItem episode = findById(id); + DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId()); + } + close(); + } + + private void close() { + getActivity().getSupportFragmentManager().popBackStack(); + } + + private FeedItem findById(long id) { + for(int i=0; i < episodes.size(); i++) { + FeedItem episode = episodes.get(i); + if(episode.getId() == id) { + return episode; + } + } + return null; + } + +} -- cgit v1.2.3 From 957497d787e1268e09b629de42db8a689a3edd0e Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Sat, 27 Jun 2015 22:17:18 +0200 Subject: Enqueue and items in the currently display order, submit changes on bulk --- .../dialog/EpisodesApplyActionFragment.java | 39 +++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'app/src/main/java/de/danoeh/antennapod/dialog') diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index d40cee37d..25d27217b 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -8,7 +8,6 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -240,7 +239,6 @@ public class EpisodesApplyActionFragment extends Fragment { } private void sortByTitle(final boolean reverse) { - Log.d(TAG, "sortByTitle()"); Collections.sort(episodes, new Comparator() { @Override public int compare(FeedItem lhs, FeedItem rhs) { @@ -293,8 +291,7 @@ public class EpisodesApplyActionFragment extends Fragment { } private void checkAll() { - for(int i=0; i < episodes.size(); i++) { - FeedItem episode = episodes.get(i); + for (FeedItem episode : episodes) { if(false == checkedIds.contains(episode.getId())) { checkedIds.add(episode.getId()); } @@ -308,8 +305,7 @@ public class EpisodesApplyActionFragment extends Fragment { } private void checkPlayed(boolean isPlayed) { - for (int i = 0; i < episodes.size(); i++) { - FeedItem episode = episodes.get(i); + for (FeedItem episode : episodes) { if(episode.isRead() == isPlayed) { if(!checkedIds.contains(episode.getId())) { checkedIds.add(episode.getId()); @@ -324,8 +320,7 @@ public class EpisodesApplyActionFragment extends Fragment { } private void checkDownloaded(boolean isDownloaded) { - for (int i = 0; i < episodes.size(); i++) { - FeedItem episode = episodes.get(i); + for (FeedItem episode : episodes) { if(episode.getMedia().isDownloaded() == isDownloaded) { if(!checkedIds.contains(episode.getId())) { checkedIds.add(episode.getId()); @@ -357,32 +352,36 @@ public class EpisodesApplyActionFragment extends Fragment { } private void queueChecked() { - DBWriter.addQueueItem(getActivity(), false, checkedIds.toArray()); + LongList orderedIds = new LongList(); + for(FeedItem episode : episodes) { + if(checkedIds.contains(episode.getId())) { + orderedIds.add((episode.getId())); + } + } + DBWriter.addQueueItem(getActivity(), false, orderedIds.toArray()); close(); } private void markedCheckedPlayed() { - for(long id : checkedIds.toArray()) { - DBWriter.markItemRead(getActivity(), id, true); - } + DBWriter.markItemRead(getActivity(), true, checkedIds.toArray()); close(); } private void markedCheckedUnplayed() { - for(long id : checkedIds.toArray()) { - DBWriter.markItemRead(getActivity(), id, false); - } + DBWriter.markItemRead(getActivity(), false, checkedIds.toArray()); close(); } private void downloadChecked() { - FeedItem[] items = new FeedItem[checkedIds.size()]; - for(int i=0; i < checkedIds.size(); i++) { - long id = checkedIds.get(i); - items[i] = findById(id); + // download the check episodes in the same order as they are currently displayed + List toDownload = new ArrayList(checkedIds.size()); + for(FeedItem episode : episodes) { + if(checkedIds.contains(episode.getId())) { + toDownload.add(episode); + } } try { - DBTasks.downloadFeedItems(getActivity(), items); + DBTasks.downloadFeedItems(getActivity(), toDownload.toArray(new FeedItem[0])); } catch (DownloadRequestException e) { e.printStackTrace(); DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); -- cgit v1.2.3 From c7256d8152cf062c8e608b87e62f645ef2c72642 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Sun, 28 Jun 2015 21:53:40 +0200 Subject: Fix enqueueing order, prevent NPEs --- .../dialog/EpisodesApplyActionFragment.java | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'app/src/main/java/de/danoeh/antennapod/dialog') diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 25d27217b..1ca5b831c 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -1,6 +1,5 @@ package de.danoeh.antennapod.dialog; -import android.app.ProgressDialog; import android.content.res.TypedArray; import android.graphics.Color; import android.os.Bundle; @@ -26,7 +25,9 @@ import com.joanzapata.android.iconify.Iconify; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; @@ -49,6 +50,7 @@ public class EpisodesApplyActionFragment extends Fragment { private Button btnDownload; private Button btnDelete; + private final Map idMap; private final List episodes; private final List titles = new ArrayList(); private final LongList checkedIds = new LongList(); @@ -57,16 +59,17 @@ public class EpisodesApplyActionFragment extends Fragment { private int textColor; - private ProgressDialog pd; - public EpisodesApplyActionFragment(List episodes) { this.episodes = episodes; + this.idMap = new HashMap<>(episodes.size()); + for(FeedItem episode : episodes) { + this.idMap.put(episode.getId(), episode); + } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ActionBar bar = ((ActionBarActivity)getActivity()).getSupportActionBar(); setHasOptionsMenu(true); } @@ -278,14 +281,21 @@ public class EpisodesApplyActionFragment extends Fragment { Collections.sort(episodes, new Comparator() { @Override public int compare(FeedItem lhs, FeedItem rhs) { - int code = lhs.getMedia().getDuration() - rhs.getMedia().getDuration(); - if (reverse) { - return -1 * code; + int ordering; + if (false == lhs.hasMedia()) { + ordering = 1; + } else if (false == rhs.hasMedia()) { + ordering = -1; } else { - return code; + ordering = lhs.getMedia().getDuration() - rhs.getMedia().getDuration(); } + if(reverse) { + return -1 * ordering; + } else { + return ordering; } - }); + } + }); refreshTitles(); refreshCheckboxes(); } @@ -321,7 +331,7 @@ public class EpisodesApplyActionFragment extends Fragment { private void checkDownloaded(boolean isDownloaded) { for (FeedItem episode : episodes) { - if(episode.getMedia().isDownloaded() == isDownloaded) { + if(episode.hasMedia() && episode.getMedia().isDownloaded() == isDownloaded) { if(!checkedIds.contains(episode.getId())) { checkedIds.add(episode.getId()); } @@ -391,8 +401,10 @@ public class EpisodesApplyActionFragment extends Fragment { private void deleteChecked() { for(long id : checkedIds.toArray()) { - FeedItem episode = findById(id); - DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId()); + FeedItem episode = idMap.get(id); + if(episode.hasMedia()) { + DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId()); + } } close(); } @@ -401,14 +413,4 @@ public class EpisodesApplyActionFragment extends Fragment { getActivity().getSupportFragmentManager().popBackStack(); } - private FeedItem findById(long id) { - for(int i=0; i < episodes.size(); i++) { - FeedItem episode = episodes.get(i); - if(episode.getId() == id) { - return episode; - } - } - return null; - } - } -- cgit v1.2.3 From 936ecc2b8e7fc5a392ef8206fe773757821a8e95 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Tue, 30 Jun 2015 00:18:24 +0200 Subject: Nav drawer subscriptions context menu --- .../java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'app/src/main/java/de/danoeh/antennapod/dialog') diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 1ca5b831c..8a4a4efbf 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -5,8 +5,6 @@ import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -316,7 +314,7 @@ public class EpisodesApplyActionFragment extends Fragment { private void checkPlayed(boolean isPlayed) { for (FeedItem episode : episodes) { - if(episode.isRead() == isPlayed) { + if(episode.isPlayed() == isPlayed) { if(!checkedIds.contains(episode.getId())) { checkedIds.add(episode.getId()); } -- cgit v1.2.3 From f799ad5ed58391ff841b1c19366c6558e99411b4 Mon Sep 17 00:00:00 2001 From: Tom Hennen Date: Sun, 2 Aug 2015 18:27:36 -0400 Subject: Changed string names relating to time units. Android can handle plurals and strings having the same names, but Transifex can't. Renamed the time_unit*'s to just time_ to make sure we got the correct translations. --- app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/de/danoeh/antennapod/dialog') diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java index 6561d501e..5c4d4c430 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java @@ -39,9 +39,9 @@ public abstract class TimeDialog extends Dialog { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); - String[] spinnerContent = new String[]{context.getString(R.string.time_unit_seconds), - context.getString(R.string.time_unit_minutes), - context.getString(R.string.time_unit_hours)}; + String[] spinnerContent = new String[]{context.getString(R.string.time_seconds), + context.getString(R.string.time_minutes), + context.getString(R.string.time_hours)}; setContentView(R.layout.time_dialog); etxtTime = (EditText) findViewById(R.id.etxtTime); -- cgit v1.2.3