Skip to content

Commit

Permalink
WIP: First version of episode list.
Browse files Browse the repository at this point in the history
See #6.
  • Loading branch information
erikagnvall committed Jan 6, 2015
1 parent c03967c commit 2d50354
Show file tree
Hide file tree
Showing 19 changed files with 707 additions and 37 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ android {

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:support-v4:21.0.3"
}
74 changes: 74 additions & 0 deletions app/src/main/java/se/kodsnack/EpisodeListAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package se.kodsnack;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

import se.kodsnack.util.Episode;

/**
* Subclass of {@link android.widget.ArrayAdapter} that holds a list of
* Kodsnack's episodes.
*
* @author Erik Jansson<[email protected]>
*/
public class EpisodeListAdapter extends ArrayAdapter<Episode> {
private LayoutInflater inflater;

public EpisodeListAdapter(Context context) {
super(context, R.layout.episode_item);
inflater = LayoutInflater.from(context);
}

/**
* Replace the data in this adapter.
*
* @param data The new list of episodes.
*/
public void setData(List<Episode> data) {
clear();
if (data != null) {
addAll(data);
}
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
final LinearLayout view;
final Episode episode;
final ViewHolder viewHolder;

/* Check if we need to inflate a new view of can recycle and old one. */
if (convertView == null) {
viewHolder = new ViewHolder();
view = (LinearLayout) inflater.inflate(R.layout.episode_item, parent, false);

viewHolder.title = (TextView) view.findViewById(R.id.title);

view.setTag(viewHolder);
} else {
view = (LinearLayout) convertView;
viewHolder = (ViewHolder) view.getTag();
}

episode = getItem(position);
viewHolder.title.setText(episode.name);

return view;
}

/**
* Private view holder class that caches the findViewById() result since
* it's expensive to perform view lookups every time a new list element
* is cycled in.
*/
private class ViewHolder {
private TextView title;
}
}
113 changes: 113 additions & 0 deletions app/src/main/java/se/kodsnack/EpisodeListFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package se.kodsnack;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import java.util.List;

import se.kodsnack.util.Episode;

/**
* Subclass of {@link android.support.v4.app.ListFragment} that
* displays {@link Episode}s from Kodsnack's Atom feed.
*
* @author Erik Jansson<[email protected]>
*/
public class EpisodeListFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<List<Episode>> {
private EpisodeListAdapter episodeAdapter; // List adapter that holds the data.
private PlayerService playerService; // The service playing the stream.

/**
* The connection to the PlayerService.
*/
private final ServiceConnection playerConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
playerService = ((PlayerService.LocalBinder) service).getService();
}

public void onServiceDisconnected(ComponentName className) {
playerService = null;
}
};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

episodeAdapter = new EpisodeListAdapter(getActivity());
setListAdapter(episodeAdapter);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_episode_list, container, false);
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
final Episode episode = episodeAdapter.getItem(position);
playerService.prepareMedia(episode.url);
}

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Start PlayerService ...
final Intent i = new Intent(activity, PlayerService.class);
activity.startService(i);
// ... and bind to it.
activity.bindService(i, playerConnection, Context.BIND_AUTO_CREATE);
}

@Override
public void onStart() {
super.onStart();
getLoaderManager().initLoader(0, null, this);
}

@Override
public void onDestroy() {
super.onDestroy();
if (playerService != null) {
getActivity().unbindService(playerConnection);
playerService = null;
}
}

/**
* Returns the title of this fragment.
*
* @return The title of this fragment.
*/
public String getTitle() {
return "Avsnitt";
}

@Override
public Loader<List<Episode>> onCreateLoader(int id, Bundle args) {
return new EpisodeLoader(getActivity());
}

@Override
public void onLoadFinished(Loader<List<Episode>> loader, List<Episode> data) {
episodeAdapter.setData(data);
episodeAdapter.notifyDataSetChanged();
}

@Override
public void onLoaderReset(Loader<List<Episode>> loader) { }
}
54 changes: 54 additions & 0 deletions app/src/main/java/se/kodsnack/EpisodeLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package se.kodsnack;

import android.support.v4.content.AsyncTaskLoader;
import android.content.Context;
import android.util.Log;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.text.ParseException;
import java.util.List;

import se.kodsnack.util.AtomParser;
import se.kodsnack.util.Episode;

/**
* Subclass of {@link android.support.v4.content.AsyncTaskLoader} that
* fetches and parses the Kodsnack Atom feed in the background.
*
* @author Erik Jansson<[email protected]>
*/
public class EpisodeLoader extends AsyncTaskLoader<List<Episode>> {
/** Logger tag. */
private static final String TAG = EpisodeLoader.class.getSimpleName();

private List<Episode> episodes; // The list of episodes from the Atom feed.

public EpisodeLoader(Context context) {
super(context);
}

@Override
public List<Episode> loadInBackground() {
// Check if we have already fetched the episodes.
if (episodes != null) {
return episodes;
}

try {
episodes = AtomParser.parse("http://feedpress.me/kodsnack");
} catch (IOException e) {
Log.e(TAG, e.toString());
} catch (XmlPullParserException | ParseException e) {
e.printStackTrace();
}

return episodes;
}

@Override
protected void onStartLoading() {
forceLoad();
}
}
56 changes: 56 additions & 0 deletions app/src/main/java/se/kodsnack/KodsnackPagerAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package se.kodsnack;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

/**
* Subclass of {@link android.support.v4.app.FragmentPagerAdapter} that keeps
* track of one {@link LiveFragment} and one {@link EpisodeListFragment} in a
* {@link android.support.v4.view.ViewPager}.
*
* @author Erik Jansson<[email protected]>
*/
public class KodsnackPagerAdapter extends FragmentPagerAdapter {
private static final int NUM_FRAGMENTS = 2;

private final Fragment[] fragments; // List of fragments this adapter holds.
private final String[] fragmentTitles; // Titles of the fragments'.

public KodsnackPagerAdapter(FragmentManager fm) {
super(fm);
final LiveFragment liveFragment = new LiveFragment();
final EpisodeListFragment listFragment = new EpisodeListFragment();

fragments = new Fragment[NUM_FRAGMENTS];
fragments[0] = liveFragment;
fragments[1] = listFragment;

fragmentTitles = new String[NUM_FRAGMENTS];
fragmentTitles[0] = liveFragment.getTitle();
fragmentTitles[1] = listFragment.getTitle();
}

@Override
public Fragment getItem(int i) {
if (i < NUM_FRAGMENTS) {
return fragments[i];
} else {
throw new IllegalArgumentException("Fragment index too big.");
}
}

@Override
public int getCount() {
return NUM_FRAGMENTS;
}

@Override
public String getPageTitle(int i) {
if (i < NUM_FRAGMENTS) {
return fragmentTitles[i];
} else {
throw new IllegalArgumentException("Fragment index too big.");
}
}
}
20 changes: 17 additions & 3 deletions app/src/main/java/se/kodsnack/ListenActivity.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package se.kodsnack;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;

public class ListenActivity extends Activity {
/**
* The main activity that holds the {@link android.support.v4.view.ViewPager}
* with the two fragments in it.
*
* @author Erik Jansson<[email protected]>
*/
public class ListenActivity extends FragmentActivity {
/* Logger tag. */
@SuppressWarnings("UnusedDeclaration")
private static final String TAG = ListenActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listen);
}

final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final PagerTabStrip tabs = (PagerTabStrip) findViewById(R.id.pager_tab_strip);

viewPager.setAdapter(new KodsnackPagerAdapter(getSupportFragmentManager()));
tabs.setTabIndicatorColorResource(R.color.alternate_foreground);
}
}
14 changes: 11 additions & 3 deletions app/src/main/java/se/kodsnack/LiveFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
Expand All @@ -22,7 +21,7 @@


/**
* A simple {@link Fragment} subclass.
* A fragment for playing the live stream.
*/
public class LiveFragment extends Fragment implements PlayerService.PlayerCallback {
private static final String TAG = LiveFragment.class.getSimpleName();
Expand Down Expand Up @@ -176,4 +175,13 @@ public void onJsonInfo(JSONObject info) {
Log.w(TAG, e.toString());
}
}

/**
* Returns the title of this fragment.
*
* @return The title of this fragment.
*/
public String getTitle() {
return "Live";
}
}
6 changes: 3 additions & 3 deletions app/src/main/java/se/kodsnack/PlayControlFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ public void onBuffering() {

@Override
public void onError(Throwable t) {
playPauseButton.setPlaying(false);
playPauseButton.setEnabled(false);
// TODO?
// playPauseButton.setPlaying(false);
// playPauseButton.setEnabled(false);
// TODO: Should probably change this to be a bit smarter.
}

@Override
Expand Down
Loading

0 comments on commit 2d50354

Please sign in to comment.