fixed update and enabling drag and drop to set a custom sort

This commit is contained in:
Prem Nirmal
2014-12-23 13:06:50 -05:00
parent c3f5c2701e
commit 982e21bf09
20 changed files with 723 additions and 43 deletions
+1 -2
View File
@@ -2,7 +2,7 @@
[Google play link](https://play.google.com/store/apps/details?id=com.github.premnirmal.tickerwidget)
- A homescreen widget that shows your stock portolio in a resizable grid.
- Based off the [ministocks widget](https://github.com/niteshpatel/ministocks) but allowing unlimited tickers in a grid so you don't have to worry about sizing.
- Stocks are sorted by change in percent (descending).
- Stocks can be sorted by dragging and dropping the list.
- Only performs automatic fetching of stocks during trading hours and weekdays.
## Importing and exporting
@@ -19,7 +19,6 @@ The main purpose of me building this app is to practice usage of Square's Dagger
- Ability to set a custom refresh interval
- Ability to pick indices such as **^DJI**.
- Ability to change the app theme and colors
- Ability to change the way the stocks are sorted or to drag and drop the sort order.
## License
+2 -2
View File
@@ -8,8 +8,8 @@ android {
applicationId "com.github.premnirmal.tickerwidget"
minSdkVersion 16
targetSdkVersion 21
versionCode 5
versionName "2.00.00"
versionCode 6
versionName "2.10.00"
}
signingConfigs {
+6
View File
@@ -31,6 +31,12 @@
<activity android:name=".settings.SettingsActivity"
android:label="@string/action_Settings"/>
<receiver android:name=".UpdateReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.github.premnirmal.ticker.UPDATE"></action>
</intent-filter>
</receiver>
<receiver android:name="com.github.premnirmal.ticker.widget.StockWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -9,9 +9,11 @@ import android.os.SystemClock;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeZone;
import org.joda.time.MutableDateTime;
import java.io.File;
import java.util.List;
/**
* Created by premnirmal on 12/22/14.
@@ -74,9 +76,10 @@ public final class Tools {
final int hourOfDay = DateTime.now().hourOfDay().get();
if(hourOfDay >= 17) { // 5pm
final MutableDateTime mutableDateTime = new MutableDateTime(DateTime.now());
mutableDateTime.setZone(DateTimeZone.getDefault());
mutableDateTime.addDays(1);
mutableDateTime.setHourOfDay(9); // 9am
mutableDateTime.setMinuteOfHour(5); // update at 9:05am
mutableDateTime.setMinuteOfHour(15); // update at 9:15am
if(mutableDateTime.getDayOfWeek() > DateTimeConstants.FRIDAY) {
switch (mutableDateTime.getDayOfWeek()) {
case DateTimeConstants.SATURDAY:
@@ -93,4 +96,14 @@ public final class Tools {
return SystemClock.elapsedRealtime() + (AlarmManager.INTERVAL_FIFTEEN_MINUTES * 2);
}
}
public static String toCommaSeparatedString(List<String> list) {
final StringBuilder builder = new StringBuilder();
for(String string : list) {
builder.append(string);
builder.append(",");
}
builder.deleteCharAt(builder.length()-1);
return builder.toString();
}
}
@@ -0,0 +1,24 @@
package com.github.premnirmal.ticker;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.github.premnirmal.ticker.model.IStocksProvider;
import javax.inject.Inject;
/**
* Created by premnirmal on 12/23/14.
*/
public class UpdateReceiver extends BroadcastReceiver {
@Inject
IStocksProvider stocksProvider;
@Override
public void onReceive(Context context, Intent intent) {
((StocksApp)context.getApplicationContext()).inject(this);
stocksProvider.fetch();
}
}
@@ -18,6 +18,8 @@ public interface IStocksProvider {
Collection<Stock> getStocks();
Collection<Stock> rearrange(List<String> tickers);
List<String> getTickers();
String lastFetched();
@@ -8,12 +8,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.SystemClock;
import android.text.TextUtils;
import android.widget.Toast;
import com.github.premnirmal.ticker.R;
import com.github.premnirmal.ticker.Tools;
import com.github.premnirmal.ticker.events.NoNetworkEvent;
import com.github.premnirmal.ticker.UpdateReceiver;
import com.github.premnirmal.ticker.events.StockUpdatedEvent;
import com.github.premnirmal.ticker.network.Stock;
import com.github.premnirmal.ticker.network.StockQuery;
@@ -25,8 +26,10 @@ import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -46,9 +49,12 @@ import rx.schedulers.Schedulers;
public class StocksProvider implements IStocksProvider {
public static final String STOCK_LIST = "STOCK_LIST";
public static final String SORTED_STOCK_LIST = "SORTED_STOCK_LIST";
public static final String LAST_FETCHED = "LAST_FETCHED";
private static final Set<String> DEFAULT_LIST = new HashSet<String>() {
public static final String UPDATE_FILTER = "com.github.premnirmal.ticker.UPDATE";
private static final Set<String> DEFAULT_SET = new HashSet<String>() {
{
add("^SPY");
add("GOOG");
@@ -57,7 +63,10 @@ public class StocksProvider implements IStocksProvider {
}
};
private Set<String> tickerList;
private static final String DEFAULT_STOCKS = "^SPY,GOOG,AAPL,MSFT";
private Set<String> deprecatedTickerSet;
private List<String> tickerList;
private List<Stock> stockList;
private String lastFetched;
private final SharedPreferences preferences;
@@ -71,16 +80,26 @@ public class StocksProvider implements IStocksProvider {
this.api = api;
this.context = context;
preferences = context.getSharedPreferences(Tools.PREFS_NAME, Context.MODE_PRIVATE);
tickerList = preferences.getStringSet(STOCK_LIST, DEFAULT_LIST);
final String tickerListVars = preferences.getString(SORTED_STOCK_LIST, DEFAULT_STOCKS);
tickerList = new ArrayList<>(Arrays.asList(tickerListVars.split(",")));
if (preferences.contains(STOCK_LIST)) { // for users using older versions
deprecatedTickerSet = preferences.getStringSet(STOCK_LIST, DEFAULT_SET);
preferences.edit().remove(STOCK_LIST).commit();
for (String ticker : deprecatedTickerSet) {
if (!tickerList.contains(ticker)) {
tickerList.add(ticker);
}
}
preferences.edit().putString(SORTED_STOCK_LIST, Tools.toCommaSeparatedString(tickerList)).commit();
}
lastFetched = preferences.getString(LAST_FETCHED, null);
tickerList.addAll(DEFAULT_LIST);
fetch();
}
private void save() {
preferences.edit().remove(STOCK_LIST).commit();
preferences.edit().putStringSet(STOCK_LIST, tickerList).commit();
preferences.edit().putString(LAST_FETCHED, lastFetched).commit();
preferences.edit().remove(STOCK_LIST)
.putString(SORTED_STOCK_LIST, Tools.toCommaSeparatedString(tickerList))
.putString(LAST_FETCHED, lastFetched).commit();
}
@Override
@@ -108,7 +127,7 @@ public class StocksProvider implements IStocksProvider {
}
});
} else {
bus.post(new NoNetworkEvent());
scheduleUpdate(SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_FIFTEEN_MINUTES);
}
}
@@ -123,16 +142,23 @@ public class StocksProvider implements IStocksProvider {
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
context.sendBroadcast(intent);
bus.post(new StockUpdatedEvent());
scheduleUpdate(Tools.getMsToNextAlarm());
}
private void scheduleUpdate(long msToNextAlarm) {
final Intent updateReceiverIntent = new Intent(context, UpdateReceiver.class);
updateReceiverIntent.setAction(UPDATE_FILTER);
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0);
alarmManager.cancel(pendingIntent);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, updateReceiverIntent, 0);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Tools.getMsToNextAlarm(), pendingIntent);
msToNextAlarm, pendingIntent);
}
@Override
public Collection<String> addStock(String ticker) {
if (tickerList.contains(ticker)) {
return tickerList;
}
tickerList.add(ticker);
save();
fetch();
@@ -141,7 +167,11 @@ public class StocksProvider implements IStocksProvider {
@Override
public Collection<String> addStocks(Collection<String> tickers) {
tickerList.addAll(tickers);
for (String ticker : tickers) {
if (!tickerList.contains(ticker)) {
tickerList.add(ticker);
}
}
save();
fetch();
return tickerList;
@@ -163,11 +193,28 @@ public class StocksProvider implements IStocksProvider {
@Override
public Collection<Stock> getStocks() {
if (stockList != null) {
Collections.sort(stockList);
sortStockList();
}
return stockList;
}
private void sortStockList() {
Collections.sort(stockList, new Comparator<Stock>() {
@Override
public int compare(Stock lhs, Stock rhs) {
return ((Integer) stockList.indexOf(lhs.symbol))
.compareTo(stockList.indexOf(rhs.symbol));
}
});
}
@Override
public Collection<Stock> rearrange(List<String> tickers) {
tickerList = new ArrayList<>(tickers);
save();
return getStocks();
}
@Override
public List<String> getTickers() {
return new ArrayList<>(tickerList);
@@ -3,6 +3,7 @@ package com.github.premnirmal.ticker.network;
import android.content.Context;
import com.github.premnirmal.ticker.R;
import com.github.premnirmal.ticker.UpdateReceiver;
import com.github.premnirmal.ticker.model.IStocksProvider;
import com.github.premnirmal.ticker.model.StocksProvider;
import com.github.premnirmal.ticker.settings.SettingsActivity;
@@ -28,6 +29,7 @@ import retrofit.RestAdapter;
RemoteStockViewAdapter.class,
SettingsActivity.class,
StockWidget.class,
UpdateReceiver.class,
ParanormalActivity.class
},
complete = false,
@@ -21,18 +21,20 @@ public class Stock implements Comparable<Stock> {
}
static double getChangeFromPercentString(String percentString) {
if(percentString == null) {
if (percentString == null) {
return -1000000.0d;
}
return Double.valueOf(percentString.replace('%','\0').trim());
return Double.valueOf(percentString.replace('%', '\0').trim());
}
@Override
public boolean equals(Object o) {
if(o instanceof Stock) {
if(symbol != null) {
return symbol.replace("^","").equalsIgnoreCase(((Stock)o).symbol);
if (o instanceof Stock) {
if (symbol != null) {
return symbol.replace("^", "").equalsIgnoreCase(((Stock) o).symbol.replace("^", ""));
}
} else if (o instanceof String) {
return ((String) o).replace("^","").equalsIgnoreCase(symbol.replace("^", ""));
}
return false;
}
@@ -13,7 +13,7 @@ import java.util.Arrays;
/**
* Created by premnirmal on 12/22/14.
*/
public class FileImportTask extends AsyncTask<String, Void, Boolean> {
class FileImportTask extends AsyncTask<String, Void, Boolean> {
private final IStocksProvider stocksProvider;
@@ -9,9 +9,11 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.devpaul.filepickerlibrary.FilePickerActivity;
import com.github.premnirmal.ticker.BuildConfig;
import com.github.premnirmal.ticker.R;
import com.github.premnirmal.ticker.StocksApp;
import com.github.premnirmal.ticker.Tools;
@@ -95,6 +97,8 @@ public class SettingsActivity extends ActionBarActivity {
}
});
((TextView)findViewById(R.id.version)).setText("Version " + BuildConfig.VERSION_NAME);
}
@Override
@@ -24,6 +24,7 @@ import com.github.premnirmal.ticker.model.IStocksProvider;
import com.github.premnirmal.ticker.settings.SettingsActivity;
import com.github.premnirmal.ticker.widget.StockWidget;
import com.google.common.eventbus.Subscribe;
import com.terlici.dragndroplist.DragNDropListView;
import javax.inject.Inject;
@@ -88,9 +89,9 @@ public class ParanormalActivity extends ActionBarActivity {
}, 600);
}
final AdapterView adapterView = (AdapterView) findViewById(R.id.stockList);
final DragNDropListView adapterView = (DragNDropListView) findViewById(R.id.stockList);
final StocksAdapter adapter = new StocksAdapter(stocksProvider);
adapterView.setAdapter(adapter);
adapterView.setDragNDropAdapter(adapter);
adapterView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
@@ -11,6 +11,8 @@ import android.widget.TextView;
import com.github.premnirmal.ticker.R;
import com.github.premnirmal.ticker.model.IStocksProvider;
import com.github.premnirmal.ticker.network.Stock;
import com.terlici.dragndroplist.DragNDropAdapter;
import com.terlici.dragndroplist.DragNDropListView;
import java.util.ArrayList;
import java.util.List;
@@ -18,11 +20,13 @@ import java.util.List;
/**
* Created by premnirmal on 12/21/14.
*/
class StocksAdapter extends BaseAdapter {
class StocksAdapter extends BaseAdapter implements DragNDropAdapter {
final List<Stock> stockList;
private final List<Stock> stockList;
private final IStocksProvider stocksProvider;
StocksAdapter(IStocksProvider stocksProvider) {
this.stocksProvider = stocksProvider;
stockList = stocksProvider.getStocks() == null ? new ArrayList<Stock>()
: new ArrayList<>(stocksProvider.getStocks());
}
@@ -39,7 +43,7 @@ class StocksAdapter extends BaseAdapter {
@Override
public long getItemId(int position) {
return position;
return 0;
}
@Override
@@ -81,4 +85,25 @@ class StocksAdapter extends BaseAdapter {
return convertView;
}
@Override
public int getDragHandler() {
return R.id.dragHandler;
}
@Override
public void onItemDrag(DragNDropListView parent, View view, int position, long id) {
}
@Override
public void onItemDrop(DragNDropListView parent, View view, int startPosition, int endPosition, long id) {
stockList.add(endPosition, stockList.remove(startPosition));
final List<String> newTickerList = new ArrayList<>();
for(Stock stock : stockList) {
newTickerList.add(stock.symbol);
}
stocksProvider.rearrange(newTickerList);
notifyDataSetChanged();
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2012 Terlici Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.terlici.dragndroplist;
import android.widget.ListAdapter;
public interface DragNDropAdapter extends ListAdapter, DragNDropListView.OnItemDragNDropListener {
public int getDragHandler();
}
@@ -0,0 +1,110 @@
/*
* Copyright 2012 Terlici Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.terlici.dragndroplist;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.view.ViewGroup;
public class DragNDropCursorAdapter extends SimpleCursorAdapter implements DragNDropAdapter {
int mPosition[];
int mHandler;
public DragNDropCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int handler) {
super(context, layout, cursor, from, to, 0);
mHandler = handler;
setup();
}
@Override
public Cursor swapCursor(Cursor c) {
Cursor cursor = super.swapCursor(c);
mPosition = null;
setup();
return cursor;
}
private void setup() {
Cursor c = getCursor();
if (c == null || !c.moveToFirst()) return;
mPosition = new int[c.getCount()];
for (int i = 0; i < mPosition.length; ++i) mPosition[i] = i;
}
@Override
public View getDropDownView(int position, View view, ViewGroup group) {
return super.getDropDownView(mPosition[position], view, group);
}
@Override
public Object getItem(int position) {
return super.getItem(mPosition[position]);
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(mPosition[position]);
}
@Override
public long getItemId(int position) {
return super.getItemId(mPosition[position]);
}
@Override
public View getView(int position, View view, ViewGroup group) {
return super.getView(mPosition[position], view, group);
}
@Override
public boolean isEnabled(int position) {
return super.isEnabled(mPosition[position]);
}
@Override
public void onItemDrag(DragNDropListView parent, View view, int position, long id) {
}
@Override
public void onItemDrop(DragNDropListView parent, View view, int startPosition, int endPosition, long id) {
int position = mPosition[startPosition];
if (startPosition < endPosition)
for(int i = startPosition; i < endPosition; ++i)
mPosition[i] = mPosition[i + 1];
else if (endPosition < startPosition)
for(int i = startPosition; i > endPosition; --i)
mPosition[i] = mPosition[i - 1];
mPosition[endPosition] = position;
}
@Override
public int getDragHandler() {
return mHandler;
}
}
@@ -0,0 +1,288 @@
/*
* Copyright 2012 Terlici Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.terlici.dragndroplist;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Adapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.WrapperListAdapter;
public class DragNDropListView extends ListView {
public static interface OnItemDragNDropListener {
public void onItemDrag(DragNDropListView parent, View view, int position, long id);
public void onItemDrop(DragNDropListView parent, View view, int startPosition, int endPosition, long id);
}
boolean mDragMode;
WindowManager mWm;
int mStartPosition = INVALID_POSITION;
int mDragPointOffset; // Used to adjust drag view location
int mDragHandler = 0;
ImageView mDragView;
OnItemDragNDropListener mDragNDropListener;
private void init() {
mWm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
}
public DragNDropListView(Context context) {
super(context);
init();
}
public DragNDropListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DragNDropListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setOnItemDragNDropListener(OnItemDragNDropListener listener) {
mDragNDropListener = listener;
}
public void setDragNDropAdapter(DragNDropAdapter adapter) {
mDragHandler = adapter.getDragHandler();
setAdapter(adapter);
}
/**
* If the motion event was inside a handler view.
*
* @param ev
* @return true if it is a dragging move, false otherwise.
*/
public boolean isDrag(MotionEvent ev) {
if (mDragMode) return true;
if (mDragHandler == 0) return false;
int x = (int)ev.getX();
int y = (int)ev.getY();
int startposition = pointToPosition(x,y);
if (startposition == INVALID_POSITION) return false;
int childposition = startposition - getFirstVisiblePosition();
View parent = getChildAt(childposition);
View handler = parent.findViewById(mDragHandler);
if (handler == null) return false;
int top = parent.getTop() + handler.getTop();
int bottom = top + handler.getHeight();
int left = parent.getLeft() + handler.getLeft();
int right = left + handler.getWidth();
return left <= x && x <= right && top <= y && y <= bottom;
}
public boolean isDragging() {
return mDragMode;
}
public View getDragView() {
return mDragView;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int x = (int)ev.getX();
final int y = (int)ev.getY();
if (action == MotionEvent.ACTION_DOWN && isDrag(ev)) mDragMode = true;
if (!mDragMode) return super.onTouchEvent(ev);
switch (action) {
case MotionEvent.ACTION_DOWN:
mStartPosition = pointToPosition(x, y);
if (mStartPosition != INVALID_POSITION) {
int childPosition = mStartPosition - getFirstVisiblePosition();
mDragPointOffset = y - getChildAt(childPosition).getTop();
mDragPointOffset -= ((int)ev.getRawY()) - y;
startDrag(childPosition, y);
drag(0, y);
}
break;
case MotionEvent.ACTION_MOVE:
drag(0, y);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
default:
mDragMode = false;
if (mStartPosition != INVALID_POSITION) {
// check if the position is a header/footer
int actualPosition = pointToPosition(x,y);
if (actualPosition > (getCount() - getFooterViewsCount()) - 1)
actualPosition = INVALID_POSITION;
stopDrag(mStartPosition - getFirstVisiblePosition(), actualPosition);
}
break;
}
return true;
}
/**
* Prepare the drag view.
*
* @param childIndex
* @param y
*/
private void startDrag(int childIndex, int y) {
View item = getChildAt(childIndex);
if (item == null) return;
long id = getItemIdAtPosition(mStartPosition);
if (mDragNDropListener != null)
mDragNDropListener.onItemDrag(this, item, mStartPosition, id);
Adapter adapter = getAdapter();
DragNDropAdapter dndAdapter;
// if exists a footer/header we have our adapter wrapped
if (adapter instanceof WrapperListAdapter) {
dndAdapter = (DragNDropAdapter)((WrapperListAdapter)adapter).getWrappedAdapter();
} else {
dndAdapter = (DragNDropAdapter)adapter;
}
dndAdapter.onItemDrag(this, item, mStartPosition, id);
item.setDrawingCacheEnabled(true);
// Create a copy of the drawing cache so that it does not get recycled
// by the framework when the list tries to clean up memory
Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();
mWindowParams.gravity = Gravity.TOP;
mWindowParams.x = 0;
mWindowParams.y = y - mDragPointOffset;
mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
mWindowParams.format = PixelFormat.TRANSLUCENT;
mWindowParams.windowAnimations = 0;
Context context = getContext();
ImageView v = new ImageView(context);
v.setImageBitmap(bitmap);
mWm.addView(v, mWindowParams);
mDragView = v;
item.setVisibility(View.INVISIBLE);
item.invalidate(); // We have not changed anything else.
}
/**
* Release all dragging resources.
*
* @param childIndex
*/
private void stopDrag(int childIndex, int endPosition) {
if (mDragView == null) return;
View item = getChildAt(childIndex);
if (endPosition != INVALID_POSITION) {
long id = getItemIdAtPosition(mStartPosition);
if (mDragNDropListener != null)
mDragNDropListener.onItemDrop(this, item, mStartPosition, endPosition, id);
Adapter adapter = getAdapter();
DragNDropAdapter dndAdapter;
// if exists a footer/header we have our adapter wrapped
if (adapter instanceof WrapperListAdapter) {
dndAdapter = (DragNDropAdapter)((WrapperListAdapter)adapter).getWrappedAdapter();
} else {
dndAdapter = (DragNDropAdapter)adapter;
}
dndAdapter.onItemDrop(this, item, mStartPosition, endPosition, id);
}
mDragView.setVisibility(GONE);
mWm.removeView(mDragView);
mDragView.setImageDrawable(null);
mDragView = null;
item.setDrawingCacheEnabled(false);
item.destroyDrawingCache();
item.setVisibility(View.VISIBLE);
mStartPosition = INVALID_POSITION;
invalidateViews(); // We have changed the adapter data, so change everything
}
/**
* Move the drag view.
*
* @param x
* @param y
*/
private void drag(int x, int y) {
if (mDragView == null) return;
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams)mDragView.getLayoutParams();
layoutParams.x = x;
layoutParams.y = y - mDragPointOffset;
mWm.updateViewLayout(mDragView, layoutParams);
}
}
@@ -0,0 +1,97 @@
/*
* Copyright 2012 Terlici Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.terlici.dragndroplist;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;
public class DragNDropSimpleAdapter extends SimpleAdapter implements DragNDropAdapter {
int mPosition[];
int mHandler;
public DragNDropSimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to, int handler) {
super(context, data, resource, from, to);
mHandler = handler;
setup(data.size());
}
private void setup(int size) {
mPosition = new int[size];
for (int i = 0; i < size; ++i) mPosition[i] = i;
}
@Override
public View getDropDownView(int position, View view, ViewGroup group) {
return super.getDropDownView(mPosition[position], view, group);
}
@Override
public Object getItem(int position) {
return super.getItem(mPosition[position]);
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(mPosition[position]);
}
@Override
public long getItemId(int position) {
return super.getItemId(mPosition[position]);
}
@Override
public View getView(int position, View view, ViewGroup group) {
return super.getView(mPosition[position], view, group);
}
@Override
public boolean isEnabled(int position) {
return super.isEnabled(mPosition[position]);
}
@Override
public void onItemDrag(DragNDropListView parent, View view, int position, long id) {
}
@Override
public void onItemDrop(DragNDropListView parent, View view, int startPosition, int endPosition, long id) {
int position = mPosition[startPosition];
if (startPosition < endPosition)
for(int i = startPosition; i < endPosition; ++i)
mPosition[i] = mPosition[i + 1];
else if (endPosition < startPosition)
for(int i = startPosition; i > endPosition; --i)
mPosition[i] = mPosition[i - 1];
mPosition[endPosition] = position;
}
@Override
public int getDragHandler() {
return mHandler;
}
}
@@ -15,13 +15,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<GridView
<com.terlici.dragndroplist.DragNDropListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:scrollbars="none"
android:numColumns="2"
android:horizontalSpacing="10dp"
android:id="@+id/stockList"
/>
@@ -48,4 +48,15 @@
<include layout="@layout/divider"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:id="@+id/version"
android:linksClickable="true"
android:autoLink="all"
/>
<include layout="@layout/divider"/>
</LinearLayout>
+38 -11
View File
@@ -1,5 +1,6 @@
<?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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -7,50 +8,76 @@
android:paddingRight="5dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:id="@+id/row"
>
android:id="@+id/row">
<TextView
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_weight="0.2"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textSize="16sp"
android:singleLine="true"
android:textStyle="bold"
tools:text="GOOG"
android:layout_gravity="center_vertical"
android:id="@+id/ticker" />
<TextView
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_weight="0.3"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textSize="16sp"
android:singleLine="true"
tools:text="GOOG"
android:layout_gravity="center_vertical"
android:id="@+id/totalValue" />
<ViewFlipper
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_weight="0.2"
android:layout_height="wrap_content"
android:flipInterval="@integer/flip_time"
android:autoStart="true"
>
android:layout_gravity="center_vertical"
android:autoStart="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textSize="16sp"
android:singleLine="true"
android:id="@+id/changePercent"
tools:text="GOOG"
android:gravity="end" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textSize="16sp"
android:singleLine="true"
android:id="@+id/changeValue"
tools:text="GOOG"
android:gravity="end" />
</ViewFlipper>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="20dp"
android:id="@+id/dragHandler">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@android:drawable/arrow_up_float" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@android:drawable/arrow_down_float" />
</LinearLayout>
</LinearLayout>