diff options
39 files changed, 524 insertions, 160 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d84bd79f1..887bea94d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -6,6 +6,7 @@ ligi ortylp LatinSuD wseemann +hzulla Translations: diff --git a/res/drawable-xhdpi/ic_undobar_undo.png b/res/drawable-xhdpi/ic_undobar_undo.png Binary files differnew file mode 100644 index 000000000..91c8429ad --- /dev/null +++ b/res/drawable-xhdpi/ic_undobar_undo.png diff --git a/res/drawable-xhdpi/undobar.9.png b/res/drawable-xhdpi/undobar.9.png Binary files differnew file mode 100644 index 000000000..22fa2205b --- /dev/null +++ b/res/drawable-xhdpi/undobar.9.png diff --git a/res/drawable-xhdpi/undobar_button_focused.9.png b/res/drawable-xhdpi/undobar_button_focused.9.png Binary files differnew file mode 100644 index 000000000..d284ca7cb --- /dev/null +++ b/res/drawable-xhdpi/undobar_button_focused.9.png diff --git a/res/drawable-xhdpi/undobar_button_pressed.9.png b/res/drawable-xhdpi/undobar_button_pressed.9.png Binary files differnew file mode 100644 index 000000000..e990659f0 --- /dev/null +++ b/res/drawable-xhdpi/undobar_button_pressed.9.png diff --git a/res/drawable-xhdpi/undobar_divider.9.png b/res/drawable-xhdpi/undobar_divider.9.png Binary files differnew file mode 100644 index 000000000..1b067d4e7 --- /dev/null +++ b/res/drawable-xhdpi/undobar_divider.9.png diff --git a/res/drawable/undobar_button.xml b/res/drawable/undobar_button.xml new file mode 100644 index 000000000..a4de91b49 --- /dev/null +++ b/res/drawable/undobar_button.xml @@ -0,0 +1,22 @@ +<!-- + + Copyright 2012 Roman Nurik + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/undobar_button_pressed" android:state_pressed="true"/> + <item android:drawable="@drawable/undobar_button_focused" android:state_focused="true"/> + <item android:drawable="@android:color/transparent"/> +</selector> diff --git a/res/layout/organize_queue.xml b/res/layout/organize_queue.xml index b73263632..62b2e980c 100644 --- a/res/layout/organize_queue.xml +++ b/res/layout/organize_queue.xml @@ -1,14 +1,12 @@ -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dslv="http://schemas.android.com/apk/res/de.danoeh.antennapod" android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" > + android:layout_height="fill_parent" > <com.mobeta.android.dslv.DragSortListView android:id="@android:id/list" android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" + android:layout_height="match_parent" dslv:collapsed_height="2dp" dslv:drag_enabled="true" dslv:drag_handle_id="@id/drag_handle" @@ -32,4 +30,9 @@ android:gravity="center" android:text="@string/no_items_label" /> -</LinearLayout>
\ No newline at end of file + <LinearLayout android:id="@+id/undobar" style="@style/UndoBar"> + <TextView android:id="@+id/undobar_message" style="@style/UndoBarMessage" /> + <Button android:id="@+id/undobar_button" style="@style/UndoBarButton" /> + </LinearLayout> + +</FrameLayout> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 6ef477546..eb15eea29 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">L\'emmagatzemament extern no està disponible. Assegureu-vos que està muntat per què l\'aplicació funcioni correctament.</string> <string name="chapters_label">Capítols</string> <string name="shownotes_label">Notes del programa</string> - <string name="last_update_prefix">Darrera actualització:\u0020</string> <string name="episodes_suffix">\u0020episodis</string> <string name="published_prefix">Publicat:\u0020</string> <string name="length_prefix">Durada:\u0020</string> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 02094b1b2..2e98a6e63 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Ingen ekstern harddisk er tilgængelig. Vær venlig at sørge for at den eksterne hukommelse er monteret så app\'en kan fungere korrekt.</string> <string name="chapters_label">Kapitler</string> <string name="shownotes_label">Afsnitsnoter</string> - <string name="last_update_prefix">Sidste opdateringer:\u0020</string> <string name="episodes_suffix">\u0020episoder</string> <string name="published_prefix">Offentliggjort:\u0020</string> <string name="length_prefix">Længde:\u0020</string> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 71236ef02..be723effe 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -32,7 +32,7 @@ <string name="external_storage_error_msg">Der externe Speicher ist nicht verfügbar. Bitte stelle sicher, dass das externe Speichermedium eingelegt ist, damit die App funktioniert.</string> <string name="chapters_label">Kapitel</string> <string name="shownotes_label">Notizen</string> - <string name="last_update_prefix">Letztes Update:\u0020</string> + <string name="most_recent_prefix">Letzte Episode:\u0020</string> <string name="episodes_suffix">\u0020Episoden</string> <string name="published_prefix">Veröffentlicht:\u0020</string> <string name="length_prefix">Länge:\u0020</string> diff --git a/res/values-es-rES/strings.xml b/res/values-es-rES/strings.xml index 31d088279..1eb829472 100644 --- a/res/values-es-rES/strings.xml +++ b/res/values-es-rES/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">No se encuentra un almacenamiento externo. Asegúrese de que su almacenamiento externo esté montado para que la aplicación funcione correctamente.</string> <string name="chapters_label">Capítulos</string> <string name="shownotes_label">Notas del programa</string> - <string name="last_update_prefix">Última actualización:\u0020</string> <string name="episodes_suffix">\u0020episodios</string> <string name="published_prefix">Publicado:\u0020</string> <string name="length_prefix">Duración:\u0020</string> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index f28453dcc..09ad122f5 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">No se encuentra un almacenamiento externo. Asegúrese de que su almacenamiento externo esté montado para que la aplicación funcione correctamente.</string> <string name="chapters_label">Capítulos</string> <string name="shownotes_label">Notas del programa</string> - <string name="last_update_prefix">Última actualización:\u0020</string> <string name="episodes_suffix">\u0020episodios</string> <string name="published_prefix">Publicado:\u0020</string> <string name="length_prefix">Duración:\u0020</string> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index e747fc625..02fb68388 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Aucun stockage externe n\'est disponible. Merci de connecter un volume de stockage externe pour que l\'application puisse fonctionner correctement.</string> <string name="chapters_label">Chapitres</string> <string name="shownotes_label">Notes d\'épisode</string> - <string name="last_update_prefix">Dernière mise à jour :\u0020</string> <string name="episodes_suffix">\u0020épisodes</string> <string name="published_prefix">Publié :\u0020</string> <string name="length_prefix">Durée :\u0020</string> diff --git a/res/values-it-rIT/strings.xml b/res/values-it-rIT/strings.xml index b664d20b5..96e0b0ca1 100644 --- a/res/values-it-rIT/strings.xml +++ b/res/values-it-rIT/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Non risulta disponibile lo spazio di archiviazione esterno. Assicurati che lo spazio di archiviazione sia montato per permettere all\'applicazione di funzionare correttamente.</string> <string name="chapters_label">Capitoli</string> <string name="shownotes_label">Note dell\'episodio</string> - <string name="last_update_prefix">Ultimo aggiornamento:\u0020</string> <string name="episodes_suffix">\u0020episodi</string> <string name="published_prefix">Pubblicato:\u0020</string> <string name="length_prefix">Durata:\u0020</string> diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index b5abb58bd..299e282ee 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Não há dispositivos de armazenamento disponíveis. Por favor, certifique-se de que um dispositivo de armazenamento externo está montado para que o aplicativo possa funcionar adequadamente.</string> <string name="chapters_label">Capítulos</string> <string name="shownotes_label">Notas do podcast</string> - <string name="last_update_prefix">Última atualização:\u0020</string> <string name="episodes_suffix">\u0020episódios</string> <string name="published_prefix">Publicado:\u0020</string> <string name="length_prefix">Duração:\u0020</string> diff --git a/res/values-ro-rRO/strings.xml b/res/values-ro-rRO/strings.xml index ba3c26827..d0bc9fdec 100644 --- a/res/values-ro-rRO/strings.xml +++ b/res/values-ro-rRO/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Nu exista stocare externă. Asigurați-vă că stocarea externă este conectată pentru ca aplicația să funcționeze corespunzător.</string> <string name="chapters_label">Capitole</string> <string name="shownotes_label">Notițe</string> - <string name="last_update_prefix">Ultima actualizare:\u0020</string> <string name="episodes_suffix">\u0020episoade</string> <string name="published_prefix">Publicat:\u0020</string> <string name="length_prefix">Durată:\u0020</string> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 6f9f165cf..eac5da4b1 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Внешний носитель данных недоступен. Убедитесь что внешний носитель смонтирован, иначе это приложение не сможет нормально работать.</string> <string name="chapters_label">Разделы</string> <string name="shownotes_label">Описание</string> - <string name="last_update_prefix">Последнее обновление:\u0020</string> <string name="episodes_suffix">\u0020 выпуск(ов)</string> <string name="published_prefix">Опубликовано:\u0020</string> <string name="length_prefix">Продолжительность:\u0020</string> diff --git a/res/values-uk-rUA/strings.xml b/res/values-uk-rUA/strings.xml index ccb65ab61..b2b6e7786 100644 --- a/res/values-uk-rUA/strings.xml +++ b/res/values-uk-rUA/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">Немає доступної флешки. Зовнішній носій потрібен для коректної роботи додатку</string> <string name="chapters_label">Глави</string> <string name="shownotes_label">Нотатки до епізода</string> - <string name="last_update_prefix">Останнє оновлення:\u0020</string> <string name="episodes_suffix">\u0020епізодів</string> <string name="published_prefix">Опубліковано:\u0020</string> <string name="length_prefix">Довжина:\u0020</string> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index d8c99b20a..5e2840536 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -32,7 +32,6 @@ <string name="external_storage_error_msg">没有可用的外部存储. 请确保安装外部存储器, 这样本应用才可以正常工作.</string> <string name="chapters_label">章节</string> <string name="shownotes_label">笔记</string> - <string name="last_update_prefix">最后更新:\u0020</string> <string name="episodes_suffix">\u0020 曲</string> <string name="published_prefix">发表:\u0020</string> <string name="length_prefix">长度:\u0020</string> diff --git a/res/values/arrays.xml b/res/values/arrays.xml index aebc74b33..4036ff0f4 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1,16 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <string-array name="update_intervall_options"> - <item>Manual</item> - <item>1 hour</item> - <item>2 hours</item> - <item>4 hours</item> - <item>8 hours</item> - <item>12 hours</item> - <item>24 hours</item> - </string-array> - <string-array name="update_intervall_values"> <item>0</item> <item>1</item> @@ -20,8 +10,17 @@ <item>12</item> <item>24</item> </string-array> - - <string-array name="episode_cache_size"> + <string-array name="episode_cache_size_entries"> + <item>@string/pref_episode_cache_unlimited</item> + <item>10</item> + <item>20</item> + <item>40</item> + <item>60</item> + <item>80</item> + <item>100</item> + </string-array> + <string-array name="episode_cache_size_values"> + <item>-1</item> <item>10</item> <item>20</item> <item>40</item> @@ -29,20 +28,16 @@ <item>80</item> <item>100</item> </string-array> - <string-array name="autodl_select_networks_default_entries"> <item>N/A</item> </string-array> - <string-array name="autodl_select_networks_default_values"> <item>0</item> </string-array> - <string-array name="theme_options"> - <item>Light</item> - <item>Dark</item> + <item>@string/pref_theme_title_light</item> + <item>@string/pref_theme_title_dark</item> </string-array> - <string-array name="theme_values"> <item>0</item> <item>1</item> diff --git a/res/values/integers.xml b/res/values/integers.xml new file mode 100644 index 000000000..33501d9fb --- /dev/null +++ b/res/values/integers.xml @@ -0,0 +1,4 @@ +<resources> + <integer name="undobar_hide_delay">5000</integer> + <integer name="episode_cache_size_unlimited">-1</integer> +</resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index 5bc40db54..b79c561f4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -36,7 +36,7 @@ <string name="external_storage_error_msg">No external storage is available. Please make sure that external storage is mounted so that the app can work properly.</string> <string name="chapters_label">Chapters</string> <string name="shownotes_label">Shownotes</string> - <string name="last_update_prefix">Last Update:\u0020</string> + <string name="most_recent_prefix">Most Recent Episode:\u0020</string> <string name="episodes_suffix">\u0020episodes</string> <string name="published_prefix">Published:\u0020</string> <string name="length_prefix">Length:\u0020</string> @@ -122,6 +122,8 @@ <!-- Queue operations --> <string name="clear_queue_label">Clear queue</string> <string name="organize_queue_label">Organize queue</string> + <string name="undo">Undo</string> + <string name="removed_from_queue">Item removed</string> <!-- Flattr --> <string name="flattr_auth_label">Flattr sign-in</string> @@ -177,6 +179,13 @@ <string name="pref_autodl_wifi_filter_title">Enable Wi-Fi filter</string> <string name="pref_autodl_wifi_filter_sum">Allow automatic download only for selected Wi-Fi networks.</string> <string name="pref_episode_cache_title">Episode cache</string> + <string name="pref_theme_title_light">Light</string> + <string name="pref_theme_title_dark">Dark</string> + <string name="pref_episode_cache_unlimited">Unlimited</string> + <string name="pref_update_interval_hours_plural">hours</string> + <string name="pref_update_interval_hours_singular">hour</string> + <string name="pref_update_interval_hours_manual">Manual</string> + <!-- Search --> <string name="search_hint">Search for Feeds or Episodes</string> diff --git a/res/values/styles.xml b/res/values/styles.xml index c5e3abde3..f32ea3894 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -92,4 +92,42 @@ <item name="android:textColor">#FFFFFF</item> </style> -</resources>
\ No newline at end of file + <style name="UndoBar"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">48dp</item> + <item name="android:layout_gravity">bottom</item> + <item name="android:layout_marginLeft">8dp</item> + <item name="android:layout_marginRight">8dp</item> + <item name="android:layout_marginBottom">16dp</item> + <item name="android:orientation">horizontal</item> + <item name="android:background">@drawable/undobar</item> + <item name="android:clickable">true</item> + <item name="android:showDividers">middle</item> + <item name="android:divider">@drawable/undobar_divider</item> + <item name="android:dividerPadding">10dp</item> + </style> + <style name="UndoBarMessage"> + <item name="android:layout_width">0dp</item> + <item name="android:layout_weight">1</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_marginLeft">16dp</item> + <item name="android:layout_gravity">center_vertical</item> + <item name="android:layout_marginRight">16dp</item> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:textColor">#fff</item> + </style> + <style name="UndoBarButton"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">match_parent</item> + <item name="android:paddingLeft">16dp</item> + <item name="android:paddingRight">16dp</item> + <item name="android:background">@drawable/undobar_button</item> + <item name="android:drawableLeft">@drawable/ic_undobar_undo</item> + <item name="android:drawablePadding">12dp</item> + <item name="android:textAppearance">?android:textAppearanceSmall</item> + <item name="android:textAllCaps">true</item> + <item name="android:textStyle">bold</item> + <item name="android:textColor">#fff</item> + <item name="android:text">@string/undo</item> + </style> +</resources> diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index dfa67d4f9..e94d1c47e 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -22,7 +22,7 @@ <PreferenceCategory android:title="@string/network_pref" > <ListPreference android:defaultValue="0" - android:entries="@array/update_intervall_options" + android:entries="@array/update_intervall_values" android:entryValues="@array/update_intervall_values" android:key="prefAutoUpdateIntervall" android:summary="@string/pref_autoUpdateIntervall_sum" @@ -34,7 +34,7 @@ android:key="prefMobileUpdate" android:summary="@string/pref_mobileUpdate_sum" android:title="@string/pref_mobileUpdate_title" /> - <ListPreference android:defaultValue="20" android:entries="@array/episode_cache_size" android:key="prefEpisodeCacheSize" android:title="@string/pref_episode_cache_title" android:entryValues="@array/episode_cache_size"/><PreferenceScreen android:summary="@string/pref_automatic_download_sum" android:key="prefAutoDownloadSettings" android:title="@string/pref_automatic_download_title"> + <ListPreference android:defaultValue="20" android:entries="@array/episode_cache_size_entries" android:key="prefEpisodeCacheSize" android:title="@string/pref_episode_cache_title" android:entryValues="@array/episode_cache_size_values"/><PreferenceScreen android:summary="@string/pref_automatic_download_sum" android:key="prefAutoDownloadSettings" android:title="@string/pref_automatic_download_title"> <CheckBoxPreference android:key="prefEnableAutoDl" android:title="@string/pref_automatic_download_title" android:defaultValue="false"/><CheckBoxPreference android:key="prefEnableAutoDownloadWifiFilter" android:title="@string/pref_autodl_wifi_filter_title" android:summary="@string/pref_autodl_wifi_filter_sum"/> </PreferenceScreen> diff --git a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java index 89001f7f5..7269f7549 100644 --- a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java +++ b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java @@ -3,6 +3,8 @@ package de.danoeh.antennapod.activity; import android.content.Context; import android.content.res.TypedArray; import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -21,19 +23,23 @@ import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedManager; import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.util.UndoBarController; -public class OrganizeQueueActivity extends SherlockListActivity { +public class OrganizeQueueActivity extends SherlockListActivity implements + UndoBarController.UndoListener { private static final String TAG = "OrganizeQueueActivity"; private static final int MENU_ID_ACCEPT = 2; private OrganizeAdapter adapter; + private UndoBarController undoBarController; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); super.onCreate(savedInstanceState); setContentView(R.layout.organize_queue); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); DragSortListView listView = (DragSortListView) getListView(); listView.setDropListener(dropListener); @@ -41,6 +47,9 @@ public class OrganizeQueueActivity extends SherlockListActivity { adapter = new OrganizeAdapter(this); setListAdapter(adapter); + + undoBarController = new UndoBarController(findViewById(R.id.undobar), + this); } @Override @@ -50,6 +59,13 @@ public class OrganizeQueueActivity extends SherlockListActivity { } @Override + protected void onStop() { + super.onStop(); + FeedManager.getInstance().autodownloadUndownloadedItems( + getApplicationContext()); + } + + @Override protected void onResume() { super.onResume(); EventDistributor.getInstance().register(contentUpdate); @@ -82,27 +98,24 @@ public class OrganizeQueueActivity extends SherlockListActivity { @Override public void remove(int which) { FeedManager manager = FeedManager.getInstance(); - manager.removeQueueItem(OrganizeQueueActivity.this, - (FeedItem) getListAdapter().getItem(which)); + FeedItem item = (FeedItem) getListAdapter().getItem(which); + manager.removeQueueItem(OrganizeQueueActivity.this, item, false); + undoBarController.showUndoBar(false, + getString(R.string.removed_from_queue), new UndoToken(item, + which)); } }; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - TypedArray drawables = obtainStyledAttributes(new int[] { R.attr.navigation_accept }); - menu.add(Menu.NONE, MENU_ID_ACCEPT, Menu.NONE, R.string.confirm_label) - .setIcon(drawables.getDrawable(0)) - .setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM - | MenuItem.SHOW_AS_ACTION_WITH_TEXT); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_ID_ACCEPT: + case android.R.id.home: finish(); return true; default: @@ -110,11 +123,18 @@ public class OrganizeQueueActivity extends SherlockListActivity { } } - /** - * WARNING: If the PlaybackService is playing an episode from the queue, - * this list adapter will ignore the first item in the list to make sure - * that the position of the first queue item cannot be changed. - */ + @Override + public void onUndo(Parcelable token) { + // Perform the undo + UndoToken undoToken = (UndoToken) token; + FeedItem feedItem = undoToken.getFeedItem(); + int position = undoToken.getPosition(); + + FeedManager manager = FeedManager.getInstance(); + manager.addQueueItemAt(OrganizeQueueActivity.this, feedItem, position, + false); + } + private static class OrganizeAdapter extends BaseAdapter { private Context context; @@ -185,4 +205,52 @@ public class OrganizeQueueActivity extends SherlockListActivity { } + private static class UndoToken implements Parcelable { + private long itemId; + private long feedId; + private int position; + + public UndoToken(FeedItem item, int position) { + FeedManager manager = FeedManager.getInstance(); + this.itemId = item.getId(); + this.feedId = item.getFeed().getId(); + this.position = position; + } + + private UndoToken(Parcel in) { + itemId = in.readLong(); + feedId = in.readLong(); + position = in.readInt(); + } + + public static final Parcelable.Creator<UndoToken> CREATOR = new Parcelable.Creator<UndoToken>() { + public UndoToken createFromParcel(Parcel in) { + return new UndoToken(in); + } + + public UndoToken[] newArray(int size) { + return new UndoToken[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + out.writeLong(itemId); + out.writeLong(feedId); + out.writeInt(position); + } + + public FeedItem getFeedItem() { + FeedManager manager = FeedManager.getInstance(); + return manager.getFeedItem(itemId, feedId); + } + + public int getPosition() { + return position; + } + } + } diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java index 994cd2df6..9fcf57ac2 100644 --- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -12,6 +12,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; @@ -166,13 +167,40 @@ public class PreferenceActivity extends SherlockPreferenceActivity { return true; } }); - + buildUpdateIntervalPreference(); buildAutodownloadSelectedNetworsPreference(); setSelectedNetworksEnabled(UserPreferences .isEnableAutodownloadWifiFilter()); } + private void buildUpdateIntervalPreference() { + ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_UPDATE_INTERVAL); + String[] values = getResources().getStringArray( + R.array.update_intervall_values); + String[] entries = new String[values.length]; + for (int x = 0; x < values.length; x++) { + Integer v = Integer.parseInt(values[x]); + switch (v) { + case 0: + entries[x] = getString(R.string.pref_update_interval_hours_manual); + break; + case 1: + entries[x] = v + + " " + + getString(R.string.pref_update_interval_hours_singular); + break; + default: + entries[x] = v + " " + + getString(R.string.pref_update_interval_hours_plural); + break; + + } + } + pref.setEntries(entries); + + } + private void setSelectedNetworksEnabled(boolean b) { if (selectedNetworks != null) { for (Preference p : selectedNetworks) { @@ -205,9 +233,15 @@ public class PreferenceActivity extends SherlockPreferenceActivity { } private void setEpisodeCacheSizeText(int cacheSize) { - findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary( - Integer.toString(cacheSize) - + getString(R.string.episodes_suffix)); + String s; + if (cacheSize == getResources().getInteger( + R.integer.episode_cache_size_unlimited)) { + s = getString(R.string.pref_episode_cache_unlimited); + } else { + s = Integer.toString(cacheSize) + + getString(R.string.episodes_suffix); + } + findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(s); } private void setDataFolderText() { diff --git a/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java index b603bb54f..2b49795c3 100644 --- a/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/DefaultFeedItemlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.text.DateFormat; - import android.content.Context; import android.content.res.TypedArray; import android.text.format.DateUtils; @@ -75,10 +73,9 @@ public class DefaultFeedItemlistAdapter extends BaseAdapter { holder.title.setText(item.getTitle()); holder.published.setText(convertView.getResources().getString( R.string.published_prefix) - + DateUtils.formatSameDayTime(item.getPubDate().getTime(), - System.currentTimeMillis(), DateFormat.MEDIUM, - DateFormat.SHORT)); - + + DateUtils.getRelativeTimeSpanString( + item.getPubDate().getTime(), + System.currentTimeMillis(), 0, 0)); if (item.getMedia() == null) { holder.type.setVisibility(View.GONE); holder.lenSize.setVisibility(View.GONE); diff --git a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java index c0ccdc7fe..f97210cf3 100644 --- a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.text.DateFormat; - import android.content.Context; import android.text.format.DateUtils; import android.view.LayoutInflater; @@ -60,9 +58,9 @@ public class DownloadLogAdapter extends BaseAdapter { } else { holder.title.setText(R.string.download_log_title_unknown); } - holder.date.setText(DateUtils.formatSameDayTime(status - .getCompletionDate().getTime(), System.currentTimeMillis(), - DateFormat.SHORT, DateFormat.SHORT)); + holder.date.setText(DateUtils.getRelativeTimeSpanString( + status.getCompletionDate().getTime(), + System.currentTimeMillis(), 0, 0)); if (status.isSuccessful()) { holder.successful.setTextColor(convertView.getResources().getColor( R.color.download_success_green)); diff --git a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java index d7ea0c160..03b46cce5 100644 --- a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.text.DateFormat; - import android.content.Context; import android.text.format.DateUtils; import android.view.LayoutInflater; @@ -77,16 +75,21 @@ public class FeedlistAdapter extends BaseAdapter { } holder.title.setText(feed.getTitle()); + int numOfItems = feed.getNumOfItems(true); if (DownloadRequester.getInstance().isDownloadingFile(feed)) { holder.lastUpdate.setText(R.string.refreshing_label); } else { - holder.lastUpdate.setText(convertView.getResources().getString( - R.string.last_update_prefix) - + DateUtils.formatSameDayTime(feed.getLastUpdate() - .getTime(), System.currentTimeMillis(), - DateFormat.MEDIUM, DateFormat.SHORT)); + if (numOfItems > 0) { + holder.lastUpdate.setText(convertView.getResources().getString( + R.string.most_recent_prefix) + + DateUtils.getRelativeTimeSpanString( + feed.getItemAtIndex(true, 0).getPubDate().getTime(), + System.currentTimeMillis(), 0, 0)); + } else { + holder.lastUpdate.setText(""); + } } - holder.numberOfEpisodes.setText(feed.getNumOfItems(true) + holder.numberOfEpisodes.setText(numOfItems + convertView.getResources() .getString(R.string.episodes_suffix)); diff --git a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java index 7b898385e..e5c12f018 100644 --- a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.text.DateFormat; - import android.content.Context; import android.content.res.TypedArray; import android.text.format.DateUtils; @@ -122,9 +120,9 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { holder.published.setText(convertView.getResources().getString( R.string.published_prefix) - + DateUtils.formatSameDayTime(item.getPubDate().getTime(), - System.currentTimeMillis(), DateFormat.MEDIUM, - DateFormat.SHORT)); + + DateUtils.getRelativeTimeSpanString( + item.getPubDate().getTime(), + System.currentTimeMillis(), 0, 0)); FeedMedia media = item.getMedia(); if (media == null) { diff --git a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java index 4cee0a64a..f12345f84 100644 --- a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java @@ -1,6 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.text.DateFormat; import java.util.List; import android.content.Context; @@ -42,9 +41,8 @@ public class MiroGuideItemlistAdapter extends ArrayAdapter<MiroGuideItem> { holder.title.setText(item.getName()); if (item.getDate() != null) { - holder.date.setText(DateUtils.formatSameDayTime(item.getDate() - .getTime(), System.currentTimeMillis(), DateFormat.SHORT, - DateFormat.SHORT)); + holder.date.setText(DateUtils.getRelativeTimeSpanString( + item.getDate().getTime(), System.currentTimeMillis(), 0, 0)); holder.date.setVisibility(View.VISIBLE); } else { holder.date.setVisibility(View.GONE); diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index bdffdc667..a1a8c6c32 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; +import java.util.Comparator; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -676,8 +677,12 @@ public class FeedManager { int deletedEpisodes = performAutoCleanup(context, getPerformAutoCleanupArgs(undownloadedEpisodes)); int episodeSpaceLeft = undownloadedEpisodes; - if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes - + undownloadedEpisodes) { + boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences + .getEpisodeCacheSizeUnlimited(); + + if (!cacheIsUnlimited + && UserPreferences.getEpisodeCacheSize() < downloadedEpisodes + + undownloadedEpisodes) { episodeSpaceLeft = UserPreferences.getEpisodeCacheSize() - (downloadedEpisodes - deletedEpisodes); } @@ -732,7 +737,9 @@ public class FeedManager { * that the number of episodes fits into the episode cache. * */ private int getPerformAutoCleanupArgs(final int episodeNumber) { - if (episodeNumber >= 0) { + if (episodeNumber >= 0 + && UserPreferences.getEpisodeCacheSize() != UserPreferences + .getEpisodeCacheSizeUnlimited()) { int downloadedEpisodes = getNumberOfDownloadedEpisodes(); if (downloadedEpisodes + episodeNumber >= UserPreferences .getEpisodeCacheSize()) { @@ -760,24 +767,45 @@ public class FeedManager { * @return The number of episodes that were actually deleted * */ private int performAutoCleanup(Context context, final int episodeNumber) { - int counter = 0; - if (episodeNumber > 0) { - int episodesLeft = episodeNumber; - feedloop: for (Feed feed : feeds) { - for (FeedItem item : feed.getItems()) { - if (item.hasMedia() && item.getMedia().isDownloaded()) { - if (!isInQueue(item) && item.isRead()) { - deleteFeedMedia(context, item.getMedia()); - counter++; - episodesLeft--; - if (episodesLeft == 0) { - break feedloop; - } - } - } + List<FeedItem> candidates = new ArrayList<FeedItem>(); + List<FeedItem> delete; + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + if (item.hasMedia() && item.getMedia().isDownloaded() + && !isInQueue(item) && item.isRead()) { + candidates.add(item); } } } + + Collections.sort(candidates, new Comparator<FeedItem>() { + @Override + public int compare(FeedItem lhs, FeedItem rhs) { + Date l = lhs.getMedia().getPlaybackCompletionDate(); + Date r = rhs.getMedia().getPlaybackCompletionDate(); + + if (l == null) { + l = new Date(0); + } + if (r == null) { + r = new Date(0); + } + return l.compareTo(r); + } + }); + + if (candidates.size() > episodeNumber) { + delete = candidates.subList(0, episodeNumber); + } else { + delete = candidates; + } + + for (FeedItem item : delete) { + deleteFeedMedia(context, item.getMedia()); + } + + int counter = delete.size(); + if (AppConfig.DEBUG) Log.d(TAG, String.format( "Auto-delete deleted %d episodes (%d requested)", counter, @@ -970,7 +998,8 @@ public class FeedManager { } /** Removes a FeedItem from the queue. */ - public void removeQueueItem(final Context context, FeedItem item) { + public void removeQueueItem(final Context context, FeedItem item, + final boolean performAutoDownload) { boolean removed = queue.remove(item); if (removed) { dbExec.execute(new Runnable() { @@ -985,12 +1014,14 @@ public class FeedManager { }); } - new Thread() { - @Override - public void run() { - autodownloadUndownloadedItems(context); - } - }.start(); + if (performAutoDownload) { + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); + } eventDist.sendQueueUpdateBroadcast(); } @@ -1980,4 +2011,4 @@ public class FeedManager { } } -}
\ No newline at end of file +} diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index a1dfa51d4..10f43718f 100644 --- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.TypedArray; -import android.graphics.Picture; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -23,10 +22,9 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.webkit.WebChromeClient; import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebView; -import android.webkit.WebView.PictureListener; +import android.webkit.WebViewClient; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragment; @@ -101,7 +99,6 @@ public class ItemDescriptionFragment extends SherlockFragment { if (AppConfig.DEBUG) Log.d(TAG, "Creating view"); webvDescription = new WebView(getActivity()); - if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { @@ -115,6 +112,32 @@ public class ItemDescriptionFragment extends SherlockFragment { LayoutAlgorithm.NARROW_COLUMNS); webvDescription.getSettings().setLoadWithOverviewMode(true); webvDescription.setOnLongClickListener(webViewLongClickListener); + webvDescription.setWebViewClient(new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + return true; + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + if (AppConfig.DEBUG) + Log.d(TAG, "Page finished"); + // Restoring the scroll position might not always work + view.postDelayed(new Runnable() { + + @Override + public void run() { + restoreFromPreference(); + } + + }, 50); + } + + }); registerForContextMenu(webvDescription); return webvDescription; } @@ -336,7 +359,6 @@ public class ItemDescriptionFragment extends SherlockFragment { String data; - @SuppressWarnings("deprecation") @Override protected void onPostExecute(Void result) { super.onPostExecute(result); @@ -350,16 +372,6 @@ public class ItemDescriptionFragment extends SherlockFragment { if (AppConfig.DEBUG) Log.d(TAG, "Webview loaded"); webViewLoader = null; - webvDescription.setPictureListener(new PictureListener() { - - @Override - @Deprecated - public void onNewPicture(WebView view, Picture picture) { - restoreFromPreference(); - - } - }); - } @Override @@ -434,17 +446,21 @@ public class ItemDescriptionFragment extends SherlockFragment { if (saveState) { if (AppConfig.DEBUG) Log.d(TAG, "Restoring from preferences"); - SharedPreferences prefs = getActivity().getSharedPreferences(PREF, - Activity.MODE_PRIVATE); - String id = prefs.getString(PREF_PLAYABLE_ID, ""); - int scrollY = prefs.getInt(PREF_SCROLL_Y, -1); - if (scrollY != -1 && media != null - && id.equals(media.getIdentifier().toString()) - && webvDescription != null) { - if (AppConfig.DEBUG) - Log.d(TAG, "Restored scroll Position: " + scrollY); - webvDescription.scrollTo(webvDescription.getScrollX(), scrollY); - return true; + Activity activity = getActivity(); + if (activity != null) { + SharedPreferences prefs = activity.getSharedPreferences( + PREF, Activity.MODE_PRIVATE); + String id = prefs.getString(PREF_PLAYABLE_ID, ""); + int scrollY = prefs.getInt(PREF_SCROLL_Y, -1); + if (scrollY != -1 && media != null + && id.equals(media.getIdentifier().toString()) + && webvDescription != null) { + if (AppConfig.DEBUG) + Log.d(TAG, "Restored scroll Position: " + scrollY); + webvDescription.scrollTo(webvDescription.getScrollX(), + scrollY); + return true; + } } } return false; diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index bd491a5cf..f2f35f41d 100644 --- a/src/de/danoeh/antennapod/preferences/UserPreferences.java +++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java @@ -42,6 +42,8 @@ public class UserPreferences implements private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks"; public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize"; + private static int EPISODE_CACHE_SIZE_UNLIMITED = -1; + private static UserPreferences instance; private Context context; @@ -86,6 +88,8 @@ public class UserPreferences implements private void loadPreferences() { SharedPreferences sp = PreferenceManager .getDefaultSharedPreferences(context); + EPISODE_CACHE_SIZE_UNLIMITED = context.getResources().getInteger( + R.integer.episode_cache_size_unlimited); pauseOnHeadsetDisconnect = sp.getBoolean( PREF_PAUSE_ON_HEADSET_DISCONNECT, true); followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false); @@ -101,7 +105,7 @@ public class UserPreferences implements PREF_ENABLE_AUTODL_WIFI_FILTER, false); autodownloadSelectedNetworks = StringUtils.split( sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ','); - episodeCacheSize = Integer.valueOf(sp.getString( + episodeCacheSize = readEpisodeCacheSize(sp.getString( PREF_EPISODE_CACHE_SIZE, "20")); enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false); } @@ -122,6 +126,15 @@ public class UserPreferences implements return TimeUnit.HOURS.toMillis(hours); } + private int readEpisodeCacheSize(String valueFromPrefs) { + if (valueFromPrefs.equals(context + .getString(R.string.pref_episode_cache_unlimited))) { + return EPISODE_CACHE_SIZE_UNLIMITED; + } else { + return Integer.valueOf(valueFromPrefs); + } + } + private static void instanceAvailable() { if (instance == null) { throw new IllegalStateException( @@ -179,6 +192,15 @@ public class UserPreferences implements return instance.autodownloadSelectedNetworks; } + public static int getEpisodeCacheSizeUnlimited() { + return EPISODE_CACHE_SIZE_UNLIMITED; + } + + /** + * Returns the capacity of the episode cache. This method will return the + * negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to + * 'unlimited'. + */ public static int getEpisodeCacheSize() { instanceAvailable(); return instance.episodeCacheSize; @@ -224,7 +246,7 @@ public class UserPreferences implements autodownloadSelectedNetworks = StringUtils.split( sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ','); } else if (key.equals(PREF_EPISODE_CACHE_SIZE)) { - episodeCacheSize = Integer.valueOf(sp.getString( + episodeCacheSize = readEpisodeCacheSize(sp.getString( PREF_EPISODE_CACHE_SIZE, "20")); } else if (key.equals(PREF_ENABLE_AUTODL)) { enableAutodownload = sp.getBoolean(PREF_ENABLE_AUTODL, false); diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index 11da79015..409ac6b48 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -73,8 +73,8 @@ public class PlaybackService extends Service { public static final String EXTRA_PREPARE_IMMEDIATELY = "extra.de.danoeh.antennapod.service.prepareImmediately"; public static final String ACTION_PLAYER_STATUS_CHANGED = "action.de.danoeh.antennapod.service.playerStatusChanged"; - private static final String AVRCP_ACTION_PLAYER_STATUS_CHANGED= "com.android.music.playstatechanged"; - + private static final String AVRCP_ACTION_PLAYER_STATUS_CHANGED = "com.android.music.playstatechanged"; + public static final String ACTION_PLAYER_NOTIFICATION = "action.de.danoeh.antennapod.service.playerNotification"; public static final String EXTRA_NOTIFICATION_CODE = "extra.de.danoeh.antennapod.service.notificationCode"; public static final String EXTRA_NOTIFICATION_TYPE = "extra.de.danoeh.antennapod.service.notificationType"; @@ -363,13 +363,15 @@ public class PlaybackService extends Service { } // Intent values appear to be valid // check if already playing and playbackType is the same - } else if (media == null || playable != media + } else if (media == null + || !playable.getIdentifier().equals(media.getIdentifier()) || playbackType != shouldStream) { pause(true, false); player.reset(); sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0); if (media == null - || playable.getIdentifier() != media.getIdentifier()) { + || !playable.getIdentifier().equals( + media.getIdentifier())) { media = playable; } @@ -730,7 +732,7 @@ public class PlaybackService extends Service { isInQueue = media instanceof FeedMedia && manager.isInQueue(((FeedMedia) media).getItem()); if (isInQueue) { - manager.removeQueueItem(PlaybackService.this, item); + manager.removeQueueItem(PlaybackService.this, item, true); } manager.addItemToPlaybackHistory(PlaybackService.this, item); manager.setFeedMedia(PlaybackService.this, (FeedMedia) media); @@ -1226,23 +1228,23 @@ public class PlaybackService extends Service { private void bluetoothNotifyChange() { boolean isPlaying = false; - + if (status == PlayerStatus.PLAYING) { isPlaying = true; } - - Intent i = new Intent(AVRCP_ACTION_PLAYER_STATUS_CHANGED); - i.putExtra("id", 1); - i.putExtra("artist", ""); - i.putExtra("album", media.getFeedTitle()); - i.putExtra("track", media.getEpisodeTitle()); - i.putExtra("playing", isPlaying); - i.putExtra("ListSize", manager.getQueueSize(false)); - i.putExtra("duration", media.getDuration()); - i.putExtra("position", media.getPosition()); - sendBroadcast(i); + + Intent i = new Intent(AVRCP_ACTION_PLAYER_STATUS_CHANGED); + i.putExtra("id", 1); + i.putExtra("artist", ""); + i.putExtra("album", media.getFeedTitle()); + i.putExtra("track", media.getEpisodeTitle()); + i.putExtra("playing", isPlaying); + i.putExtra("ListSize", manager.getQueueSize(false)); + i.putExtra("duration", media.getDuration()); + i.putExtra("position", media.getPosition()); + sendBroadcast(i); } - + /** * Pauses playback when the headset is disconnected and the preference is * set diff --git a/src/de/danoeh/antennapod/util/Converter.java b/src/de/danoeh/antennapod/util/Converter.java index f02e8ea69..6ef47af31 100644 --- a/src/de/danoeh/antennapod/util/Converter.java +++ b/src/de/danoeh/antennapod/util/Converter.java @@ -78,4 +78,5 @@ public final class Converter { return String.format("%02d:%02d", h, m); } + } diff --git a/src/de/danoeh/antennapod/util/UndoBarController.java b/src/de/danoeh/antennapod/util/UndoBarController.java new file mode 100644 index 000000000..e726717a1 --- /dev/null +++ b/src/de/danoeh/antennapod/util/UndoBarController.java @@ -0,0 +1,135 @@ +/* + * Copyright 2012 Roman Nurik + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.danoeh.antennapod.util; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.os.Bundle; +import android.os.Handler; +import android.os.Parcelable; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewPropertyAnimator; +import android.widget.TextView; + +import de.danoeh.antennapod.R; + +public class UndoBarController { + private View mBarView; + private TextView mMessageView; + private ViewPropertyAnimator mBarAnimator; + private Handler mHideHandler = new Handler(); + + private UndoListener mUndoListener; + + // State objects + private Parcelable mUndoToken; + private CharSequence mUndoMessage; + + public interface UndoListener { + void onUndo(Parcelable token); + } + + public UndoBarController(View undoBarView, UndoListener undoListener) { + mBarView = undoBarView; + mBarAnimator = mBarView.animate(); + mUndoListener = undoListener; + + mMessageView = (TextView) mBarView.findViewById(R.id.undobar_message); + mBarView.findViewById(R.id.undobar_button) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + hideUndoBar(false); + mUndoListener.onUndo(mUndoToken); + } + }); + + hideUndoBar(true); + } + + public void showUndoBar(boolean immediate, CharSequence message, Parcelable undoToken) { + mUndoToken = undoToken; + mUndoMessage = message; + mMessageView.setText(mUndoMessage); + + mHideHandler.removeCallbacks(mHideRunnable); + mHideHandler.postDelayed(mHideRunnable, + mBarView.getResources().getInteger(R.integer.undobar_hide_delay)); + + mBarView.setVisibility(View.VISIBLE); + if (immediate) { + mBarView.setAlpha(1); + } else { + mBarAnimator.cancel(); + mBarAnimator + .alpha(1) + .setDuration( + mBarView.getResources() + .getInteger(android.R.integer.config_shortAnimTime)) + .setListener(null); + } + } + + public void hideUndoBar(boolean immediate) { + mHideHandler.removeCallbacks(mHideRunnable); + if (immediate) { + mBarView.setVisibility(View.GONE); + mBarView.setAlpha(0); + mUndoMessage = null; + mUndoToken = null; + + } else { + mBarAnimator.cancel(); + mBarAnimator + .alpha(0) + .setDuration(mBarView.getResources() + .getInteger(android.R.integer.config_shortAnimTime)) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mBarView.setVisibility(View.GONE); + mUndoMessage = null; + mUndoToken = null; + } + }); + } + } + + public void onSaveInstanceState(Bundle outState) { + outState.putCharSequence("undo_message", mUndoMessage); + outState.putParcelable("undo_token", mUndoToken); + } + + public void onRestoreInstanceState(Bundle savedInstanceState) { + if (savedInstanceState != null) { + mUndoMessage = savedInstanceState.getCharSequence("undo_message"); + mUndoToken = savedInstanceState.getParcelable("undo_token"); + + if (mUndoToken != null || !TextUtils.isEmpty(mUndoMessage)) { + showUndoBar(true, mUndoMessage, mUndoToken); + } + } + } + + private Runnable mHideRunnable = new Runnable() { + @Override + public void run() { + hideUndoBar(false); + } + }; +} diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index 64bcb1cf2..472124bf7 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -140,7 +140,7 @@ public class FeedItemMenuHandler { manager.addQueueItem(context, selectedItem); break; case R.id.remove_from_queue_item: - manager.removeQueueItem(context, selectedItem); + manager.removeQueueItem(context, selectedItem, true); break; case R.id.stream_item: manager.playMedia(context, selectedItem.getMedia(), true, true, |