From 62b06ef1e81998edb42030228c18066c09ea4495 Mon Sep 17 00:00:00 2001 From: Kala30 Date: Thu, 5 Jul 2018 18:40:46 -0700 Subject: [PATCH] Added DragListView --- app/build.gradle | 4 +- .../overwidget/AddProfileTask.java | 9 +- .../cogentworks/overwidget/ItemAdapter.java | 147 ++++++++++++++++++ .../cogentworks/overwidget/MainActivity.java | 133 +++++++++------- .../overwidget/OWSwipeRefreshLayout.java | 28 ++++ .../com/cogentworks/overwidget/Profile.java | 2 + .../com/cogentworks/overwidget/SQLHelper.java | 18 ++- .../overwidget/UpdateListTask.java | 16 +- app/src/main/res/layout/content_main.xml | 6 +- app/src/main/res/layout/list_item.xml | 141 ++++++++++------- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/styles.xml | 2 +- 12 files changed, 379 insertions(+), 128 deletions(-) create mode 100644 app/src/main/java/com/cogentworks/overwidget/ItemAdapter.java create mode 100644 app/src/main/java/com/cogentworks/overwidget/OWSwipeRefreshLayout.java diff --git a/app/build.gradle b/app/build.gradle index 3af7b07..021c60d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.cogentworks.overwidget" minSdkVersion 16 targetSdkVersion 27 - versionCode 9 - versionName "0.4.2" + versionCode 10 + versionName "0.5.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } diff --git a/app/src/main/java/com/cogentworks/overwidget/AddProfileTask.java b/app/src/main/java/com/cogentworks/overwidget/AddProfileTask.java index b3dac5e..d689fb2 100644 --- a/app/src/main/java/com/cogentworks/overwidget/AddProfileTask.java +++ b/app/src/main/java/com/cogentworks/overwidget/AddProfileTask.java @@ -5,6 +5,8 @@ import android.os.AsyncTask; import android.support.design.widget.Snackbar; +import com.woxthebox.draglistview.DragItemAdapter; + import java.io.IOException; public class AddProfileTask extends AsyncTask { @@ -26,7 +28,9 @@ public AddProfileTask(Context context, String battleTag, String platform, String protected Profile doInBackground(String... params) { ((MainActivity)context).isBusy = true; try { - return WidgetUtils.getProfile(battleTag, platform, region, null, null); + Profile profile = WidgetUtils.getProfile(battleTag, platform, region, null, null); + profile.Id = profile.BattleTag.hashCode(); + return profile; } catch (IOException ex) { ex.printStackTrace(); Snackbar.make(((Activity) context).findViewById(R.id.swiperefresh), "An error occurred", Snackbar.LENGTH_LONG).show(); @@ -39,7 +43,8 @@ protected void onPostExecute(Profile result) { if (result != null && result.BattleTag != null) { MainActivity activity = (MainActivity) context; activity.dbHelper.insertNewProfile(battleTag, result); - activity.showItemList(); + DragItemAdapter adapter = activity.mDragListView.getAdapter(); + adapter.addItem(adapter.getItemCount(), result); } else { String error; if (result != null) diff --git a/app/src/main/java/com/cogentworks/overwidget/ItemAdapter.java b/app/src/main/java/com/cogentworks/overwidget/ItemAdapter.java new file mode 100644 index 0000000..f825bbf --- /dev/null +++ b/app/src/main/java/com/cogentworks/overwidget/ItemAdapter.java @@ -0,0 +1,147 @@ +package com.cogentworks.overwidget; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.woxthebox.draglistview.DragItemAdapter; + +import java.util.List; + +public class ItemAdapter extends DragItemAdapter { + + private int mLayoutId; + private int mGrabHandleId; + private boolean mDragOnLongPress; + + public ItemAdapter(List list, int layoutId, int grabHandleId, boolean dragOnLongPress) { + mLayoutId = layoutId; + mGrabHandleId = grabHandleId; + mDragOnLongPress = dragOnLongPress; + setItemList(list); + } + + @Override + public long getUniqueItemId(int position) { + return mItemList.get(position).Id; + } + + @Override + public void onBindViewHolder(@NonNull OWViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + Profile profile = mItemList.get(position); + holder.itemView.setTag(profile); + Context context = holder.itemView.getContext(); + boolean isDark = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsActivity.PREF_DARK_THEME, false); + + String[] parts = profile.BattleTag.split("#"); + String username = parts[0]; + holder.name.setText(username); + if (parts.length > 1) { + holder.tag.setText("#" + parts[1]); + } + + if(Integer.parseInt(profile.gamesWon) > 0) + holder.gamesWon.setText(profile.gamesWon + " games won"); + + holder.level.setText("Lvl " + (Integer.parseInt(profile.Prestige)*100 + Integer.parseInt(profile.Level))); + if (!profile.Tier.equals("") && !profile.Tier.equals("nullrank")) { + holder.tier.setImageResource(context.getResources().getIdentifier(profile.Tier, "drawable", context.getPackageName())); + if (isDark) + holder.comprank.setImageBitmap(WidgetUtils.BuildTextBmp(profile.CompRank, "Dark", context)); + else + holder.comprank.setImageBitmap(WidgetUtils.BuildTextBmp(profile.CompRank, "Light", context)); + } else { + holder.itemView.findViewById(R.id.skill_layout).setVisibility(View.GONE); + } + + String platform = profile.Platform; + if (!(profile.Region.equals("") || profile.Region.equals("any"))) + platform += " " + profile.Region; + + holder.info.setText(platform); + try { + Glide.with(context) + .load(profile.AvatarURL) + .into((ImageView) holder.itemView.findViewById(R.id.avatar)); + } catch (Exception e) { + Glide.with(context) + .load("https://us.battle.net/forums/static/images/avatars/overwatch/avatar-overwatch-default.png") + .into((ImageView) holder.itemView.findViewById(R.id.avatar)); + } + } + + @NonNull + @Override + public OWViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false); + return new OWViewHolder(view); + } + + class OWViewHolder extends DragItemAdapter.ViewHolder { + + TextView name; + TextView info; + TextView tag; + TextView level; + TextView gamesWon; + ImageView comprank; + ImageView tier; + + OWViewHolder(final View itemView) { + super(itemView, mGrabHandleId, mDragOnLongPress); + + name = itemView.findViewById(R.id.name); + tag = itemView.findViewById(R.id.tag); + level = itemView.findViewById(R.id.level); + gamesWon = itemView.findViewById(R.id.games_won); + info = itemView.findViewById(R.id.info); + comprank = itemView.findViewById(R.id.appwidget_comprank); + tier = itemView.findViewById(R.id.appwidget_tier); + } + + @Override + public void onItemClicked(View view) { + final View mView = view; + AlertDialog dialog = new AlertDialog.Builder(view.getContext()) + .setTitle("Open in Browser") + .setItems(R.array.link_array, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String battleTag = (name.getText().toString() + tag.getText()).replace('#','-'); + String platform = info.getText().toString().split(" ")[0].toLowerCase(); + Intent i = new Intent(Intent.ACTION_VIEW); + switch (which) { + case 0: + i.setData(Uri.parse("http://playoverwatch.com/career/" + platform + "/" + battleTag)); + mView.getContext().startActivity(i); + break; + case 1: + i.setData(Uri.parse("https://www.overbuff.com/players/" + platform + "/" + battleTag)); + mView.getContext().startActivity(i); + break; + } + } + }) + .setNegativeButton("Cancel", null) + .create(); + dialog.show(); + } + + @Override + public boolean onItemLongClicked(View view) { + Toast.makeText(view.getContext(), "Item long clicked", Toast.LENGTH_SHORT).show(); + return true; + } + } +} diff --git a/app/src/main/java/com/cogentworks/overwidget/MainActivity.java b/app/src/main/java/com/cogentworks/overwidget/MainActivity.java index 7763b42..1a842a6 100644 --- a/app/src/main/java/com/cogentworks/overwidget/MainActivity.java +++ b/app/src/main/java/com/cogentworks/overwidget/MainActivity.java @@ -5,25 +5,28 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.design.widget.Snackbar; +import android.support.v4.content.ContextCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; -import android.util.Log; +import android.support.v7.widget.LinearLayoutManager; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; import android.widget.Toast; -import com.google.gson.Gson; +import com.woxthebox.draglistview.DragListView; +import com.woxthebox.draglistview.swipe.ListSwipeHelper; +import com.woxthebox.draglistview.swipe.ListSwipeItem; + +import java.util.ArrayList; public class MainActivity extends AppCompatActivity { @@ -33,6 +36,9 @@ public class MainActivity extends AppCompatActivity { ProfileAdapter adapter; ListView listView; + public DragListView mDragListView; + ArrayList mItemArray; + boolean isBusy = false; @Override @@ -51,13 +57,11 @@ protected void onCreate(Bundle savedInstanceState) { // Set swipe to refresh behavior final MainActivity activityContext = this; - SwipeRefreshLayout mSwipeRefreshLayout = findViewById(R.id.swiperefresh); + OWSwipeRefreshLayout mSwipeRefreshLayout = findViewById(R.id.swiperefresh); mSwipeRefreshLayout.setOnRefreshListener( new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { - Log.i(TAG, "onRefresh called from SwipeRefreshLayout"); - // This method performs the actual data-refresh operation. // The method calls setRefreshing(false) when it's finished. UpdateListTask updateListTask = new UpdateListTask(activityContext, dbHelper.getList()); @@ -67,69 +71,81 @@ public void onRefresh() { ); dbHelper = new SQLHelper(this); - listView = findViewById(R.id.list); + mItemArray = dbHelper.getList(); + + final OWSwipeRefreshLayout mRefreshLayout = mSwipeRefreshLayout; - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + mDragListView = (DragListView) findViewById(R.id.list); + mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true); + mDragListView.setDragListListener(new DragListView.DragListListenerAdapter() { @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - final int mPosition = position; - AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) - .setTitle("Open in Browser") - .setItems(R.array.link_array, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - Profile profile = dbHelper.getList().get(mPosition); - Intent i = new Intent(Intent.ACTION_VIEW); - switch (which) { - case 0: - i.setData(Uri.parse("http://playoverwatch.com/career/" + profile.Platform.toLowerCase() + "/" + profile.BattleTag.replace('#','-'))); - startActivity(i); - break; - case 1: - i.setData(Uri.parse("https://www.overbuff.com/players/" + profile.Platform.toLowerCase() + "/" + profile.BattleTag.replace('#','-'))); - startActivity(i); - break; - } - } - }) - .setNegativeButton("Cancel", null) - .create(); - dialog.show(); + public void onItemDragStarted(int position) { + mRefreshLayout.setEnabled(false); + //Toast.makeText(mDragListView.getContext(), "Start - position: " + position, Toast.LENGTH_SHORT).show(); } - }); - listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + public void onItemDragEnded(int fromPosition, int toPosition) { if (!isBusy) { - final int mPosition = position; - AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) - .setTitle("Delete Profile") - .setMessage("Are you sure you want to delete?") - .setPositiveButton("Delete", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - isBusy = true; - Gson gson = new Gson(); - dbHelper.deleteItem(gson.toJson(listView.getItemAtPosition(mPosition))); - showItemList(); - isBusy = false; - } - }) - .setNegativeButton("Cancel", null) - .create(); - dialog.show(); - } else { - Toast.makeText(MainActivity.this, "List is busy", Toast.LENGTH_LONG).show(); + mRefreshLayout.setEnabled(true); + if (fromPosition != toPosition) { + dbHelper.setList(mItemArray); + //Toast.makeText(mDragListView.getContext(), "End - position: " + toPosition, Toast.LENGTH_SHORT).show(); + } } + } + }); - return true; + mRefreshLayout.setScrollingView(mDragListView.getRecyclerView()); + if (useDarkTheme) + mRefreshLayout.setColorSchemeColors(ContextCompat.getColor(this, R.color.colorAccentDark)); + else + mRefreshLayout.setColorSchemeColors(ContextCompat.getColor(this, R.color.colorAccent)); + + mDragListView.setSwipeListener(new ListSwipeHelper.OnSwipeListenerAdapter() { + @Override + public void onItemSwipeStarted(ListSwipeItem item) { + mRefreshLayout.setEnabled(false); + } + + @Override + public void onItemSwipeEnded(ListSwipeItem item, ListSwipeItem.SwipeDirection swipedDirection) { + mRefreshLayout.setEnabled(true); + // Swipe to delete on left + if (swipedDirection == ListSwipeItem.SwipeDirection.LEFT || swipedDirection == ListSwipeItem.SwipeDirection.RIGHT) { + if (!isBusy) { + final Profile adapterItem = (Profile) item.getTag(); + final int pos = mDragListView.getAdapter().getPositionForItem(adapterItem); + + isBusy = true; + dbHelper.deleteItem(adapterItem.BattleTag); + mDragListView.getAdapter().removeItem(pos); + isBusy = false; + } else { + Toast.makeText(MainActivity.this, "List is busy", Toast.LENGTH_LONG).show(); + } + } } }); - showItemList(); + setupListRecyclerView(); + + isBusy = true; + mSwipeRefreshLayout.setRefreshing(true); + UpdateListTask updateListTask = new UpdateListTask(this, mItemArray); + updateListTask.execute(); + + } + + private void setupListRecyclerView() { + mDragListView.setLayoutManager(new LinearLayoutManager(this)); + ItemAdapter listAdapter = new ItemAdapter(mItemArray, R.layout.list_item, R.id.layout_main, true); + mDragListView.setAdapter(listAdapter, true); + mDragListView.setCanDragHorizontally(false); + //mDragListView.setCustomDragItem(new MyDragItem(getContext(), R.layout.list_item)); } - public void showItemList() { + /*public void showItemList() { isBusy = true; if (adapter == null) { @@ -147,7 +163,7 @@ public void showItemList() { } isBusy = false; - } + }*/ public void onFabClick(View view) { final Context context = this; @@ -249,5 +265,4 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } - } diff --git a/app/src/main/java/com/cogentworks/overwidget/OWSwipeRefreshLayout.java b/app/src/main/java/com/cogentworks/overwidget/OWSwipeRefreshLayout.java new file mode 100644 index 0000000..326227d --- /dev/null +++ b/app/src/main/java/com/cogentworks/overwidget/OWSwipeRefreshLayout.java @@ -0,0 +1,28 @@ +package com.cogentworks.overwidget; + +import android.content.Context; +import android.support.v4.view.ViewCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.util.AttributeSet; +import android.view.View; + +public class OWSwipeRefreshLayout extends SwipeRefreshLayout { + private View mScrollingView; + + public OWSwipeRefreshLayout(Context context) { + super(context); + } + + public OWSwipeRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean canChildScrollUp() { + return mScrollingView != null && ViewCompat.canScrollVertically(mScrollingView, -1); + } + + public void setScrollingView(View scrollingView) { + mScrollingView = scrollingView; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cogentworks/overwidget/Profile.java b/app/src/main/java/com/cogentworks/overwidget/Profile.java index df1b55e..135d2f6 100644 --- a/app/src/main/java/com/cogentworks/overwidget/Profile.java +++ b/app/src/main/java/com/cogentworks/overwidget/Profile.java @@ -27,6 +27,8 @@ public class Profile { private String errorMsg; private String theme; + public int Id; + public Profile() {} public Profile(String battleTag, String platform, String region) { diff --git a/app/src/main/java/com/cogentworks/overwidget/SQLHelper.java b/app/src/main/java/com/cogentworks/overwidget/SQLHelper.java index cf7efee..6a42419 100644 --- a/app/src/main/java/com/cogentworks/overwidget/SQLHelper.java +++ b/app/src/main/java/com/cogentworks/overwidget/SQLHelper.java @@ -33,6 +33,22 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { onCreate(db); } + public void setList(ArrayList list) { + SQLiteDatabase db = this.getWritableDatabase(); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); + onCreate(db); + + for (Profile profile : list) { + ContentValues values = new ContentValues(); + values.put("BattleTag", profile.BattleTag); + values.put(COL_NAME, profile.toGson()); + + db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE); + } + + db.close(); + } + public void insertNewProfile(String battleTag, Profile profile) { SQLiteDatabase db = this.getWritableDatabase(); @@ -57,7 +73,7 @@ public void updateItem(String battleTag, Profile profile) { public void deleteItem(String item) { SQLiteDatabase db = this.getWritableDatabase(); - db.delete(TABLE_NAME, COL_NAME + " = ?", new String[]{item}); + db.delete(TABLE_NAME, "BattleTag = ?", new String[]{item}); db.close(); } diff --git a/app/src/main/java/com/cogentworks/overwidget/UpdateListTask.java b/app/src/main/java/com/cogentworks/overwidget/UpdateListTask.java index e3c6039..182a6d5 100644 --- a/app/src/main/java/com/cogentworks/overwidget/UpdateListTask.java +++ b/app/src/main/java/com/cogentworks/overwidget/UpdateListTask.java @@ -34,8 +34,12 @@ protected ArrayList doInBackground(String... params) { try { for (int i = 0; i < profiles.size(); i++) { Profile profile = profiles.get(i); - profiles.set(i, WidgetUtils.getProfile(profile.BattleTag, profile.Platform, profile.Region, null, null)); + int id = profile.Id; Log.d("UpdateListTask", profile.BattleTag); + + profile = WidgetUtils.getProfile(profile.BattleTag, profile.Platform, profile.Region, null, null); + profile.Id = id; + profiles.set(i, profile); } return profiles; } catch (IOException ex) { @@ -52,14 +56,10 @@ protected ArrayList doInBackground(String... params) { protected void onPostExecute(ArrayList result) { if (result != null) { MainActivity activity = (MainActivity) context; - for (Profile profile : result) - try { - activity.dbHelper.updateItem(profile.BattleTag, profile); - } catch (IndexOutOfBoundsException ex) { - ex.printStackTrace(); - } - activity.showItemList(); + activity.dbHelper.setList(result); + activity.mDragListView.getAdapter().setItemList(result); + } else { if (error) Snackbar.make(((Activity) context).findViewById(R.id.layout_main), "An update error occurred", Snackbar.LENGTH_LONG).show(); diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 4ff282f..2df9614 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml index c9d2c85..3f8caa8 100644 --- a/app/src/main/res/layout/list_item.xml +++ b/app/src/main/res/layout/list_item.xml @@ -1,79 +1,116 @@ - + app:leftViewId="@+id/item_left" + app:rightViewId="@+id/item_right" + app:swipeViewId="@+id/item_layout"> - + - + + + android:padding="16dp"> + + + android:layout_gravity="center_horizontal" + android:layout_toRightOf="@+id/avatar" + android:orientation="vertical" + android:paddingLeft="8dp"> - + android:orientation="horizontal"> - + - + - - - + + android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" /> - + android:orientation="horizontal"> - + + + - + + + - + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 6fda7b2..b9ad823 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,4 +3,5 @@ #F5F5F5 #E0E0E0 #FF9800 + #f44336 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ad3a846..d2b66d6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -13,7 +13,7 @@ - #f44336 + @color/colorAccentDark false