mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-25 16:15:55 +01:00
SwipingView of Sports Activity Detail (#1977)
Swipable view done WIP. Basic POC. Co-authored-by: vanous <petr@linuks.cz> Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/1977
This commit is contained in:
parent
6e62e26331
commit
ed5b4ac793
@ -72,6 +72,7 @@ public class ActivitySummariesActivity extends AbstractListActivity<BaseActivity
|
||||
private GBDevice mGBDevice;
|
||||
private SwipeRefreshLayout swipeLayout;
|
||||
LinkedHashMap<String , Integer> activityKindMap = new LinkedHashMap<>(1);
|
||||
int activityFilter=0;
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
@ -130,7 +131,7 @@ public class ActivitySummariesActivity extends AbstractListActivity<BaseActivity
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
int activityFilter=0;
|
||||
|
||||
setItemAdapter(new ActivitySummariesAdapter(this, mGBDevice,activityFilter));
|
||||
|
||||
getItemListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@ -140,7 +141,7 @@ public class ActivitySummariesActivity extends AbstractListActivity<BaseActivity
|
||||
if (item != null) {
|
||||
ActivitySummary summary = (ActivitySummary) item;
|
||||
try {
|
||||
showActivityDetail(summary);
|
||||
showActivityDetail(position);
|
||||
} catch (Exception e) {
|
||||
GB.toast(getApplicationContext(), "Unable to display Activity Detail, maybe the activity is not available yet: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
}
|
||||
@ -267,7 +268,8 @@ public class ActivitySummariesActivity extends AbstractListActivity<BaseActivity
|
||||
public class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
|
||||
setActivityKindFilter(activityKindMap.get(parent.getItemAtPosition(pos)));
|
||||
activityFilter=activityKindMap.get(parent.getItemAtPosition(pos));
|
||||
setActivityKindFilter(activityFilter);
|
||||
refresh();
|
||||
}
|
||||
|
||||
@ -317,16 +319,13 @@ public class ActivitySummariesActivity extends AbstractListActivity<BaseActivity
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void showActivityDetail(ActivitySummary summary){
|
||||
private void showActivityDetail(int position){
|
||||
Intent ActivitySummaryDetailIntent = new Intent(this, ActivitySummaryDetail.class);
|
||||
ActivitySummaryDetailIntent.putExtra("name", summary.getName());
|
||||
ActivitySummaryDetailIntent.putExtra("ActivityKind", summary.getActivityKind());
|
||||
ActivitySummaryDetailIntent.putExtra("StartTime", summary.getStartTime());
|
||||
ActivitySummaryDetailIntent.putExtra("EndTime", summary.getEndTime());
|
||||
ActivitySummaryDetailIntent.putExtra("GpxTrack", summary.getGpxTrack());
|
||||
ActivitySummaryDetailIntent.putExtra("SummaryData", summary.getSummaryData());
|
||||
ActivitySummaryDetailIntent.putExtra("position", position);
|
||||
ActivitySummaryDetailIntent.putExtra("filter", activityFilter);
|
||||
ActivitySummaryDetailIntent.putExtra(GBDevice.EXTRA_DEVICE, mGBDevice);
|
||||
startActivity(ActivitySummaryDetailIntent);
|
||||
|
||||
}
|
||||
|
||||
private void fetchTrackData() {
|
||||
|
@ -17,14 +17,18 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
@ -43,26 +47,94 @@ import java.util.Iterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryItems;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.SwipeEvents;
|
||||
|
||||
public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActivitySummaryDetail.class);
|
||||
private GBDevice mGBDevice;
|
||||
private JSONObject groupData = setGroups();
|
||||
private boolean show_raw_data = false;
|
||||
BaseActivitySummary currentItem = null;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_summary_details);
|
||||
Intent intent = getIntent();
|
||||
mGBDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
final int filter = intent.getIntExtra("filter",0);
|
||||
final int position = intent.getIntExtra("position",0);
|
||||
final ActivitySummaryItems items = new ActivitySummaryItems(this, mGBDevice, filter);
|
||||
final RelativeLayout layout = findViewById(R.id.activity_summary_detail_relative_layout);
|
||||
|
||||
final String gpxTrack = intent.getStringExtra("GpxTrack");
|
||||
final Animation animFadein;
|
||||
final Animation animFadeout;
|
||||
animFadein = AnimationUtils.loadAnimation(
|
||||
this,
|
||||
R.anim.flyright);
|
||||
animFadeout = AnimationUtils.loadAnimation(
|
||||
this,
|
||||
R.anim.flyleft);
|
||||
|
||||
layout.setOnTouchListener(new SwipeEvents(this) {
|
||||
@Override
|
||||
public void onSwipeRight() {
|
||||
currentItem = items.getNextItem();
|
||||
if (currentItem != null) {
|
||||
makeSummaryHeader(currentItem);
|
||||
makeSummaryContent(currentItem);
|
||||
layout.startAnimation(animFadein);
|
||||
|
||||
}else{
|
||||
GB.toast("No more items", Toast.LENGTH_SHORT,0);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onSwipeLeft() {
|
||||
currentItem = items.getPrevItem();
|
||||
if (currentItem != null) {
|
||||
makeSummaryHeader(currentItem);
|
||||
makeSummaryContent(currentItem);
|
||||
layout.startAnimation(animFadeout);
|
||||
}else{
|
||||
GB.toast("No more items", Toast.LENGTH_SHORT,0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
currentItem = items.getItem(position);
|
||||
if (currentItem != null) {
|
||||
makeSummaryHeader(currentItem);
|
||||
makeSummaryContent(currentItem);
|
||||
}
|
||||
|
||||
//allows long-press.switch of data being in raw form or recalculated
|
||||
ImageView activity_icon = (ImageView) findViewById(R.id.item_image);
|
||||
activity_icon.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
public boolean onLongClick(View v) {
|
||||
show_raw_data=!show_raw_data;
|
||||
if (currentItem != null) {
|
||||
makeSummaryHeader(currentItem);
|
||||
makeSummaryContent(currentItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void makeSummaryHeader(BaseActivitySummary item){
|
||||
//make view of data from main part of item
|
||||
final String gpxTrack = item.getGpxTrack();
|
||||
Button show_track_btn = (Button) findViewById(R.id.showTrack);
|
||||
show_track_btn.setVisibility(View.GONE);
|
||||
|
||||
@ -78,15 +150,16 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
}
|
||||
});
|
||||
}
|
||||
String activitykindname = ActivityKind.asString(intent.getIntExtra("ActivityKind",0), getApplicationContext());
|
||||
Date starttime = (Date) intent.getSerializableExtra("StartTime");
|
||||
Date endtime = (Date) intent.getSerializableExtra("EndTime");
|
||||
String activitykindname = ActivityKind.asString(item.getActivityKind(), getApplicationContext());
|
||||
Date starttime = (Date) item.getStartTime();
|
||||
Date endtime = (Date) item.getEndTime();
|
||||
String starttimeS = DateTimeUtils.formatDateTime(starttime);
|
||||
String endtimeS = DateTimeUtils.formatDateTime(endtime);
|
||||
String durationhms = DateTimeUtils.formatDurationHoursMinutes((endtime.getTime() - starttime.getTime()), TimeUnit.MILLISECONDS);
|
||||
|
||||
ImageView activity_icon = (ImageView) findViewById(R.id.item_image);
|
||||
activity_icon.setImageResource(ActivityKind.getIconId(intent.getIntExtra("ActivityKind",0)));
|
||||
activity_icon.setImageResource(ActivityKind.getIconId(item.getActivityKind()));
|
||||
|
||||
TextView activity_kind = (TextView) findViewById(R.id.activitykind);
|
||||
activity_kind.setText(activitykindname);
|
||||
TextView start_time = (TextView) findViewById(R.id.starttime);
|
||||
@ -96,37 +169,32 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
TextView activity_duration = (TextView) findViewById(R.id.duration);
|
||||
activity_duration.setText(durationhms);
|
||||
|
||||
JSONObject summaryData = null;
|
||||
String sumData = intent.getStringExtra("SummaryData");
|
||||
}
|
||||
|
||||
private void makeSummaryContent (BaseActivitySummary item){
|
||||
//make view of data from summaryData of item
|
||||
|
||||
TableLayout fieldLayout = findViewById(R.id.summaryDetails);
|
||||
fieldLayout.removeAllViews(); //remove old widgets
|
||||
|
||||
JSONObject summarySubdata = null;
|
||||
JSONObject data = null;
|
||||
|
||||
String sumData = item.getSummaryData();
|
||||
|
||||
if (sumData != null) {
|
||||
try {
|
||||
summaryData = new JSONObject(sumData);
|
||||
summarySubdata = new JSONObject(sumData);
|
||||
} catch (JSONException e) {
|
||||
LOG.error("SportsActivity", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (summaryData == null) return;
|
||||
if (summarySubdata == null) return;
|
||||
data = makeSummaryList(summarySubdata); //make new list, grouped by groups
|
||||
|
||||
JSONObject listOfSummaries = makeSummaryList(summaryData);
|
||||
makeSummaryContent(listOfSummaries);
|
||||
if (data == null) return;
|
||||
|
||||
final JSONObject finalSummaryData = summaryData;
|
||||
activity_icon.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
public boolean onLongClick(View v) {
|
||||
show_raw_data=!show_raw_data;
|
||||
TableLayout fieldLayout = findViewById(R.id.summaryDetails);
|
||||
fieldLayout.removeAllViews();
|
||||
JSONObject listOfSummaries = makeSummaryList(finalSummaryData);
|
||||
makeSummaryContent(listOfSummaries);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void makeSummaryContent (JSONObject data){
|
||||
//build view, use localized names
|
||||
Iterator<String> keys = data.keys();
|
||||
DecimalFormat df = new DecimalFormat("#.##");
|
||||
|
||||
@ -136,7 +204,6 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
|
||||
LOG.error("SportsActivity:" + key + ": " + data.get(key) + "\n");
|
||||
JSONArray innerList = (JSONArray) data.get(key);
|
||||
|
||||
TableLayout fieldLayout = findViewById(R.id.summaryDetails);
|
||||
TableRow label_row = new TableRow(ActivitySummaryDetail.this);
|
||||
TextView label_field = new TextView(ActivitySummaryDetail.this);
|
||||
label_field.setTextSize(16);
|
||||
|
@ -27,6 +27,7 @@ import java.util.Date;
|
||||
* // TODO: split into separate entities?
|
||||
*/
|
||||
public interface ActivitySummary extends Serializable {
|
||||
Long getId();
|
||||
String getName();
|
||||
Date getStartTime();
|
||||
Date getEndTime();
|
||||
|
@ -0,0 +1,57 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.ActivitySummariesAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class ActivitySummaryItems {
|
||||
private final GBDevice device;
|
||||
private int activityKindFilter;
|
||||
List<BaseActivitySummary> allItems;
|
||||
ActivitySummariesAdapter itemsAdapter;
|
||||
private int current_position = 0;
|
||||
|
||||
public ActivitySummaryItems(Context context, GBDevice device, int activityKindFilter) {
|
||||
this.device = device;
|
||||
this.activityKindFilter = activityKindFilter;
|
||||
this.itemsAdapter = new ActivitySummariesAdapter(context, device, activityKindFilter);
|
||||
}
|
||||
|
||||
public BaseActivitySummary getItem(int position){
|
||||
current_position=position;
|
||||
return itemsAdapter.getItem(position);
|
||||
}
|
||||
|
||||
public int getPosition(BaseActivitySummary item){
|
||||
return itemsAdapter.getPosition(item);
|
||||
}
|
||||
|
||||
public List<BaseActivitySummary> getAllItems(){
|
||||
return itemsAdapter.getItems();
|
||||
}
|
||||
|
||||
public BaseActivitySummary getNextItem(){
|
||||
if (current_position+1 < itemsAdapter.getCount()){
|
||||
current_position+=1;
|
||||
return itemsAdapter.getItem(current_position);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BaseActivitySummary getPrevItem(){
|
||||
if (current_position-1 >= 0){
|
||||
current_position-=1;
|
||||
return itemsAdapter.getItem(current_position);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCurrent_position(){
|
||||
return current_position;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
//simple swipe detector based on GestureDetector, inspired by https://stackoverflow.com/a/19506010
|
||||
public class SwipeEvents implements View.OnTouchListener {
|
||||
|
||||
private final GestureDetector gestureDetector;
|
||||
|
||||
public SwipeEvents(Context context) {
|
||||
gestureDetector = new GestureDetector(context, new GestureListener());
|
||||
}
|
||||
|
||||
public void onSwipeLeft() {
|
||||
}
|
||||
|
||||
public void onSwipeRight() {
|
||||
}
|
||||
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
|
||||
|
||||
private static final int SWIPE_DISTANCE_THRESHOLD = 100;
|
||||
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
float distanceX = e2.getX() - e1.getX();
|
||||
float distanceY = e2.getY() - e1.getY();
|
||||
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
|
||||
if (distanceX > 0)
|
||||
onSwipeRight();
|
||||
else
|
||||
onSwipeLeft();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
8
app/src/main/res/anim/flyleft.xml
Normal file
8
app/src/main/res/anim/flyleft.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shareInterpolator="false">
|
||||
<translate
|
||||
android:fromXDelta="100%" android:toXDelta="0%"
|
||||
android:fromYDelta="0%" android:toYDelta="0%"
|
||||
android:duration="150" />
|
||||
</set>
|
8
app/src/main/res/anim/flyright.xml
Normal file
8
app/src/main/res/anim/flyright.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shareInterpolator="false">
|
||||
<translate
|
||||
android:fromXDelta="-100%" android:toXDelta="0%"
|
||||
android:fromYDelta="0%" android:toYDelta="0%"
|
||||
android:duration="150" />
|
||||
</set>
|
@ -1,8 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/activity_summary_detail_relative_layout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:clickable="true"
|
||||
android:focusable="auto"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageView
|
||||
@ -13,8 +16,8 @@
|
||||
android:contentDescription="activity image" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/item_image"
|
||||
android:orientation="vertical"
|
||||
@ -32,9 +35,9 @@
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/summaryDetails"
|
||||
android:id="@+id/summaryHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
@ -79,7 +82,7 @@
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
@ -99,6 +102,11 @@
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/summaryDetails"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/showTrack"
|
||||
|
Loading…
Reference in New Issue
Block a user