mirror of
https://github.com/mediathekview/zapp.git
synced 2024-09-20 20:23:04 +02:00
Make channel order adjustable #6
This commit is contained in:
parent
68b31c59ab
commit
a130d5057d
@ -28,21 +28,30 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile project(':programguide')
|
||||
|
||||
// tests
|
||||
testCompile 'junit:junit:4.12'
|
||||
androidTestCompile 'com.android.support:support-annotations:24.2.1'
|
||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
||||
|
||||
// support
|
||||
compile 'com.android.support:appcompat-v7:24.2.1'
|
||||
compile 'com.android.support:support-v4:24.2.1'
|
||||
compile 'com.android.support:design:24.2.1'
|
||||
|
||||
// helper
|
||||
compile 'com.google.code.gson:gson:2.7'
|
||||
compile 'commons-io:commons-io:2.5'
|
||||
|
||||
// changelog
|
||||
compile 'com.github.porokoro.paperboy:paperboy:3.0.0'
|
||||
// for butterknive:
|
||||
|
||||
// sortable list
|
||||
compile 'com.github.woxthebox:draglistview:1.3'
|
||||
|
||||
// butterknive:
|
||||
compile 'com.jakewharton:butterknife:8.4.0'
|
||||
apt 'com.jakewharton:butterknife-compiler:8.4.0'
|
||||
compile project(':programguide')
|
||||
}
|
||||
|
@ -35,6 +35,11 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ChannelSelectionActivity"
|
||||
android:label="@string/activity_channel_selection_title"
|
||||
android:parentActivityName=".ChannelListActivity">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -27,7 +27,7 @@ import butterknife.OnTouch;
|
||||
import de.christinecoenen.code.zapp.adapters.ChannelDetailAdapter;
|
||||
import de.christinecoenen.code.zapp.model.ChannelModel;
|
||||
import de.christinecoenen.code.zapp.model.IChannelList;
|
||||
import de.christinecoenen.code.zapp.model.json.JsonChannelList;
|
||||
import de.christinecoenen.code.zapp.model.json.SortableJsonChannelList;
|
||||
import de.christinecoenen.code.zapp.utils.ColorHelper;
|
||||
import de.christinecoenen.code.zapp.utils.VideoErrorHandler;
|
||||
import de.christinecoenen.code.zapp.utils.view.ClickableViewPager;
|
||||
@ -133,7 +133,7 @@ public class ChannelDetailActivity extends FullscreenActivity implements
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
final IChannelList channelList = new JsonChannelList(this);
|
||||
final IChannelList channelList = new SortableJsonChannelList(this);
|
||||
|
||||
// set to channel
|
||||
Bundle extras = getIntent().getExtras();
|
||||
|
@ -15,14 +15,17 @@ import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnItemClick;
|
||||
import de.christinecoenen.code.zapp.adapters.ChannelListAdapter;
|
||||
import de.christinecoenen.code.zapp.model.IChannelList;
|
||||
import de.christinecoenen.code.zapp.model.json.JsonChannelList;
|
||||
import de.christinecoenen.code.zapp.model.ISortableChannelList;
|
||||
import de.christinecoenen.code.zapp.model.json.SortableJsonChannelList;
|
||||
|
||||
public class ChannelListActivity extends AppCompatActivity {
|
||||
|
||||
protected @BindView(R.id.toolbar) Toolbar toolbar;
|
||||
protected @BindView(R.id.gridview_channels) GridView channelGridView;
|
||||
|
||||
private ISortableChannelList channelList;
|
||||
private BaseAdapter gridAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -33,11 +36,18 @@ public class ChannelListActivity extends AppCompatActivity {
|
||||
setSupportActionBar(toolbar);
|
||||
ViewCompat.setNestedScrollingEnabled(channelGridView, true);
|
||||
|
||||
IChannelList channelList = new JsonChannelList(this);
|
||||
BaseAdapter gridAdapter = new ChannelListAdapter(this, channelList);
|
||||
channelList = new SortableJsonChannelList(this);
|
||||
gridAdapter = new ChannelListAdapter(this, channelList);
|
||||
channelGridView.setAdapter(gridAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
channelList.reloadChannelOrder();
|
||||
gridAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@OnItemClick(R.id.gridview_channels)
|
||||
void onGridItemClick(int position) {
|
||||
Intent intent = ChannelDetailActivity.getStartIntent(this, position);
|
||||
@ -53,9 +63,15 @@ public class ChannelListActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
Intent intent;
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_channel_selection:
|
||||
intent = ChannelSelectionActivity.getStartIntent(this);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.menu_changelog:
|
||||
Intent intent = ChangelogActivity.getStartIntent(this);
|
||||
intent = ChangelogActivity.getStartIntent(this);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
default:
|
||||
|
@ -0,0 +1,59 @@
|
||||
package de.christinecoenen.code.zapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import com.woxthebox.draglistview.DragListView;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.christinecoenen.code.zapp.adapters.ChannelSelectionAdapter;
|
||||
import de.christinecoenen.code.zapp.model.ISortableChannelList;
|
||||
import de.christinecoenen.code.zapp.model.json.SortableJsonChannelList;
|
||||
import de.christinecoenen.code.zapp.utils.view.GridAutofitLayoutManager;
|
||||
import de.christinecoenen.code.zapp.utils.view.SimpleDragListListener;
|
||||
|
||||
public class ChannelSelectionActivity extends AppCompatActivity {
|
||||
|
||||
public static Intent getStartIntent(Context context) {
|
||||
return new Intent(context, ChannelSelectionActivity.class);
|
||||
}
|
||||
|
||||
protected @BindView(R.id.draglist_channel_selection) DragListView channelListView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_channel_selection);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
ActionBar toolbar = getSupportActionBar();
|
||||
if (toolbar != null) {
|
||||
toolbar.setSubtitle(R.string.activity_channel_selection_subtitle);
|
||||
}
|
||||
|
||||
// adapter
|
||||
final ISortableChannelList channelList = new SortableJsonChannelList(this);
|
||||
final ChannelSelectionAdapter listAdapter = new ChannelSelectionAdapter(this);
|
||||
listAdapter.setItemList(channelList.getList());
|
||||
|
||||
// view
|
||||
RecyclerView.LayoutManager layoutManager = new GridAutofitLayoutManager(this, 400);
|
||||
channelListView.setLayoutManager(layoutManager);
|
||||
channelListView.setAdapter(listAdapter, true);
|
||||
|
||||
channelListView.setDragListListener(new SimpleDragListListener() {
|
||||
@Override
|
||||
public void onItemDragEnded(int fromPosition, int toPosition) {
|
||||
if (fromPosition != toPosition) {
|
||||
channelList.persistChannelOrder();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package de.christinecoenen.code.zapp.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.woxthebox.draglistview.DragItemAdapter;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.christinecoenen.code.zapp.R;
|
||||
import de.christinecoenen.code.zapp.model.ChannelModel;
|
||||
|
||||
|
||||
public class ChannelSelectionAdapter extends DragItemAdapter<ChannelModel, ChannelSelectionAdapter.ViewHolder> {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public ChannelSelectionAdapter(Context context) {
|
||||
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelSelectionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = inflater.inflate(R.layout.item_channel_selection_list, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ChannelSelectionAdapter.ViewHolder holder, int position) {
|
||||
super.onBindViewHolder(holder, position);
|
||||
ChannelModel channel = mItemList.get(position);
|
||||
holder.setChannel(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mItemList.get(position).getId().hashCode();
|
||||
}
|
||||
|
||||
class ViewHolder extends DragItemAdapter.ViewHolder {
|
||||
|
||||
@BindView(R.id.image_handle) ImageView handleView;
|
||||
@BindView(R.id.image_channel_logo) ImageView logoView;
|
||||
@BindView(R.id.text_channel_subtitle) TextView subtitle;
|
||||
|
||||
ViewHolder(final View itemView) {
|
||||
super(itemView, R.id.image_handle, false);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
void setChannel(ChannelModel channel) {
|
||||
logoView.setImageResource(channel.getDrawableId());
|
||||
handleView.setContentDescription(channel.getName());
|
||||
|
||||
if (channel.getSubtitle() == null) {
|
||||
subtitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
subtitle.setText(channel.getSubtitle());
|
||||
subtitle.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
package de.christinecoenen.code.zapp.model;
|
||||
|
||||
public interface IChannelList {
|
||||
import java.util.List;
|
||||
|
||||
public interface IChannelList extends Iterable<ChannelModel> {
|
||||
|
||||
ChannelModel get(int index);
|
||||
int size();
|
||||
List<ChannelModel> getList();
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package de.christinecoenen.code.zapp.model;
|
||||
|
||||
/**
|
||||
* A sorted channel list. Channel order will be
|
||||
* persisted across application starts.
|
||||
*/
|
||||
public interface ISortableChannelList extends IChannelList {
|
||||
|
||||
/**
|
||||
* Reloads the current channel order from disk.
|
||||
* Us this eg. in onResume when another activity
|
||||
* might have modified the channel order.
|
||||
*/
|
||||
void reloadChannelOrder();
|
||||
|
||||
/**
|
||||
* Writes the current channel order to disk.
|
||||
*/
|
||||
void persistChannelOrder();
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package de.christinecoenen.code.zapp.model;
|
||||
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Simple IChannelList wrapper around a List of ChannelModels.
|
||||
*/
|
||||
public class SimpleChannelList implements IChannelList {
|
||||
|
||||
private final List<ChannelModel> channels;
|
||||
|
||||
public SimpleChannelList(List<ChannelModel> channels) {
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelModel get(int index) {
|
||||
return channels.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return channels.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChannelModel> getList() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ChannelModel> iterator() {
|
||||
return channels.iterator();
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import de.christinecoenen.code.zapp.R;
|
||||
@ -40,6 +41,16 @@ public class JsonChannelList implements IChannelList {
|
||||
return channels.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChannelModel> getList() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ChannelModel> iterator() {
|
||||
return channels.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return content of R.raw.channels json file
|
||||
*/
|
||||
|
@ -0,0 +1,60 @@
|
||||
package de.christinecoenen.code.zapp.model.json;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import de.christinecoenen.code.zapp.model.ChannelModel;
|
||||
import de.christinecoenen.code.zapp.model.IChannelList;
|
||||
import de.christinecoenen.code.zapp.model.ISortableChannelList;
|
||||
import de.christinecoenen.code.zapp.model.SimpleChannelList;
|
||||
import de.christinecoenen.code.zapp.preferences.PreferenceChannelOrderHelper;
|
||||
|
||||
public class SortableJsonChannelList implements ISortableChannelList {
|
||||
|
||||
private IChannelList channelList;
|
||||
private final PreferenceChannelOrderHelper channelOrderHelper;
|
||||
|
||||
public SortableJsonChannelList(Context context) {
|
||||
channelOrderHelper = new PreferenceChannelOrderHelper(context);
|
||||
channelList = new JsonChannelList(context);
|
||||
loadSortingFromDisk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelModel get(int index) {
|
||||
return channelList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return channelList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChannelModel> getList() {
|
||||
return channelList.getList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ChannelModel> iterator() {
|
||||
return channelList.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadChannelOrder() {
|
||||
loadSortingFromDisk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistChannelOrder() {
|
||||
channelOrderHelper.saveChannelOrder(channelList.getList());
|
||||
}
|
||||
|
||||
private void loadSortingFromDisk() {
|
||||
List<ChannelModel> sortedChannels = channelOrderHelper.sortChannelList(channelList.getList());
|
||||
channelList = new SimpleChannelList(sortedChannels);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package de.christinecoenen.code.zapp.preferences;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.christinecoenen.code.zapp.model.ChannelModel;
|
||||
import de.christinecoenen.code.zapp.utils.PreferenceHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Helps persisting and reloading the channel order.
|
||||
* SharedPreferences are used to store the values on disk.
|
||||
*/
|
||||
public class PreferenceChannelOrderHelper {
|
||||
|
||||
private static final String PREF_KEY_CHANNEL_ORDER = "PREF_KEY_CHANNEL_ORDER";
|
||||
|
||||
private final PreferenceHelper preferenceHelper;
|
||||
|
||||
public PreferenceChannelOrderHelper (Context context) {
|
||||
preferenceHelper = new PreferenceHelper(context);
|
||||
}
|
||||
|
||||
public void saveChannelOrder(List<ChannelModel> channels) {
|
||||
List<String> sortedChannelIds = new ArrayList<>(channels.size());
|
||||
|
||||
for (ChannelModel channel : channels) {
|
||||
sortedChannelIds.add(channel.getId());
|
||||
}
|
||||
|
||||
preferenceHelper.saveList(PREF_KEY_CHANNEL_ORDER, sortedChannelIds);
|
||||
}
|
||||
|
||||
public List<ChannelModel> sortChannelList(List<ChannelModel> channels) {
|
||||
List<String> sortedChannelIds = preferenceHelper.loadList(PREF_KEY_CHANNEL_ORDER);
|
||||
|
||||
if (sortedChannelIds == null) {
|
||||
// have never been saved before
|
||||
return channels;
|
||||
}
|
||||
|
||||
int size = Math.max(sortedChannelIds.size(), channels.size());
|
||||
int unsavedIndex = sortedChannelIds.size();
|
||||
|
||||
ChannelModel[] sortedChannelArray = new ChannelModel[size];
|
||||
|
||||
for (ChannelModel channel : channels) {
|
||||
int index = sortedChannelIds.indexOf(channel.getId());
|
||||
|
||||
if (index == -1) {
|
||||
// order for this channel has never been saved - move to end
|
||||
index = unsavedIndex++;
|
||||
}
|
||||
|
||||
sortedChannelArray[index] = channel;
|
||||
}
|
||||
|
||||
// save as editable list without null values in case channels have been deleted
|
||||
List<ChannelModel> sortedChannelList = new ArrayList<>(Arrays.asList(sortedChannelArray));
|
||||
sortedChannelList.removeAll(Collections.singleton((ChannelModel) null));
|
||||
|
||||
return sortedChannelList;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package de.christinecoenen.code.zapp.utils;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PreferenceHelper {
|
||||
|
||||
private static final String SHARED_PEFERENCES_NAME = "ZAPP_SHARED_PREFERENCES";
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
private final SharedPreferences preferences;
|
||||
|
||||
public PreferenceHelper(Context context) {
|
||||
preferences = context.getSharedPreferences(SHARED_PEFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public void saveList(String key, List list) {
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
String jsonList = gson.toJson(list);
|
||||
editor.putString(key, jsonList);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public <T> List<T> loadList(String key) {
|
||||
if (preferences.contains(key)) {
|
||||
String jsonList = preferences.getString(key, null);
|
||||
Type listType = new TypeToken<ArrayList<T>>(){}.getType();
|
||||
return gson.fromJson(jsonList, listType);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package de.christinecoenen.code.zapp.utils.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* A GridLayoutManager with a flexible column count
|
||||
* based on view size and item size.
|
||||
*
|
||||
* @see "http://stackoverflow.com/a/30256880/3012757"
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public class GridAutofitLayoutManager extends GridLayoutManager {
|
||||
|
||||
private int mColumnWidth;
|
||||
private boolean mColumnWidthChanged = true;
|
||||
|
||||
public GridAutofitLayoutManager(Context context, int columnWidth) {
|
||||
/* Initially set spanCount to 1, will be changed automatically later. */
|
||||
super(context, 1);
|
||||
setColumnWidth(checkedColumnWidth(context, columnWidth));
|
||||
}
|
||||
|
||||
public GridAutofitLayoutManager(Context context, int columnWidth, int orientation, boolean reverseLayout) {
|
||||
/* Initially set spanCount to 1, will be changed automatically later. */
|
||||
super(context, 1, orientation, reverseLayout);
|
||||
setColumnWidth(checkedColumnWidth(context, columnWidth));
|
||||
}
|
||||
|
||||
private int checkedColumnWidth(Context context, int columnWidth) {
|
||||
if (columnWidth <= 0) {
|
||||
/* Set default columnWidth value (48dp here). It is better to move this constant
|
||||
to static constant on top, but we need context to convert it to dp, so can't really
|
||||
do so. */
|
||||
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
|
||||
context.getResources().getDisplayMetrics());
|
||||
}
|
||||
return columnWidth;
|
||||
}
|
||||
|
||||
public void setColumnWidth(int newColumnWidth) {
|
||||
if (newColumnWidth > 0 && newColumnWidth != mColumnWidth) {
|
||||
mColumnWidth = newColumnWidth;
|
||||
mColumnWidthChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
if (mColumnWidthChanged && mColumnWidth > 0 && width > 0 && height > 0) {
|
||||
int totalSpace;
|
||||
if (getOrientation() == VERTICAL) {
|
||||
totalSpace = width - getPaddingRight() - getPaddingLeft();
|
||||
} else {
|
||||
totalSpace = height - getPaddingTop() - getPaddingBottom();
|
||||
}
|
||||
int spanCount = Math.max(1, totalSpace / mColumnWidth);
|
||||
setSpanCount(spanCount);
|
||||
mColumnWidthChanged = false;
|
||||
}
|
||||
super.onLayoutChildren(recycler, state);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package de.christinecoenen.code.zapp.utils.view;
|
||||
|
||||
import com.woxthebox.draglistview.DragListView;
|
||||
|
||||
|
||||
public class SimpleDragListListener implements DragListView.DragListListener {
|
||||
@Override
|
||||
public void onItemDragStarted(int position) {}
|
||||
|
||||
@Override
|
||||
public void onItemDragging(int itemPosition, float x, float y) {}
|
||||
|
||||
@Override
|
||||
public void onItemDragEnded(int fromPosition, int toPosition) {}
|
||||
}
|
9
app/src/main/res/drawable/ic_handle_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_handle_white_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,21h18v-2L3,19v2zM3,17h18v-2L3,15v2zM3,13h18v-2L3,11v2zM3,9h18L21,7L3,7v2zM3,3v2h18L21,3L3,3z"/>
|
||||
</vector>
|
19
app/src/main/res/layout/activity_channel_selection.xml
Normal file
19
app/src/main/res/layout/activity_channel_selection.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/activity_channel_selection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context="de.christinecoenen.code.zapp.ChannelSelectionActivity">
|
||||
|
||||
<com.woxthebox.draglistview.DragListView
|
||||
android:id="@+id/draglist_channel_selection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
49
app/src/main/res/layout/item_channel_selection_list.xml
Normal file
49
app/src/main/res/layout/item_channel_selection_list.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/activity_channel_selection_item_width"
|
||||
android:layout_height="@dimen/activity_channel_selection_item_height"
|
||||
android:layout_margin="@dimen/activity_channel_selection_item_margin"
|
||||
android:background="@android:color/white"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_handle"
|
||||
android:layout_width="@dimen/activity_channel_selection_handleWidth"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_handle_white_24dp"
|
||||
android:padding="@dimen/activity_channel_selection_item_margin"
|
||||
tools:ignore="ContentDescription"
|
||||
android:background="@color/black_overlay"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_channel_logo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="4"
|
||||
android:padding="@dimen/activity_vertical_margin"
|
||||
tools:src="@drawable/channel_logo_das_erste"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_channel_subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
style="@style/Base.TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp"
|
||||
android:gravity="center|bottom"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="Mecklenburg-Vorpommern" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -2,6 +2,12 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_channel_selection"
|
||||
android:title="@string/menu_channel_selection"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_changelog"
|
||||
android:title="@string/menu_changelog"
|
||||
|
@ -5,4 +5,9 @@
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
<dimen name="view_program_info_subtitle_margin_bottom">4dp</dimen>
|
||||
|
||||
<dimen name="activity_channel_selection_item_width">120dip</dimen>
|
||||
<dimen name="activity_channel_selection_item_height">75dip</dimen>
|
||||
<dimen name="activity_channel_selection_item_margin">5dip</dimen>
|
||||
<dimen name="activity_channel_selection_handleWidth">25dip</dimen>
|
||||
</resources>
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
<string name="activity_channel_detail_info_error">Keine Programminfo</string>
|
||||
|
||||
<string name="activity_channel_selection_title">Sender anordnen</string>
|
||||
<string name="activity_channel_selection_subtitle">Ziehe an den grauen Balken</string>
|
||||
|
||||
<string name="view_program_info_show_time">%1$s – %2$s Uhr</string>
|
||||
|
||||
<!-- error messages -->
|
||||
@ -19,6 +22,7 @@
|
||||
<!-- menus -->
|
||||
<string name="action_share">Teilen</string>
|
||||
|
||||
<string name="menu_channel_selection">Sender anordnen</string>
|
||||
<string name="menu_changelog">Changelog</string>
|
||||
|
||||
<!-- paperboy changelog -->
|
||||
|
Loading…
Reference in New Issue
Block a user