diff options
Diffstat (limited to 'src/de/danoeh/antennapod/activity')
9 files changed, 1081 insertions, 214 deletions
diff --git a/src/de/danoeh/antennapod/activity/AddFeedActivity.java b/src/de/danoeh/antennapod/activity/AddFeedActivity.java index 4085fc8d2..ad1adfa6b 100644 --- a/src/de/danoeh/antennapod/activity/AddFeedActivity.java +++ b/src/de/danoeh/antennapod/activity/AddFeedActivity.java @@ -5,6 +5,7 @@ import java.util.Date; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; +import de.danoeh.antennapod.activity.gpoddernet.GpodnetMainActivity; import org.apache.commons.lang3.StringUtils; import android.app.AlertDialog; @@ -37,6 +38,7 @@ public class AddFeedActivity extends ActionBarActivity { private EditText etxtFeedurl; private Button butBrowseMiroGuide; + private Button butBrowserGpoddernet; private Button butOpmlImport; private Button butConfirm; private Button butCancel; @@ -63,6 +65,7 @@ public class AddFeedActivity extends ActionBarActivity { } butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide); + butBrowserGpoddernet = (Button) findViewById(R.id.butBrowseGpoddernet); butOpmlImport = (Button) findViewById(R.id.butOpmlImport); butConfirm = (Button) findViewById(R.id.butConfirm); butCancel = (Button) findViewById(R.id.butCancel); @@ -75,6 +78,13 @@ public class AddFeedActivity extends ActionBarActivity { MiroGuideMainActivity.class)); } }); + butBrowserGpoddernet.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(AddFeedActivity.this, + GpodnetMainActivity.class)); + } + }); butOpmlImport.setOnClickListener(new OnClickListener() { diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java new file mode 100644 index 000000000..bb56b1d12 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -0,0 +1,164 @@ +package de.danoeh.antennapod.activity; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.NavUtils; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter; +import de.danoeh.antennapod.asynctask.ImageDiskCache; +import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.feed.EventDistributor; +import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DownloadRequestException; +import de.danoeh.antennapod.storage.DownloadRequester; + +import java.util.Date; +import java.util.List; + +/** + * Created by daniel on 24.08.13. + */ +public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { + + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE; + private volatile List<Feed> feeds; + private Feed feed; + + private Button subscribeButton; + + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void loadData() { + super.loadData(); + feeds = DBReader.getFeedList(this); + } + + @Override + protected void showFeedInformation(final Feed feed) { + super.showFeedInformation(feed); + setContentView(R.layout.listview_activity); + + this.feed = feed; + EventDistributor.getInstance().register(listener); + ListView listView = (ListView) findViewById(R.id.listview); + LayoutInflater inflater = (LayoutInflater) + getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View header = inflater.inflate(R.layout.onlinefeedview_header, null); + listView.addHeaderView(header); + + listView.setAdapter(new FeedItemlistDescriptionAdapter(this, 0, feed.getItems())); + + ImageView cover = (ImageView) header.findViewById(R.id.imgvCover); + TextView title = (TextView) header.findViewById(R.id.txtvTitle); + TextView author = (TextView) header.findViewById(R.id.txtvAuthor); + TextView description = (TextView) header.findViewById(R.id.txtvDescription); + subscribeButton = (Button) header.findViewById(R.id.butSubscribe); + + if (feed.getImage() != null) { + ImageDiskCache.getDefaultInstance().loadThumbnailBitmap(feed.getImage().getDownload_url(), cover, (int) getResources().getDimension( + R.dimen.thumbnail_length)); + } + title.setText(feed.getTitle()); + author.setText(feed.getAuthor()); + description.setText(feed.getDescription()); + + subscribeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + DownloadRequester.getInstance().downloadFeed( + DefaultOnlineFeedViewActivity.this, + new Feed(feed.getDownload_url(), new Date(), feed + .getTitle())); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(DefaultOnlineFeedViewActivity.this, + e.getMessage()); + } + setSubscribeButtonState(feed); + } + }); + setSubscribeButtonState(feed); + + } + + private boolean feedInFeedlist(Feed feed) { + if (feeds == null || feed == null) + return false; + for (Feed f : feeds) { + if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) { + return true; + } + } + return false; + } + + private void setSubscribeButtonState(Feed feed) { + if (subscribeButton != null && feed != null) { + if (DownloadRequester.getInstance().isDownloadingFile(feed.getDownload_url())) { + subscribeButton.setEnabled(false); + subscribeButton.setText(R.string.downloading_label); + } else if (feedInFeedlist(feed)) { + subscribeButton.setEnabled(false); + subscribeButton.setText(R.string.subscribed_label); + } else { + subscribeButton.setEnabled(true); + subscribeButton.setText(R.string.subscribe_label); + } + } + } + + EventDistributor.EventListener listener = new EventDistributor.EventListener() { + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) { + new AsyncTask<Void, Void, List<Feed>>() { + @Override + protected List<Feed> doInBackground(Void... params) { + return DBReader.getFeedList(DefaultOnlineFeedViewActivity.this); + } + + @Override + protected void onPostExecute(List<Feed> feeds) { + super.onPostExecute(feeds); + DefaultOnlineFeedViewActivity.this.feeds = feeds; + setSubscribeButtonState(feed); + } + }.execute(); + } else if ((arg & EVENTS) != 0) { + setSubscribeButtonState(feed); + } + } + }; + + @Override + protected void onStop() { + super.onStop(); + EventDistributor.getInstance().unregister(listener); + } +} + diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index fbac7057d..84aa2d26b 100644 --- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -1,23 +1,15 @@ package de.danoeh.antennapod.activity; -import java.io.File; -import java.io.IOException; -import java.util.Date; - -import javax.xml.parsers.ParserConfigurationException; - -import android.support.v7.app.ActionBarActivity; -import org.xml.sax.SAXException; - import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Gravity; import android.widget.LinearLayout; import android.widget.ProgressBar; - +import android.widget.RelativeLayout; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.Feed; @@ -25,7 +17,6 @@ import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.service.download.DownloadRequest; import de.danoeh.antennapod.service.download.DownloadStatus; import de.danoeh.antennapod.service.download.Downloader; -import de.danoeh.antennapod.service.download.DownloaderCallback; import de.danoeh.antennapod.service.download.HttpDownloader; import de.danoeh.antennapod.syndication.handler.FeedHandler; import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException; @@ -33,207 +24,238 @@ import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.FileNameGenerator; import de.danoeh.antennapod.util.StorageUtils; import de.danoeh.antennapod.util.URLChecker; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; +import java.util.Date; /** * Downloads a feed from a feed URL and parses it. Subclasses can display the * feed object that was parsed. This activity MUST be started with a given URL * or an Exception will be thrown. - * + * <p/> * If the feed cannot be downloaded or parsed, an error dialog will be displayed * and the activity will finish as soon as the error dialog is closed. */ public abstract class OnlineFeedViewActivity extends ActionBarActivity { - private static final String TAG = "OnlineFeedViewActivity"; - private static final String ARG_FEEDURL = "arg.feedurl"; - - public static final int RESULT_ERROR = 2; - - private Feed feed; - private Downloader downloader; - - @Override - protected void onCreate(Bundle arg0) { - setTheme(UserPreferences.getTheme()); - super.onCreate(arg0); - StorageUtils.checkStorageAvailability(this); - final String feedUrl = getIntent().getStringExtra(ARG_FEEDURL); - if (feedUrl == null) { - throw new IllegalArgumentException( - "Activity must be started with feedurl argument!"); - } - if (AppConfig.DEBUG) - Log.d(TAG, "Activity was started with url " + feedUrl); - setLoadingLayout(); - startFeedDownload(feedUrl); - } - - @Override - protected void onStop() { - super.onStop(); - if (downloader != null && !downloader.isFinished()) { - downloader.cancel(); - } - } - - private DownloaderCallback downloaderCallback = new DownloaderCallback() { - @Override - public void onDownloadCompleted(final Downloader downloader) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - DownloadStatus status = downloader.getResult(); - if (status != null) { - if (!status.isCancelled()) { - if (status.isSuccessful()) { - parseFeed(); - } else { - String errorMsg = status.getReason().getErrorString( - OnlineFeedViewActivity.this); - if (errorMsg != null - && status.getReasonDetailed() != null) { - errorMsg += " (" - + status.getReasonDetailed() + ")"; - } - showErrorDialog(errorMsg); - } - } - } else { - Log.wtf(TAG, - "DownloadStatus returned by Downloader was null"); - finish(); - } - } - }); - - } - }; - - private void startFeedDownload(String url) { - if (AppConfig.DEBUG) - Log.d(TAG, "Starting feed download"); - url = URLChecker.prepareURL(url); - feed = new Feed(url, new Date()); - String fileUrl = new File(getExternalCacheDir(), - FileNameGenerator.generateFileName(feed.getDownload_url())) - .toString(); - feed.setFile_url(fileUrl); - DownloadRequest request = new DownloadRequest(feed.getFile_url(), - feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED); - /* TODO update - HttpDownloader httpDownloader = new HttpDownloader(downloaderCallback, - request); - httpDownloader.start(); - */ - } - - /** Displays a progress indicator. */ - private void setLoadingLayout() { - LinearLayout ll = new LinearLayout(this); - LinearLayout.LayoutParams llLayoutParams = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - - ProgressBar pb = new ProgressBar(this); - pb.setIndeterminate(true); - LinearLayout.LayoutParams pbLayoutParams = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT); - pbLayoutParams.gravity = Gravity.CENTER; - ll.addView(pb, pbLayoutParams); - addContentView(ll, llLayoutParams); - } - - private void parseFeed() { - if (feed == null || feed.getFile_url() == null) { - throw new IllegalStateException( - "feed must be non-null and downloaded when parseFeed is called"); - } - - if (AppConfig.DEBUG) - Log.d(TAG, "Parsing feed"); - - Thread thread = new Thread() { - - @Override - public void run() { - String reasonDetailed = ""; - boolean successful = false; - FeedHandler handler = new FeedHandler(); - try { - handler.parseFeed(feed); - successful = true; - } catch (SAXException e) { - e.printStackTrace(); - reasonDetailed = e.getMessage(); - } catch (IOException e) { - e.printStackTrace(); - reasonDetailed = e.getMessage(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - reasonDetailed = e.getMessage(); - } catch (UnsupportedFeedtypeException e) { - e.printStackTrace(); - reasonDetailed = e.getMessage(); - } finally { - boolean rc = new File(feed.getFile_url()).delete(); - if (AppConfig.DEBUG) - Log.d(TAG, "Deleted feed source file. Result: " + rc); - } - - if (successful) { - runOnUiThread(new Runnable() { - @Override - public void run() { - showFeedInformation(); - } - }); - } else { - final String errorMsg = - DownloadError.ERROR_PARSER_EXCEPTION.getErrorString( - OnlineFeedViewActivity.this) - + " (" + reasonDetailed + ")"; - runOnUiThread(new Runnable() { - - @Override - public void run() { - showErrorDialog(errorMsg); - } - }); - } - } - }; - thread.start(); - } - - /** Called when feed parsed successfully */ - protected void showFeedInformation() { - - } - - private void showErrorDialog(String errorMsg) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.error_label); - if (errorMsg != null) { - builder.setMessage(getString(R.string.error_msg_prefix) + errorMsg); - } else { - builder.setMessage(R.string.error_msg_prefix); - } - builder.setNeutralButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - builder.setOnCancelListener(new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - setResult(RESULT_ERROR); - finish(); - } - }); - } + private static final String TAG = "OnlineFeedViewActivity"; + public static final String ARG_FEEDURL = "arg.feedurl"; + + /** Optional argument: specify a title for the actionbar. */ + public static final String ARG_TITLE = "title"; + + public static final int RESULT_ERROR = 2; + + private Feed feed; + private Downloader downloader; + + @Override + protected void onCreate(Bundle arg0) { + setTheme(UserPreferences.getTheme()); + super.onCreate(arg0); + + if (getIntent() != null && getIntent().hasExtra(ARG_TITLE)) { + getSupportActionBar().setTitle(getIntent().getStringExtra(ARG_TITLE)); + } + + StorageUtils.checkStorageAvailability(this); + final String feedUrl = getIntent().getStringExtra(ARG_FEEDURL); + if (feedUrl == null) { + throw new IllegalArgumentException( + "Activity must be started with feedurl argument!"); + } + if (AppConfig.DEBUG) + Log.d(TAG, "Activity was started with url " + feedUrl); + setLoadingLayout(); + startFeedDownload(feedUrl); + } + + @Override + protected void onStop() { + super.onStop(); + if (downloader != null && !downloader.isFinished()) { + downloader.cancel(); + } + } + + + private void onDownloadCompleted(final Downloader downloader) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (AppConfig.DEBUG) Log.d(TAG, "Download was completed"); + DownloadStatus status = downloader.getResult(); + if (status != null) { + if (!status.isCancelled()) { + if (status.isSuccessful()) { + parseFeed(); + } else { + String errorMsg = status.getReason().getErrorString( + OnlineFeedViewActivity.this); + if (errorMsg != null + && status.getReasonDetailed() != null) { + errorMsg += " (" + + status.getReasonDetailed() + ")"; + } + showErrorDialog(errorMsg); + } + } + } else { + Log.wtf(TAG, + "DownloadStatus returned by Downloader was null"); + finish(); + } + } + }); + + } + + private void startFeedDownload(String url) { + if (AppConfig.DEBUG) + Log.d(TAG, "Starting feed download"); + url = URLChecker.prepareURL(url); + feed = new Feed(url, new Date()); + String fileUrl = new File(getExternalCacheDir(), + FileNameGenerator.generateFileName(feed.getDownload_url())) + .toString(); + feed.setFile_url(fileUrl); + final DownloadRequest request = new DownloadRequest(feed.getFile_url(), + feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED); + downloader = new HttpDownloader( + request); + new Thread() { + @Override + public void run() { + loadData(); + downloader.call(); + onDownloadCompleted(downloader); + } + }.start(); + + + } + + /** + * Displays a progress indicator. + */ + private void setLoadingLayout() { + RelativeLayout rl = new RelativeLayout(this); + RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + + ProgressBar pb = new ProgressBar(this); + pb.setIndeterminate(true); + RelativeLayout.LayoutParams pbLayoutParams = new RelativeLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + pbLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); + rl.addView(pb, pbLayoutParams); + addContentView(rl, rlLayoutParams); + } + + private void parseFeed() { + if (feed == null || feed.getFile_url() == null) { + throw new IllegalStateException( + "feed must be non-null and downloaded when parseFeed is called"); + } + + if (AppConfig.DEBUG) + Log.d(TAG, "Parsing feed"); + + Thread thread = new Thread() { + + @Override + public void run() { + String reasonDetailed = ""; + boolean successful = false; + FeedHandler handler = new FeedHandler(); + try { + handler.parseFeed(feed); + successful = true; + } catch (SAXException e) { + e.printStackTrace(); + reasonDetailed = e.getMessage(); + } catch (IOException e) { + e.printStackTrace(); + reasonDetailed = e.getMessage(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + reasonDetailed = e.getMessage(); + } catch (UnsupportedFeedtypeException e) { + e.printStackTrace(); + reasonDetailed = e.getMessage(); + } finally { + boolean rc = new File(feed.getFile_url()).delete(); + if (AppConfig.DEBUG) + Log.d(TAG, "Deleted feed source file. Result: " + rc); + } + + if (successful) { + runOnUiThread(new Runnable() { + @Override + public void run() { + showFeedInformation(feed); + } + }); + } else { + final String errorMsg = + DownloadError.ERROR_PARSER_EXCEPTION.getErrorString( + OnlineFeedViewActivity.this) + + " (" + reasonDetailed + ")"; + runOnUiThread(new Runnable() { + + @Override + public void run() { + showErrorDialog(errorMsg); + } + }); + } + } + }; + thread.start(); + } + + /** + * Can be used to load data asynchronously. + * */ + protected void loadData() { + + } + + /** + * Called when feed parsed successfully + */ + protected void showFeedInformation(Feed feed) { + + } + + private void showErrorDialog(String errorMsg) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.error_label); + if (errorMsg != null) { + builder.setMessage(getString(R.string.error_msg_prefix) + errorMsg); + } else { + builder.setMessage(R.string.error_msg_prefix); + } + builder.setNeutralButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + setResult(RESULT_ERROR); + finish(); + } + }); + } } diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java index 96471d06d..bae6c2e17 100644 --- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -1,10 +1,5 @@ package de.danoeh.antennapod.activity; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import android.content.Context; import android.content.Intent; import android.content.res.Resources.Theme; @@ -18,17 +13,24 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; import android.util.Log; - import android.view.Menu; import android.view.MenuItem; +import android.widget.Toast; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.asynctask.OpmlExportWorker; +import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import de.danoeh.antennapod.preferences.GpodnetPreferences; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.flattr.FlattrUtils; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * The main preference activity */ @@ -43,7 +45,11 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir"; private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings"; private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher"; - + + private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate"; + private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information"; + private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; + private CheckBoxPreference[] selectedNetworks; @SuppressWarnings("deprecation") @@ -56,9 +62,9 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { getActionBar().setDisplayHomeAsUpEnabled(true); } - addPreferencesFromResource(R.xml.preferences); - findPreference(PREF_FLATTR_THIS_APP).setOnPreferenceClickListener( - new OnPreferenceClickListener() { + addPreferencesFromResource(R.xml.preferences); + findPreference(PREF_FLATTR_THIS_APP).setOnPreferenceClickListener( + new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -166,11 +172,45 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { return true; } }); + findPreference(PREF_GPODNET_SETLOGIN_INFORMATION).setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + AuthenticationDialog dialog = new AuthenticationDialog(PreferenceActivity.this, + R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(), + null) { + + @Override + protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { + GpodnetPreferences.setPassword(password); + } + }; + dialog.show(); + return true; + } + }); + findPreference(PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + GpodnetPreferences.logout(); + Toast toast = Toast.makeText(PreferenceActivity.this, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT); + toast.show(); + updateGpodnetPreferenceScreen(); + return true; + } + }); buildUpdateIntervalPreference(); buildAutodownloadSelectedNetworsPreference(); setSelectedNetworksEnabled(UserPreferences .isEnableAutodownloadWifiFilter()); + + } + + private void updateGpodnetPreferenceScreen() { + final boolean loggedIn = GpodnetPreferences.loggedIn(); + findPreference(PREF_GPODNET_LOGIN).setEnabled(!loggedIn); + findPreference(PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn); + findPreference(PREF_GPODNET_LOGOUT).setEnabled(loggedIn); } private void buildUpdateIntervalPreference() { @@ -214,6 +254,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { checkItemVisibility(); setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize()); setDataFolderText(); + updateGpodnetPreferenceScreen(); } @SuppressWarnings("deprecation") diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java new file mode 100644 index 000000000..08b37ae60 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetActivity.java @@ -0,0 +1,44 @@ +package de.danoeh.antennapod.activity.gpoddernet; + +import android.app.SearchManager; +import android.content.Context; +import android.os.Bundle; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.SearchView; +import android.view.Menu; +import android.view.MenuItem; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.preferences.UserPreferences; + +/** + * Created by daniel on 23.08.13. + */ +public class GpodnetActivity extends ActionBarActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(UserPreferences.getTheme()); + super.onCreate(savedInstanceState); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label) + .setIcon( + obtainStyledAttributes( + new int[]{R.attr.action_search}) + .getDrawable(0)), + MenuItem.SHOW_AS_ACTION_IF_ROOM); + MenuItemCompat.setActionView(menu.findItem(R.id.search_item), new SearchView(this)); + + SearchManager searchManager = + (SearchManager) getSystemService(Context.SEARCH_SERVICE); + SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search_item)); + searchView.setIconifiedByDefault(true); + searchView.setSearchableInfo( + searchManager.getSearchableInfo(getComponentName())); + + return true; + } +} diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java new file mode 100644 index 000000000..d355a7826 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java @@ -0,0 +1,370 @@ +package de.danoeh.antennapod.activity.gpoddernet; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.NavUtils; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.*; +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.gpoddernet.GpodnetService; +import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; +import de.danoeh.antennapod.gpoddernet.model.GpodnetDevice; +import de.danoeh.antennapod.preferences.GpodnetPreferences; +import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.service.GpodnetSyncService; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Guides the user through the authentication process + * Step 1: Request username and password from user + * Step 2: Choose device from a list of available devices or create a new one + * Step 3: Choose from a list of actions + */ +public class GpodnetAuthenticationActivity extends ActionBarActivity { + private static final String TAG = "GpodnetAuthenticationActivity"; + + private static final String CURRENT_STEP = "current_step"; + + private ViewFlipper viewFlipper; + + private static final int STEP_DEFAULT = -1; + private static final int STEP_LOGIN = 0; + private static final int STEP_DEVICE = 1; + private static final int STEP_FINISH = 2; + + private int currentStep = -1; + + private GpodnetService service; + private volatile String username; + private volatile String password; + private volatile GpodnetDevice selectedDevice; + + View[] views; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + setTheme(UserPreferences.getTheme()); + + setContentView(R.layout.gpodnetauth_activity); + service = new GpodnetService(); + + viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper); + LayoutInflater inflater = (LayoutInflater) + getSystemService(Context.LAYOUT_INFLATER_SERVICE); + views = new View[]{ + inflater.inflate(R.layout.gpodnetauth_credentials, null), + inflater.inflate(R.layout.gpodnetauth_device, null), + inflater.inflate(R.layout.gpodnetauth_finish, null) + }; + for (View view : views) { + viewFlipper.addView(view); + } + advance(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (service != null) { + service.shutdown(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + } + + private void setupLoginView(View view) { + final EditText username = (EditText) view.findViewById(R.id.etxtUsername); + final EditText password = (EditText) view.findViewById(R.id.etxtPassword); + final Button login = (Button) view.findViewById(R.id.butLogin); + final TextView txtvError = (TextView) view.findViewById(R.id.txtvError); + final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progBarLogin); + + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + final String usernameStr = username.getText().toString(); + final String passwordStr = password.getText().toString(); + + if (AppConfig.DEBUG) Log.d(TAG, "Checking login credentials"); + new AsyncTask<GpodnetService, Void, Void>() { + + volatile Exception exception; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + login.setEnabled(false); + progressBar.setVisibility(View.VISIBLE); + txtvError.setVisibility(View.GONE); + + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + login.setEnabled(true); + progressBar.setVisibility(View.GONE); + + if (exception == null) { + advance(); + } else { + txtvError.setText(exception.getMessage()); + txtvError.setVisibility(View.VISIBLE); + } + } + + @Override + protected Void doInBackground(GpodnetService... params) { + try { + params[0].authenticate(usernameStr, passwordStr); + GpodnetAuthenticationActivity.this.username = usernameStr; + GpodnetAuthenticationActivity.this.password = passwordStr; + } catch (GpodnetServiceException e) { + e.printStackTrace(); + exception = e; + } + return null; + } + }.execute(service); + } + }); + } + + private void setupDeviceView(View view) { + final EditText deviceID = (EditText) view.findViewById(R.id.etxtDeviceID); + final EditText caption = (EditText) view.findViewById(R.id.etxtCaption); + final Button createNewDevice = (Button) view.findViewById(R.id.butCreateNewDevice); + final Button chooseDevice = (Button) view.findViewById(R.id.butChooseExistingDevice); + final TextView txtvError = (TextView) view.findViewById(R.id.txtvError); + final ProgressBar progBarCreateDevice = (ProgressBar) view.findViewById(R.id.progbarCreateDevice); + final Spinner spinnerDevices = (Spinner) view.findViewById(R.id.spinnerChooseDevice); + + + // load device list + final AtomicReference<List<GpodnetDevice>> devices = new AtomicReference<List<GpodnetDevice>>(); + new AsyncTask<GpodnetService, Void, List<GpodnetDevice>>() { + + private volatile Exception exception; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + chooseDevice.setEnabled(false); + spinnerDevices.setEnabled(false); + createNewDevice.setEnabled(false); + } + + @Override + protected void onPostExecute(List<GpodnetDevice> gpodnetDevices) { + super.onPostExecute(gpodnetDevices); + if (gpodnetDevices != null) { + List<String> deviceNames = new ArrayList<String>(); + for (GpodnetDevice device : gpodnetDevices) { + deviceNames.add(device.getCaption()); + } + spinnerDevices.setAdapter(new ArrayAdapter<String>(GpodnetAuthenticationActivity.this, + android.R.layout.simple_spinner_dropdown_item, deviceNames)); + spinnerDevices.setEnabled(true); + if (!deviceNames.isEmpty()) { + chooseDevice.setEnabled(true); + } + devices.set(gpodnetDevices); + createNewDevice.setEnabled(true); + } + } + + @Override + protected List<GpodnetDevice> doInBackground(GpodnetService... params) { + try { + return params[0].getDevices(username); + } catch (GpodnetServiceException e) { + e.printStackTrace(); + exception = e; + return null; + } + } + }.execute(service); + + + createNewDevice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (checkDeviceIDText(deviceID, txtvError, devices.get())) { + final String deviceStr = deviceID.getText().toString(); + final String captionStr = caption.getText().toString(); + + new AsyncTask<GpodnetService, Void, GpodnetDevice>() { + + private volatile Exception exception; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + createNewDevice.setEnabled(false); + chooseDevice.setEnabled(false); + progBarCreateDevice.setVisibility(View.VISIBLE); + txtvError.setVisibility(View.GONE); + } + + @Override + protected void onPostExecute(GpodnetDevice result) { + super.onPostExecute(result); + createNewDevice.setEnabled(true); + chooseDevice.setEnabled(true); + progBarCreateDevice.setVisibility(View.GONE); + if (exception == null) { + selectedDevice = result; + advance(); + } else { + txtvError.setText(exception.getMessage()); + txtvError.setVisibility(View.VISIBLE); + } + } + + @Override + protected GpodnetDevice doInBackground(GpodnetService... params) { + try { + params[0].configureDevice(username, deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE); + return new GpodnetDevice(deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE.toString(), 0); + } catch (GpodnetServiceException e) { + e.printStackTrace(); + exception = e; + } + return null; + } + }.execute(service); + } + } + }); + + deviceID.setText(generateDeviceID()); + chooseDevice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final int position = spinnerDevices.getSelectedItemPosition(); + selectedDevice = devices.get().get(position); + advance(); + } + }); + } + + + private String generateDeviceID() { + final int DEVICE_ID_LENGTH = 10; + StringBuilder buffer = new StringBuilder(DEVICE_ID_LENGTH); + SecureRandom random = new SecureRandom(); + for (int i = 0; i < DEVICE_ID_LENGTH; i++) { + buffer.append(random.nextInt(10)); + + } + return buffer.toString(); + } + + private boolean checkDeviceIDText(EditText deviceID, TextView txtvError, List<GpodnetDevice> devices) { + String text = deviceID.getText().toString(); + if (text.length() == 0) { + txtvError.setText(R.string.gpodnetauth_device_errorEmpty); + txtvError.setVisibility(View.VISIBLE); + return false; + } else { + if (devices != null) { + for (GpodnetDevice device : devices) { + if (device.getId().equals(text)) { + txtvError.setText(R.string.gpodnetauth_device_errorAlreadyUsed); + txtvError.setVisibility(View.VISIBLE); + return false; + } + } + txtvError.setVisibility(View.GONE); + return true; + } + return true; + } + + } + + private void setupFinishView(View view) { + final Button sync = (Button) view.findViewById(R.id.butSyncNow); + final Button back = (Button) view.findViewById(R.id.butGoMainscreen); + + sync.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + GpodnetSyncService.sendSyncIntent(GpodnetAuthenticationActivity.this); + finish(); + } + }); + back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(GpodnetAuthenticationActivity.this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + } + }); + } + + private void writeLoginCredentials() { + if (AppConfig.DEBUG) Log.d(TAG, "Writing login credentials"); + GpodnetPreferences.setUsername(username); + GpodnetPreferences.setPassword(password); + GpodnetPreferences.setDeviceID(selectedDevice.getId()); + } + + private void advance() { + if (currentStep < STEP_FINISH) { + + View view = views[currentStep + 1]; + if (currentStep == STEP_DEFAULT) { + setupLoginView(view); + } else if (currentStep == STEP_LOGIN) { + if (username == null || password == null) { + throw new IllegalStateException("Username and password must not be null here"); + } else { + setupDeviceView(view); + } + } else if (currentStep == STEP_DEVICE) { + if (selectedDevice == null) { + throw new IllegalStateException("Device must not be null here"); + } else { + writeLoginCredentials(); + setupFinishView(view); + } + } + if (currentStep != STEP_DEFAULT) { + viewFlipper.showNext(); + } + currentStep++; + } else { + finish(); + } + } +} diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java new file mode 100644 index 000000000..9535e9d32 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java @@ -0,0 +1,89 @@ +package de.danoeh.antennapod.activity.gpoddernet; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.app.NavUtils; +import android.support.v4.view.ViewPager; +import android.view.MenuItem; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.fragment.gpodnet.PodcastTopListFragment; +import de.danoeh.antennapod.fragment.gpodnet.SuggestionListFragment; +import de.danoeh.antennapod.fragment.gpodnet.TagListFragment; +import de.danoeh.antennapod.preferences.GpodnetPreferences; + +/** + * Created by daniel on 22.08.13. + */ +public class GpodnetMainActivity extends GpodnetActivity { + private static final String TAG = "GPodnetMainActivity"; + + private static final int POS_TAGS = 0; + private static final int POS_TOPLIST = 1; + private static final int POS_SUGGESTIONS = 2; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + setContentView(R.layout.gpodnet_main); + ViewPager viewpager = (ViewPager) findViewById(R.id.viewpager); + viewpager.setAdapter(new PagerAdapter(getSupportFragmentManager())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + } + return super.onOptionsItemSelected(item); + } + + private class PagerAdapter extends FragmentStatePagerAdapter { + + private static final int NUM_PAGES_LOGGED_OUT = 2; + private static final int NUM_PAGES_LOGGED_IN = 3; + private final int NUM_PAGES; + + public PagerAdapter(FragmentManager fm) { + super(fm); + NUM_PAGES = NUM_PAGES_LOGGED_OUT; + } + + @Override + public Fragment getItem(int i) { + switch (i) { + case POS_TAGS: + return new TagListFragment(); + case POS_TOPLIST: + return new PodcastTopListFragment(); + case POS_SUGGESTIONS: + return new SuggestionListFragment(); + default: + return null; + } + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case POS_TAGS: + return getString(R.string.gpodnet_taglist_header); + case POS_TOPLIST: + return getString(R.string.gpodnet_toplist_header); + case POS_SUGGESTIONS: + return getString(R.string.gpodnet_suggestions_header); + default: + return super.getPageTitle(position); + } + } + + @Override + public int getCount() { + return NUM_PAGES; + } + } +} diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java new file mode 100644 index 000000000..199b45dc9 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetSearchActivity.java @@ -0,0 +1,63 @@ +package de.danoeh.antennapod.activity.gpoddernet; + +import android.app.SearchManager; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.NavUtils; +import android.view.MenuItem; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.fragment.gpodnet.SearchListFragment; +import org.apache.commons.lang3.StringUtils; + +/** + * Created by daniel on 23.08.13. + */ +public class GpodnetSearchActivity extends GpodnetActivity { + + private SearchListFragment searchFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + setContentView(R.layout.gpodnet_search); + } + + @Override + protected void onResume() { + super.onResume(); + Intent intent = getIntent(); + if (StringUtils.equals(intent.getAction(), Intent.ACTION_SEARCH)) { + handleSearchRequest(intent.getStringExtra(SearchManager.QUERY)); + } + } + + @Override + protected void onNewIntent(Intent intent) { + setIntent(intent); + } + + private void handleSearchRequest(String query) { + getSupportActionBar().setSubtitle(getString(R.string.search_term_label) + query); + if (searchFragment == null) { + FragmentTransaction transaction = getSupportFragmentManager() + .beginTransaction(); + searchFragment = SearchListFragment.newInstance(query); + transaction.replace(R.id.searchListFragment, searchFragment); + transaction.commit(); + } else { + searchFragment.changeQuery(query); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java new file mode 100644 index 000000000..f3922f7aa --- /dev/null +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java @@ -0,0 +1,64 @@ +package de.danoeh.antennapod.activity.gpoddernet; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.NavUtils; +import android.view.MenuItem; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.fragment.gpodnet.PodcastListFragment; +import de.danoeh.antennapod.fragment.gpodnet.SearchListFragment; +import de.danoeh.antennapod.gpoddernet.GpodnetService; +import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; +import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; +import de.danoeh.antennapod.gpoddernet.model.GpodnetTag; + +import java.util.List; + +/** + * Created by daniel on 23.08.13. + */ +public class GpodnetTagActivity extends GpodnetActivity{ + + private static final int PODCAST_COUNT = 50; + public static final String ARG_TAGNAME = "tagname"; + + private GpodnetTag tag; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + setContentView(R.layout.gpodnet_tag_activity); + + if (!getIntent().hasExtra(ARG_TAGNAME)) { + throw new IllegalArgumentException("No tagname argument"); + } + tag = new GpodnetTag(getIntent().getStringExtra(ARG_TAGNAME)); + getSupportActionBar().setTitle(tag.getName()); + + FragmentTransaction transaction = getSupportFragmentManager() + .beginTransaction(); + Fragment taglistFragment = new TaglistFragment(); + transaction.replace(R.id.taglistFragment, taglistFragment); + transaction.commit(); + } + + private class TaglistFragment extends PodcastListFragment { + + @Override + protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException { + return service.getPodcastsForTag(tag, PODCAST_COUNT); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + } + return super.onOptionsItemSelected(item); + } +} |