diff options
15 files changed, 740 insertions, 90 deletions
diff --git a/vdrmanager/res/drawable/folder.png b/vdrmanager/res/drawable/folder.png Binary files differnew file mode 100644 index 0000000..5b3fcec --- /dev/null +++ b/vdrmanager/res/drawable/folder.png diff --git a/vdrmanager/res/layout-land/vdrmanager.xml b/vdrmanager/res/layout-land/vdrmanager.xml index 52cc9c6..8f5b86e 100644 --- a/vdrmanager/res/layout-land/vdrmanager.xml +++ b/vdrmanager/res/layout-land/vdrmanager.xml @@ -8,13 +8,13 @@ <ImageView android:id="@+id/main_logo" android:layout_width="fill_parent" android:layout_height="80dip" android:src="@drawable/vdr_logo" android:paddingBottom="5dip" /> - <!-- <ListView android:id="@+id/vdrmanager_menu" android:layout_width="fill_parent" + <!-- <ListView android:id="@+id/vdrmanager_menu" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/main_logo"/> --> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="3dip"> <Button android:text="@string/action_menu_channels" - xmlns:android="http://schemas.android.com/apk/res/android" + android:drawableTop="@drawable/btn_channels" android:layout_width="wrap_content" android:id="@+id/action_menu_channels" android:layout_height="wrap_content" android:textColor="#FFF" android:layout_weight="1" @@ -23,17 +23,17 @@ <Button android:text="@string/action_menu_recordings" - xmlns:android="http://schemas.android.com/apk/res/android" android:padding="3dip" + android:padding="3dip" android:drawableTop="@drawable/btn_recordings" android:layout_width="wrap_content" android:id="@+id/action_menu_recordings" android:layout_height="wrap_content" android:layout_weight="1" android:cacheColorHint="?android:attr/colorBackground" android:background="@android:drawable/list_selector_background" - android:textColor="#FFF" + android:textColor="#FFF" /> <Button - xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/action_menu_timers" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -46,27 +46,8 @@ android:textColor="#FFF" /> </LinearLayout> - <LinearLayout android:layout_width="fill_parent" + <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> - <Button android:text="@string/action_menu_epg" - xmlns:android="http://schemas.android.com/apk/res/android" - android:drawableTop="@drawable/btn_epglist" android:layout_width="wrap_content" - android:id="@+id/action_menu_epg" android:layout_height="wrap_content" - android:layout_weight="1" - android:cacheColorHint="?android:attr/colorBackground" - android:padding="3dip" - android:background="@android:drawable/list_selector_background" - android:textColor="#FFF" /> - - <Button android:text="@string/action_menu_search" - xmlns:android="http://schemas.android.com/apk/res/android" - android:drawableTop="@drawable/btn_search" android:layout_width="wrap_content" - android:id="@+id/action_menu_search" android:layout_height="wrap_content" - android:layout_weight="1" - android:cacheColorHint="?android:attr/colorBackground" - android:background="@android:drawable/list_selector_background" - android:padding="3dip" - android:textColor="#FFF" /> <Button android:text="@string/action_menu_wakeup" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_weight="1" @@ -77,6 +58,6 @@ android:background="@android:drawable/list_selector_background" android:textColor="#FFF" /> </LinearLayout> - + </LinearLayout> </ScrollView>
\ No newline at end of file diff --git a/vdrmanager/res/layout/folder_item.xml b/vdrmanager/res/layout/folder_item.xml new file mode 100644 index 0000000..fa2f8ab --- /dev/null +++ b/vdrmanager/res/layout/folder_item.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:orientation="horizontal" + android:padding="5dip" + android:layout_height="wrap_content" > + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:src="@drawable/folder" /> + + <TextView + android:id="@+id/header_item" + android:textAppearance="?android:textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="5dip" + android:layout_gravity="center_vertical" + android:text="House of Cards" /> + +</LinearLayout>
\ No newline at end of file diff --git a/vdrmanager/res/layout/header_item.xml b/vdrmanager/res/layout/header_item.xml index 0ca07d6..0821980 100644 --- a/vdrmanager/res/layout/header_item.xml +++ b/vdrmanager/res/layout/header_item.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" -android:text="Header" +android:text="Header" android:layout_margin="2dip" android:paddingLeft="4dip" android:paddingRight="4dip" android:background="#444444" android:textAppearance="?android:textAppearanceMedium" android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/header_item"/> - + diff --git a/vdrmanager/res/layout/vdrmanager.xml b/vdrmanager/res/layout/vdrmanager.xml index d963d70..8fdf062 100644 --- a/vdrmanager/res/layout/vdrmanager.xml +++ b/vdrmanager/res/layout/vdrmanager.xml @@ -6,7 +6,7 @@ android:layout_height="wrap_content" > - + <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:padding="10dip"> @@ -15,7 +15,7 @@ android:clickable="true" android:layout_height="80dip" android:src="@drawable/vdr_logo" android:padding="10dip" /> - <!-- <ListView android:id="@+id/vdrmanager_menu" android:layout_width="fill_parent" + <!-- <ListView android:id="@+id/vdrmanager_menu" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/main_logo"/> --> <LinearLayout android:layout_width="fill_parent" @@ -26,9 +26,8 @@ android:textColor="#FFF" android:layout_weight="1" android:cacheColorHint="?android:attr/colorBackground" android:background="@android:drawable/list_selector_background"/> - + <Button android:text="@string/action_menu_epg" - xmlns:android="http://schemas.android.com/apk/res/android" android:drawableTop="@drawable/btn_epglist" android:layout_width="wrap_content" android:id="@+id/action_menu_epg" android:layout_height="wrap_content" android:layout_weight="1" @@ -37,22 +36,20 @@ android:textColor="#FFF" /> </LinearLayout> - + <LinearLayout android:layout_width="fill_parent" android:padding="10dip" android:layout_height="wrap_content" android:orientation="horizontal"> - + <Button android:text="@string/action_menu_recordings" - xmlns:android="http://schemas.android.com/apk/res/android" android:drawableTop="@drawable/btn_recordings" android:layout_width="wrap_content" android:id="@+id/action_menu_recordings" android:layout_height="wrap_content" android:layout_weight="1" android:cacheColorHint="?android:attr/colorBackground" android:background="@android:drawable/list_selector_background" - android:textColor="#FFF" + android:textColor="#FFF" /> - + <Button android:text="@string/action_menu_timers" - xmlns:android="http://schemas.android.com/apk/res/android" android:drawableTop="@drawable/btn_timer" android:layout_width="wrap_content" android:id="@+id/action_menu_timers" android:layout_height="wrap_content" android:layout_weight="1" @@ -63,29 +60,17 @@ <LinearLayout android:layout_width="fill_parent" android:padding="10dip" android:layout_height="wrap_content" android:orientation="horizontal"> - - - - <Button android:text="@string/action_menu_search" - xmlns:android="http://schemas.android.com/apk/res/android" - android:drawableTop="@drawable/btn_search" android:layout_width="wrap_content" - android:id="@+id/action_menu_search" android:layout_height="wrap_content" - android:layout_weight="1" - android:cacheColorHint="?android:attr/colorBackground" - android:background="@android:drawable/list_selector_background" - - android:textColor="#FFF" /> <Button android:text="@string/action_menu_wakeup" - xmlns:android="http://schemas.android.com/apk/res/android" android:layout_weight="1" + android:layout_weight="1" android:padding="5dip" android:drawableTop="@drawable/btn_wakeup" android:layout_width="wrap_content" android:id="@+id/action_menu_wakeup" android:layout_height="wrap_content" - + android:cacheColorHint="?android:attr/colorBackground" android:background="@android:drawable/list_selector_background" android:textColor="#FFF" /> </LinearLayout> - + </LinearLayout> </ScrollView>
\ No newline at end of file diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/data/Channel.java b/vdrmanager/src/de/bjusystems/vdrmanager/data/Channel.java index d8ca9ec..2b7b0d1 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/data/Channel.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/data/Channel.java @@ -63,6 +63,7 @@ public class Channel implements Parcelable { } public Channel(final String channelData) { + System.err.println(channelData); String[] words = StringUtils.splitPreserveAllTokens(channelData, C.DATA_SEPARATOR); this.number = Integer.valueOf(words[0].substring(1)); diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/data/Recording.java b/vdrmanager/src/de/bjusystems/vdrmanager/data/Recording.java index f2ad445..f510011 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/data/Recording.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/data/Recording.java @@ -1,15 +1,60 @@ package de.bjusystems.vdrmanager.data; -import java.util.Date; +import static de.bjusystems.vdrmanager.gui.Utils.mapSpecialChars; +import java.util.Date; import de.bjusystems.vdrmanager.StringUtils; import de.bjusystems.vdrmanager.app.C; -import static de.bjusystems.vdrmanager.gui.Utils.mapSpecialChars; - public class Recording extends Event{ + public static String ROOT_FOLDER = ""; + public static final String FOLDERDELIMCHAR = "~"; + + public class Folder { + + public String name; + + public Folder parent; + + private String path; + + public boolean isRoot(){ + return parent == null; + } + + public String getFullPath(){ + if(this.path != null){ + return this.path; + } + if(isRoot()){ + this.path = ""; + } else { + this.path = parent.getFullPath() + "/" + name; + } + + return path; + } + + @Override + public boolean equals(Object o) { + if(o == this){ + return true; + } + return ((Folder)o).name.equals(this.name); + } + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name + "("+path+")"; + } + }; + public Recording(String line) { final String[] words = StringUtils.splitPreserveAllTokens(line, C.DATA_SEPARATOR); int idx = 0; @@ -17,7 +62,7 @@ public class Recording extends Event{ start = new Date(Long.parseLong(words[idx++]) * 1000); stop = new Date(Long.parseLong(words[idx++]) * 1000); channelName = mapSpecialChars(words[idx++]); - title = mapSpecialChars(words[idx++]); + eventTitle = mapSpecialChars(words[idx++]); shortText = mapSpecialChars(words[idx++]); description = mapSpecialChars(words[idx++]); fileName = mapSpecialChars(words[idx++]); @@ -39,8 +84,27 @@ public class Recording extends Event{ timerStopTime = new Date(Long.parseLong(data) * 1000L); } } + + if(idx < words.length) { //name + String titleRaw = words[idx]; + int idxdel = titleRaw.lastIndexOf(FOLDERDELIMCHAR); + if(idxdel == -1){ + title = titleRaw; + folder = ROOT_FOLDER; + } else { + title = titleRaw.substring(idxdel+1); + + String foldersRaw = titleRaw.substring(0, idxdel); + + folder = foldersRaw; + + } + } + } + private String folder; + private String fileName; private int fileSize; @@ -51,11 +115,21 @@ public class Recording extends Event{ private String devInode = null; + private String eventTitle = null; + /** * If it is not null, recording is on going or will be on going until this date; */ private Date timerStopTime = null; + public String getEventTitle() { + return eventTitle; + } + + public void setEventTitle(String eventTitle) { + this.eventTitle = eventTitle; + } + public Date getTimerStopTime() { return timerStopTime; } @@ -123,4 +197,15 @@ public class Recording extends Event{ public String toString() { return title; } -} + + + public String getFolder() { + return folder; + } + + public void setFolder(String folder) { + this.folder = folder; + } + + +}
\ No newline at end of file diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/data/RecordingListItem.java b/vdrmanager/src/de/bjusystems/vdrmanager/data/RecordingListItem.java new file mode 100644 index 0000000..b3137e3 --- /dev/null +++ b/vdrmanager/src/de/bjusystems/vdrmanager/data/RecordingListItem.java @@ -0,0 +1,33 @@ +package de.bjusystems.vdrmanager.data; + + +public class RecordingListItem extends EventListItem { + + public String folder; + + public RecordingListItem(Recording rec) { + super(rec); + } + + public RecordingListItem(String dailyHeader) { + super(dailyHeader); + } + + + + public boolean isFolder() { + + return folder != null; + + } + + @Override + public String getHeader() { + if (isFolder()) { + return folder; + } else { + return super.getHeader(); + } + } + +}
\ No newline at end of file diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseActivity.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseActivity.java index d9dc70f..fc53833 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseActivity.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseActivity.java @@ -387,7 +387,8 @@ public abstract class BaseActivity<Result, T extends ListView> extends @Override public void svdrpEvent(SvdrpEvent event, Throwable t) { - Utils.say(this, t.getLocalizedMessage()); + progress.dismiss(); + Utils.say(this, t.getMessage()); } protected void addListener(SvdrpAsyncTask<Result, SvdrpClient<Result>> task) { diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventAdapter.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventAdapter.java new file mode 100644 index 0000000..297dfe0 --- /dev/null +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventAdapter.java @@ -0,0 +1,354 @@ +package de.bjusystems.vdrmanager.gui; + +import java.util.ArrayList; +import java.util.List; + +import android.content.Context; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import de.bjusystems.vdrmanager.R; +import de.bjusystems.vdrmanager.data.Event; +import de.bjusystems.vdrmanager.data.EventFormatter; +import de.bjusystems.vdrmanager.data.EventListItem; +import de.bjusystems.vdrmanager.data.Recording; +import de.bjusystems.vdrmanager.data.TimerMatch; +import de.bjusystems.vdrmanager.data.Timerable; + +abstract class BaseEventAdapter<T extends EventListItem> extends ArrayAdapter<T> implements + Filterable +// , SectionIndexer +{ + + protected final static int TYPE_ITEM = 0; + protected final static int TYPE_HEADER = 1; + protected final int layout; + protected final LayoutInflater inflater; + protected final List<T> items = new ArrayList<T>(); + + protected boolean hideDescription = true; + + protected boolean hideChannelName = false; + + String highlight; + + /** + * Lock used to modify the content of {@link #mObjects}. Any write operation + * performed on the array should be synchronized on this lock. This lock is + * also used by the filter (see {@link #getFilter()} to make a synchronized + * copy of the original array of data. + */ + private final Object _Lock = new Object(); + + public BaseEventAdapter(final Context context, int layout) { + super(context, layout); + this.layout = layout; + inflater = LayoutInflater.from(context); + } + + @Override + public int getViewTypeCount() { + return 2; + } + + @Override + public void add(T object) { + items.add(object); + // if (object.isHeader()) { + // sections.add(object.getHeader()); + // } + super.add(object); + } + + @Override + public int getItemViewType(int position) { + + // get item + final EventListItem item = getItem(position); + + if (item.isHeader()) { + return TYPE_HEADER; + } + return TYPE_ITEM; + } + + private boolean canReuseConvertView(View convertView, int itemViewType){ + if(convertView == null){ + return false; + } + Object o = convertView.getTag(); + if(itemViewType == TYPE_ITEM){ + return o instanceof EventListItemHolder; + } + + if(itemViewType == TYPE_HEADER){ + return o instanceof de.bjusystems.vdrmanager.gui.EventAdapter.EventListItemHeaderHolder; + } + + return false; + + } + + @Override + public View getView(final int position, View convertView, + final ViewGroup parent) { + + // get item + final EventListItem item = getItem(position); + + Object holder = null; + int type = getItemViewType(position); + if (canReuseConvertView(convertView, type) == false) { + switch (type) { + case TYPE_ITEM: + convertView = inflater.inflate(layout, null); + holder = getEventViewHolder(item, convertView); + break; + case TYPE_HEADER: + convertView = inflater.inflate(R.layout.header_item, null); + holder = getHeaderViewHolder(item, convertView); + break; + } + convertView.setTag(holder); + } else { + holder = convertView.getTag(); + } + + if (type == TYPE_ITEM) { + fillEventViewHolder((EventListItemHolder) holder, item); + } else { + ((EventListItemHeaderHolder) holder).header.setText(item + .getHeader()); + } + return convertView; + } + + protected EventListItemHolder getEventViewHolder(EventListItem item, View view) { + + EventListItemHolder itemHolder = new EventListItemHolder(); + + itemHolder = new EventListItemHolder(); + + itemHolder.state = (ImageView) view.findViewById(R.id.timer_item_state); + itemHolder.time = (TextView) view.findViewById(R.id.timer_item_time); + itemHolder.channel = (TextView) view + .findViewById(R.id.timer_item_channel); + itemHolder.title = (TextView) view.findViewById(R.id.timer_item_title); + itemHolder.progress = (ProgressBar) view + .findViewById(R.id.timer_progress); + itemHolder.shortText = (TextView) view + .findViewById(R.id.timer_item_shorttext); + itemHolder.duration = (TextView) view + .findViewById(R.id.timer_item_duration); + itemHolder.description = (TextView) view + .findViewById(R.id.event_item_description); + return itemHolder; + } + + public void fillEventViewHolder(EventListItemHolder itemHolder, + EventListItem item) { + + itemHolder.state.setVisibility(View.VISIBLE); + + if (item.getEvent() instanceof Recording) { + Recording r = (Recording) item.getEvent(); + if (r.getTimerStopTime() != null) { + itemHolder.state.setImageResource(R.drawable.timer_recording); + } + } else if (item.getEvent() instanceof Timerable == true) { + TimerMatch match = ((Timerable) item.getEvent()).getTimerMatch(); + switch (((Timerable) item.getEvent()).getTimerState()) { + case Active: + itemHolder.state.setImageResource(Utils.getTimerStateDrawable( + match, R.drawable.timer_active, + R.drawable.timer_active_begin, + R.drawable.timer_active_end)); + break; + case Inactive: + itemHolder.state.setImageResource(Utils.getTimerStateDrawable( + match, R.drawable.timer_inactive, + R.drawable.timer_inactive_begin, + R.drawable.timer_inactive_end)); + break; + case Recording: + itemHolder.state.setImageResource(Utils.getTimerStateDrawable( + match, R.drawable.timer_recording, + R.drawable.timer_recording_begin, + R.drawable.timer_recording_end)); + break; + case None: + itemHolder.state.setImageResource(R.drawable.timer_none); + break; + } + } else { + itemHolder.state.setImageResource(R.drawable.timer_none); + } + + final EventFormatter formatter = getEventFormatter(item); + itemHolder.time.setText(formatter.getTime()); + if (hideChannelName) { + itemHolder.channel.setVisibility(View.GONE); + } else { + itemHolder.channel.setText(item.getChannelName()); + } + + CharSequence title = Utils.highlight(formatter.getTitle(), highlight); + CharSequence shortText = Utils.highlight(formatter.getShortText(), + highlight); + itemHolder.title.setText(title); + itemHolder.shortText.setText(shortText); + + if (hideDescription == false) { + Pair<Boolean, CharSequence> desc = Utils.highlight2( + formatter.getDescription(), highlight); + if (desc.first == true) { + itemHolder.description.setVisibility(View.VISIBLE); + itemHolder.description.setText(desc.second); + } + } + + // TODO better render of duration + int p = Utils.getProgress(item.getEvent()); + if (p == -1) { + itemHolder.progress.setVisibility(View.GONE); + int dura = Utils.getDuration(item); + itemHolder.duration.setText(getContext().getString( + R.string.epg_duration_template, dura)); + } else { + itemHolder.progress.setVisibility(View.VISIBLE); + itemHolder.progress.setProgress(p); + int dura = Utils.getDuration(item.getEvent()); + int rest = dura - (dura * p / 100); + // on live recordings the amount of already recorded time + if (item.getEvent() instanceof Recording) { + rest = dura - rest; + } + itemHolder.duration.setText(getContext().getString( + R.string.epg_duration_template_live, rest, dura)); + } + } + + class EventListItemHeaderHolder { + public TextView header; + } + + + protected EventListItemHeaderHolder getHeaderViewHolder(EventListItem item, + View view) { + EventListItemHeaderHolder itemHolder = new EventListItemHeaderHolder(); + itemHolder.header = (TextView) view.findViewById(R.id.header_item); + return itemHolder; + } + + protected EventFormatter getEventFormatter(Event event) { + return new EventFormatter(event); + } + + protected void addSuper(T item) { + super.add(item); + } + + protected void clearSuper() { + super.clear(); + } + + public boolean isHideDescription() { + return hideDescription; + } + + public void setHideDescription(boolean hideDescription) { + this.hideDescription = hideDescription; + } + + public boolean isHideChannelName() { + return hideChannelName; + } + + public void setHideChannelName(boolean hideChannelName) { + this.hideChannelName = hideChannelName; + } + + // TODO implement locking in performFiltering, check the parent class + // http://stackoverflow.com/questions/5846385/how-to-update-android-listview-with-dynamic-data-in-real-time + public Filter getFilter() { + return new Filter() { + /** + * + */ + EventListItem prevHead = null; + + @Override + protected FilterResults performFiltering(CharSequence arg0) { + highlight = arg0.toString().toLowerCase(); + ArrayList<EventListItem> result = new ArrayList<EventListItem>(); + for (EventListItem event : items) { + if (event.isHeader()) { + prevHead = event; + // result.add(event); + continue; + } + if (event.getTitle().toLowerCase() + .indexOf(String.valueOf(arg0).toLowerCase()) != -1 + || event.getShortText() + .toLowerCase() + .indexOf(String.valueOf(arg0).toLowerCase()) != -1) { + if (prevHead != null) { + result.add(prevHead); + prevHead = null; + } + result.add(event); + } + } + + FilterResults fr = new FilterResults(); + fr.count = result.size(); + fr.values = result; + return fr; + } + + @Override + protected void publishResults(CharSequence arg0, FilterResults arg1) { + clearSuper(); + for (T item : (ArrayList<T>) arg1.values) { + addSuper(item); + } + notifyDataSetChanged(); + } + }; + } + + // @Override + // public int getPositionForSection(int section) { + // return 0; + // } + + // @Override + // public int getSectionForPosition(int position) { + // TODO Auto-generated method stub + // return 0; + // } + + // ArrayList<String> sections = new ArrayList<String>(); + + // @Override + // public Object[] getSections() { + // try { + // return sections.toArray(); + // } finally { + // sections.clear(); + // } + // } + + @Override + public void clear() { + super.clear(); + items.clear(); + } +} diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventListActivity.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventListActivity.java index be1e17d..8463063 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventListActivity.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/BaseEventListActivity.java @@ -51,7 +51,7 @@ public abstract class BaseEventListActivity<T extends Event> extends private SimpleGestureFilter detector; - protected EventAdapter adapter; + protected BaseEventAdapter<EventListItem> adapter; protected String highlight = null; diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/ChannelEventAdapter.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/ChannelEventAdapter.java index 7e3d575..475f3e6 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/ChannelEventAdapter.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/ChannelEventAdapter.java @@ -4,16 +4,17 @@ import android.content.Context; import de.bjusystems.vdrmanager.R; import de.bjusystems.vdrmanager.data.Event; import de.bjusystems.vdrmanager.data.EventFormatter; +import de.bjusystems.vdrmanager.data.EventListItem; -class ChannelEventAdapter extends EventAdapter +class ChannelEventAdapter extends BaseEventAdapter<EventListItem> { - + public ChannelEventAdapter(final Context context) { super(context, R.layout.epg_event_item); hideChannelName = true; } - + @Override protected EventFormatter getEventFormatter(Event event) { return new EventFormatter(event,true); diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingAdapter.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingAdapter.java index 3645596..d2fed1f 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingAdapter.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingAdapter.java @@ -1,13 +1,19 @@ package de.bjusystems.vdrmanager.gui; import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; import de.bjusystems.vdrmanager.R; import de.bjusystems.vdrmanager.data.Event; import de.bjusystems.vdrmanager.data.EventFormatter; +import de.bjusystems.vdrmanager.data.EventListItem; +import de.bjusystems.vdrmanager.data.RecordingListItem; -class RecordingAdapter extends EventAdapter -{ +class RecordingAdapter extends BaseEventAdapter<EventListItem> { + + protected final static int TYPE_FOLDER = 2; public RecordingAdapter(final Context context) { super(context, R.layout.epg_event_item); @@ -16,8 +22,77 @@ class RecordingAdapter extends EventAdapter @Override protected EventFormatter getEventFormatter(Event event) { - return new EventFormatter(event, true); + return new EventFormatter(event, true); + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public void add(EventListItem object) { + items.add(object); + // if (object.isHeader()) { + // sections.add(object.getHeader()); + // } + super.add(object); } + @Override + public int getItemViewType(int position) { + + // get item + final RecordingListItem item = (RecordingListItem) getItem(position); + + if (item.isHeader()) { + return TYPE_HEADER; + } else if (item.isFolder()) { + return TYPE_FOLDER; + } + return TYPE_ITEM; + } + + + class EventListItemFolderHolder { + public TextView folder; + } + + protected EventListItemFolderHolder getFolderViewHolder(EventListItem item, + View view) { + EventListItemFolderHolder itemHolder = new EventListItemFolderHolder(); + itemHolder.folder = (TextView) view.findViewById(R.id.header_item); + return itemHolder; + } + + + @Override + public View getView(final int position, View convertView, + final ViewGroup parent) { + + // get item + final RecordingListItem item = (RecordingListItem) getItem(position); + + if (item.isFolder() == false) { + return super.getView(position, convertView, parent); + } + + Object holder = null; + if (convertView == null || (convertView != null && convertView.getTag() instanceof EventListItemFolderHolder) == false) { + convertView = inflater.inflate(R.layout.folder_item, null); + holder = getHeaderViewHolder(item, convertView); + convertView.setTag(holder); + } else { + holder = convertView.getTag(); + } + + ((EventListItemHeaderHolder) holder).header.setText(item.getHeader()); + return convertView; + } + + @Override + public RecordingListItem getItem(int position) { + return (RecordingListItem) super.getItem(position); + } }
\ No newline at end of file diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingListActivity.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingListActivity.java index 27ec91b..d3cb81a 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingListActivity.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/RecordingListActivity.java @@ -4,6 +4,11 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; import android.os.Bundle; import android.view.ContextMenu; @@ -20,6 +25,8 @@ import de.bjusystems.vdrmanager.data.EventFormatter; import de.bjusystems.vdrmanager.data.EventListItem; import de.bjusystems.vdrmanager.data.Preferences; import de.bjusystems.vdrmanager.data.Recording; +import de.bjusystems.vdrmanager.data.RecordingListItem; +import de.bjusystems.vdrmanager.data.Recording.Folder; import de.bjusystems.vdrmanager.tasks.DeleteRecordingTask; import de.bjusystems.vdrmanager.utils.date.DateFormatter; import de.bjusystems.vdrmanager.utils.svdrp.RecordingClient; @@ -35,24 +42,33 @@ import de.bjusystems.vdrmanager.utils.svdrp.SvdrpEvent; public class RecordingListActivity extends BaseEventListActivity<Recording> implements OnItemLongClickListener { - //RecordingClient recordingClient; + // RecordingClient recordingClient; - //public static final int MENU_GROUP_CHANNEL = 2; + // public static final int MENU_GROUP_CHANNEL = 2; public static final int ASC = 0; public static final int DESC = 1; - protected static ArrayList<Recording> CACHE = new ArrayList<Recording>(); + // protected static ArrayList<Recording> CACHE = new ArrayList<Recording>(); + private static Map<String, List<Recording>> CACHE = new TreeMap<String, List<Recording>>(); + + public static final Map<String, Set<String>> FOLDERS = new TreeMap<String, Set<String>>(); + + private String currentFolder = Recording.ROOT_FOLDER; private int ASC_DESC = ASC; + private static final List<Recording> EMPTY = new ArrayList<Recording>(0); + + private Stack<String> stack = new Stack<String>(); + @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // create an adapter + adapter = new RecordingAdapter(this); // attach adapter to ListView @@ -115,6 +131,25 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> // } // } + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, + long id) { + + final RecordingListItem item = (RecordingListItem) adapter + .getItem(position); + if (item.isFolder()) { + if(currentFolder.equals(Recording.ROOT_FOLDER)){ + currentFolder = item.folder; + } else { + currentFolder = currentFolder + Recording.FOLDERDELIMCHAR + item.folder; + } + stack.push(currentFolder); + fillAdapter(); + } else { + super.onItemClick(parent, view, position, id); + } + } + /* * (non-Javadoc) * @@ -138,7 +173,7 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> @Override protected void prepareDetailsViewData(EventListItem event) { getApp().setCurrentEvent(event.getEvent()); - getApp().setCurrentEpgList(CACHE); + getApp().setCurrentEpgList(CACHE.get(currentFolder)); } @Override @@ -167,9 +202,9 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> super.onCreateContextMenu(menu, v, menuInfo); // // http://projects.vdr-developer.org/issues/863 - //if (Utils.isLive(item)) { - menu.removeItem(R.id.epg_item_menu_live_tv); - //} + // if (Utils.isLive(item)) { + menu.removeItem(R.id.epg_item_menu_live_tv); + // } } @Override @@ -212,7 +247,7 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> } // get timer client - RecordingClient recordingClient = new RecordingClient(); + RecordingClient recordingClient = new RecordingClient(); // create backgound task final SvdrpAsyncTask<Recording, SvdrpClient<Recording>> task = new SvdrpAsyncTask<Recording, SvdrpClient<Recording>>( @@ -248,16 +283,16 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> /* */ switch (sortBy) { case MENU_GROUP_DEFAULT: { - sortItemsByTime(CACHE, true); + sortItemsByTime(CACHE.get(currentFolder), true); break; } case MENU_GROUP_ALPHABET: { - Collections.sort(CACHE, new TitleComparator()); + Collections.sort(CACHE.get(currentFolder), new TitleComparator()); break; } - //case MENU_GROUP_CHANNEL: { - //sortItemsByChannel(results); - //} + // case MENU_GROUP_CHANNEL: { + // sortItemsByChannel(results); + // } } } @@ -265,8 +300,8 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> protected void fillAdapter() { adapter.clear(); - - if (CACHE.isEmpty()) { + List<Recording> list = CACHE.get(currentFolder); + if (list == null || list.isEmpty()) { return; } @@ -275,30 +310,95 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> Calendar cal = Calendar.getInstance(); int day = -1; - for (final Event rec : CACHE) { + Set<String> folders = FOLDERS.get(currentFolder); + if (folders != null) { + for (String f : folders) { + RecordingListItem recordingListItem = new RecordingListItem(f); + recordingListItem.folder = f; + adapter.add(recordingListItem); + } + } + + for (final Event rec : CACHE.get(currentFolder)) { cal.setTime(rec.getStart()); int eday = cal.get(Calendar.DAY_OF_YEAR); if (eday != day) { day = eday; - adapter.add(new EventListItem(new DateFormatter(cal) + adapter.add(new RecordingListItem(new DateFormatter(cal) .getDailyHeader())); } - adapter.add(new EventListItem((Recording) rec)); + adapter.add(new RecordingListItem((Recording) rec)); adapter.notifyDataSetChanged(); } } @Override + public void onBackPressed() { + if (stack.isEmpty()) { + super.onBackPressed(); + } else { + stack.pop(); + if (stack.isEmpty()) { + currentFolder = ""; + } else { + currentFolder = stack.peek(); + } + fillAdapter(); + } + + } + + @Override protected boolean finishedSuccessImpl(List<Recording> results) { clearCache(); - for(Recording r :results){ - CACHE.add(r); + for (Recording r : results) { + String folder = r.getFolder(); + if (folder.length() > 0) { + String[] split = folder.split(Recording.FOLDERDELIMCHAR); + String key = null; + String value = null; + if(split.length == 1){ + key = Recording.ROOT_FOLDER ; + value = split[0]; + } else { + value = split[split.length - 1]; + //StringBuilder sb = new StringBuilder(); + //String sep = ""; + //for(int i = 0; i < split.length - 1; ++i){ + //sb.append(sep).append(split[i]); + //sep = Recording.FOLDERDELIMCHAR; + //} + key = folder.subSequence(0, folder.length() - (value.length()+1) ).toString(); + + } + + Set<String> list = FOLDERS.get(key); + if(list == null){ + list = new TreeSet<String>(); + FOLDERS.put(key, list); + } + + list.add(value); + + //a b + //a + //c + //a~b > k + + + } + List<Recording> list = CACHE.get(folder); + if (list == null) { + list = new ArrayList<Recording>(); + CACHE.put(folder, list); + } + list.add(r); } + pushResultCountToTitle(); fillAdapter(); return adapter.isEmpty() == false; - } public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, @@ -312,9 +412,20 @@ public class RecordingListActivity extends BaseEventListActivity<Recording> return LIST_NAVIGATION_RECORDINGS; } + public void clearCache() { + CACHE.clear(); + FOLDERS.clear(); + } + @Override protected List<Recording> getCACHE() { - return CACHE; + + List<Recording> list = CACHE.get(currentFolder); + + if (list != null) { + return list; + } + return EMPTY; } } diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/TimeEventAdapter.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/TimeEventAdapter.java index dc7545e..f5cca64 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/TimeEventAdapter.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/TimeEventAdapter.java @@ -4,8 +4,9 @@ import android.content.Context; import de.bjusystems.vdrmanager.R; import de.bjusystems.vdrmanager.data.Event; import de.bjusystems.vdrmanager.data.EventFormatter; +import de.bjusystems.vdrmanager.data.EventListItem; -public class TimeEventAdapter extends EventAdapter { +public class TimeEventAdapter extends BaseEventAdapter<EventListItem> { public TimeEventAdapter(final Context context) { super(context, R.layout.epg_event_item); |