mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 410 B |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 522 B |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 829 B |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -11,4 +10,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</android.support.v7.widget.LinearLayoutCompat>
|
||||
<include layout="@layout/bottom_map_sheet" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="165dp"
|
||||
android:id="@+id/bottom_sheet"
|
||||
app:behavior_hideable="false"
|
||||
app:behavior_peekHeight="35dp"
|
||||
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
|
||||
android:background="@color/transparent"
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/bottomSheetSlider"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:background="@drawable/ic_location_dot"
|
||||
android:layout_centerHorizontal="true"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_timeline"
|
||||
android:layout_centerHorizontal="true"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="135dp"
|
||||
android:orientation="vertical"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="@android:color/white"
|
||||
android:layout_marginTop="-35dp"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/filter_map_on_time"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="@color/white"
|
||||
android:textColor="@android:color/black" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.rangeslider.TimeRangeSlider
|
||||
android:id="@+id/timeRangeSlider"
|
||||
android:layout_marginBottom="15dp"
|
||||
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:paddingLeft="40dp"
|
||||
android:paddingRight="40dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -17,7 +17,9 @@
|
||||
android:id="@+id/menu_deaddrop" />
|
||||
|
||||
<item android:title="@string/menu_show_global_map"
|
||||
android:id="@+id/menu_global_map" />
|
||||
android:id="@+id/menu_global_map"
|
||||
android:visible="false"
|
||||
/>
|
||||
|
||||
<item android:title="@string/menu_settings"
|
||||
android:id="@+id/menu_settings" />
|
||||
|
||||
@@ -239,4 +239,19 @@
|
||||
<attr name="conversationThumbnail_maxHeight" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="RangeSliderView">
|
||||
<attr name="trackTintColor" format="color|reference"/>
|
||||
<attr name="trackHighlightTintColor" format="color|reference"/>
|
||||
<attr name="trackHeight" format="dimension|reference"/>
|
||||
<attr name="thumbRadius" format="dimension|reference"/>
|
||||
<attr name="thumbOutlineSize" format="dimension|reference"/>
|
||||
<attr name="displayTextFontSize" format="dimension|reference"/>
|
||||
<attr name="minValue" format="integer"/>
|
||||
<attr name="maxValue" format="integer"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TimeRangeSlider">
|
||||
<attr name="timeFrame" format="integer"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -50,4 +50,8 @@
|
||||
|
||||
<color name="universal_overlay">#44000000</color>
|
||||
|
||||
<color name="trackTintColor">#552090ea</color>
|
||||
<color name="trackHighlightTintColor">#ff2090ea</color>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -53,4 +53,12 @@
|
||||
|
||||
<dimen name="scribble_stroke_size">2dp</dimen>
|
||||
|
||||
<dimen name="slider_trackHeight">6dp</dimen>
|
||||
<dimen name="slider_thumbRadius">14dp</dimen>
|
||||
<dimen name="slider_thumbOutlineSize">4dp</dimen>
|
||||
<dimen name="slider_displayTextFontSize">12sp</dimen>
|
||||
<dimen name="slider_displayTextBasicOffsetY">8dp</dimen>
|
||||
<integer name="slider_minValue">100</integer>
|
||||
<integer name="slider_maxValue">100</integer>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -219,6 +219,11 @@
|
||||
<string name="chat_contact_request">Contact request</string>
|
||||
<string name="chat_no_contact_requests">No contact requests.\n\nIf you want classic emails to appear here as contact requests, you can change the corresponding setting in the app settings.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Show location traces in time frame</string>
|
||||
<string name="filter_last_position">Last position</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Search</string>
|
||||
<string name="search_explain">Search for chats, contacts, and messages</string>
|
||||
|
||||
@@ -92,6 +92,10 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
menu.clear();
|
||||
|
||||
inflater.inflate(R.menu.text_secure_normal, menu);
|
||||
MenuItem item = menu.findItem(R.id.menu_global_map);
|
||||
if (Prefs.isLocationStreamingEnabled(this)) {
|
||||
item.setVisible(true);
|
||||
}
|
||||
|
||||
if (!Prefs.isLocationStreamingEnabled(this)) {
|
||||
menu.findItem(R.id.menu_global_map).setVisible(false);
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
package org.thoughtcrime.securesms.components.rangeslider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RangeSliderView extends View {
|
||||
|
||||
private static final String TAG = RangeSliderView.class.getName();
|
||||
|
||||
protected int trackTintColor;
|
||||
protected int trackHighlightTintColor;
|
||||
protected float trackHeight;
|
||||
protected float thumbInnerRadius;
|
||||
protected float thumbOutlineSize;
|
||||
protected float displayTextFontSize;
|
||||
protected float displayTextBasicOffsetY;
|
||||
protected int sliderPaddingLeft;
|
||||
protected int sliderPaddingRight;
|
||||
|
||||
private ThumbLayer minValueThumb;
|
||||
private TextLayer minValueDisplayLabel;
|
||||
|
||||
private ThumbLayer maxValueThumb;
|
||||
private TextLayer maxValueDisplayLabel;
|
||||
|
||||
private TrackLayer track;
|
||||
|
||||
private ArrayList<Integer> values;
|
||||
|
||||
protected int minValue;
|
||||
protected int maxValue;
|
||||
protected float delta;
|
||||
|
||||
protected float offsetY;
|
||||
protected float maxValueDisplayLabelOffsetY;
|
||||
protected float minValueDisplayLabelOffsetY;
|
||||
protected float trackOffsetY;
|
||||
protected float thumbRadius;
|
||||
protected float sliderWidth;
|
||||
|
||||
private float beginTrackOffsetX;
|
||||
private boolean isThumbViewLocked;
|
||||
|
||||
private OnValueChangedListener onValueChangedListener;
|
||||
GestureDetector longPressDetector;
|
||||
|
||||
|
||||
public interface OnValueChangedListener {
|
||||
void onValueChanged(int minValue, int maxValue);
|
||||
String parseMinValueDisplayText(int minValue);
|
||||
String parseMaxValueDisplayText(int maxValue);
|
||||
}
|
||||
|
||||
public RangeSliderView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RangeSliderView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RangeSliderView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
int [] attributes = new int [] {android.R.attr.paddingLeft,
|
||||
android.R.attr.paddingStart,
|
||||
android.R.attr.paddingRight,
|
||||
android.R.attr.paddingEnd};
|
||||
|
||||
TypedArray arr = context.obtainStyledAttributes(attrs, attributes);
|
||||
|
||||
sliderPaddingLeft = arr.getDimensionPixelOffset(0,
|
||||
arr.getDimensionPixelOffset(1, -1));
|
||||
sliderPaddingRight = arr.getDimensionPixelOffset(2,
|
||||
arr.getDimensionPixelOffset(3, -1));
|
||||
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RangeSliderView);
|
||||
trackTintColor = typedArray.getColor(
|
||||
R.styleable.RangeSliderView_trackTintColor,
|
||||
ContextCompat.getColor(context, R.color.trackTintColor)
|
||||
);
|
||||
trackHighlightTintColor = typedArray.getColor(
|
||||
R.styleable.RangeSliderView_trackHighlightTintColor,
|
||||
ContextCompat.getColor(context, R.color.trackHighlightTintColor)
|
||||
);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
trackHeight = typedArray.getDimension(
|
||||
R.styleable.RangeSliderView_trackHeight,
|
||||
resources.getDimension(R.dimen.slider_trackHeight)
|
||||
);
|
||||
thumbInnerRadius = typedArray.getDimension(
|
||||
R.styleable.RangeSliderView_thumbRadius,
|
||||
resources.getDimension(R.dimen.slider_thumbRadius)
|
||||
);
|
||||
thumbOutlineSize = typedArray.getDimension(
|
||||
R.styleable.RangeSliderView_thumbOutlineSize,
|
||||
resources.getDimension(R.dimen.slider_thumbOutlineSize)
|
||||
);
|
||||
displayTextFontSize = typedArray.getDimension(
|
||||
R.styleable.RangeSliderView_displayTextFontSize,
|
||||
resources.getDimension(R.dimen.slider_displayTextFontSize)
|
||||
);
|
||||
displayTextBasicOffsetY = resources.getDimension(R.dimen.slider_displayTextBasicOffsetY);
|
||||
minValue = typedArray.getInt(
|
||||
R.styleable.RangeSliderView_minValue,
|
||||
100
|
||||
);
|
||||
maxValue = typedArray.getInt(
|
||||
R.styleable.RangeSliderView_maxValue,
|
||||
100
|
||||
);
|
||||
|
||||
minValueThumb = new ThumbLayer(thumbInnerRadius, thumbOutlineSize, trackHighlightTintColor, trackTintColor);
|
||||
minValueDisplayLabel = new TextLayer(displayTextFontSize, trackHighlightTintColor);
|
||||
|
||||
maxValueThumb = new ThumbLayer(thumbInnerRadius, thumbOutlineSize, trackHighlightTintColor, trackTintColor);
|
||||
maxValueDisplayLabel = new TextLayer(displayTextFontSize, trackHighlightTintColor);
|
||||
|
||||
track = new TrackLayer(sliderPaddingLeft, sliderPaddingRight, trackHeight, trackTintColor, trackHighlightTintColor);
|
||||
|
||||
values = new ArrayList<>();
|
||||
for (int index = 1; index <= 100; index++) {
|
||||
values.add(index);
|
||||
}
|
||||
delta = 0;
|
||||
|
||||
longPressDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
|
||||
public void onLongPress(MotionEvent e) {
|
||||
if (minValue == maxValue && (minValueThumb.isHighlight || maxValueThumb.isHighlight)) {
|
||||
isThumbViewLocked = true;
|
||||
minValueThumb.isHighlight = true;
|
||||
maxValueThumb.isHighlight = true;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
|
||||
this.onValueChangedListener = onValueChangedListener;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setRangeValues(ArrayList<Integer> values) {
|
||||
this.values = values;
|
||||
setMinAndMaxValue(this.values.get(0), this.values.get(this.values.size() - 1));
|
||||
}
|
||||
|
||||
public void setMinAndMaxValue(int minValue, int maxValue) {
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
invalidate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
this.offsetY = getHeight() / 5 * 3;
|
||||
maxValueDisplayLabelOffsetY = offsetY - thumbInnerRadius - thumbOutlineSize - trackHeight / 2 - displayTextBasicOffsetY - displayTextFontSize;
|
||||
minValueDisplayLabelOffsetY = maxValueDisplayLabelOffsetY + displayTextFontSize + displayTextFontSize / 2;
|
||||
trackOffsetY = offsetY - trackHeight / 2;
|
||||
sliderWidth = getWidth() - sliderPaddingLeft - sliderPaddingRight;
|
||||
thumbRadius = thumbInnerRadius + thumbOutlineSize / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
float minValueOffsetX = getPositionFromIndex(minValue);
|
||||
float maxValueOffsetX = getPositionFromIndex(maxValue);
|
||||
track.draw(canvas, getWidth(), minValueOffsetX, maxValueOffsetX, trackOffsetY, getDeltaInPixel());
|
||||
minValueThumb.draw(canvas, minValueOffsetX, offsetY);
|
||||
maxValueThumb.draw(canvas, maxValueOffsetX, offsetY);
|
||||
|
||||
if (onValueChangedListener != null) {
|
||||
minValueDisplayLabel.draw(
|
||||
canvas,
|
||||
onValueChangedListener.parseMinValueDisplayText(minValue),
|
||||
minValueOffsetX,
|
||||
minValueDisplayLabelOffsetY
|
||||
);
|
||||
maxValueDisplayLabel.draw(
|
||||
canvas,
|
||||
onValueChangedListener.parseMaxValueDisplayText(maxValue),
|
||||
maxValueOffsetX,
|
||||
maxValueDisplayLabelOffsetY
|
||||
);
|
||||
} else {
|
||||
minValueDisplayLabel.draw(canvas, String.valueOf(minValue), minValueOffsetX, minValueDisplayLabelOffsetY);
|
||||
maxValueDisplayLabel.draw(canvas, String.valueOf(maxValue), maxValueOffsetX, maxValueDisplayLabelOffsetY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
longPressDetector.onTouchEvent(event);
|
||||
|
||||
if (event.getAction() == MotionEvent.ACTION_CANCEL) {
|
||||
minValueThumb.isHighlight = false;
|
||||
maxValueThumb.isHighlight = false;
|
||||
isThumbViewLocked = false;
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
isThumbViewLocked = false;
|
||||
if (minValueThumb.isHighlight || maxValueThumb.isHighlight) {
|
||||
if (onValueChangedListener != null) {
|
||||
onValueChangedListener.onValueChanged(minValue, maxValue);
|
||||
}
|
||||
minValueThumb.isHighlight = false;
|
||||
maxValueThumb.isHighlight = false;
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int offsetX = (int) event.getX();
|
||||
if (offsetX < (sliderPaddingLeft - thumbRadius) || offsetX > getWidth() - sliderPaddingRight + thumbRadius) {
|
||||
//Log.d(TAG, "ignore touch in padding");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
float minValuePosition = getPositionFromIndex(minValue);
|
||||
Log.d(TAG, "action_down minVal: " + minValue + ", " + minValuePosition );
|
||||
if (offsetX >= minValuePosition - thumbRadius && offsetX <= minValuePosition + thumbRadius) {
|
||||
minValueThumb.isHighlight = true;
|
||||
} else {
|
||||
float maxValuePosition = getPositionFromIndex(maxValue);
|
||||
if (offsetX >= maxValuePosition - thumbRadius && offsetX <= maxValuePosition + thumbRadius) {
|
||||
maxValueThumb.isHighlight = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (minValueThumb.isHighlight || maxValueThumb.isHighlight) {
|
||||
beginTrackOffsetX = offsetX;
|
||||
invalidate();
|
||||
} else {
|
||||
beginTrackOffsetX = -1;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (minValue == maxValue && beginTrackOffsetX > -1 && offsetX > beginTrackOffsetX && !maxValueThumb.isHighlight) {
|
||||
minValueThumb.isHighlight = false;
|
||||
maxValueThumb.isHighlight = true;
|
||||
}
|
||||
|
||||
int count = values.size();
|
||||
int index = getIndexFromPosition(offsetX);
|
||||
Log.d(TAG, "move - index: " + index + ", offsetX: " + offsetX);
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
} else if (index > count - 1) {
|
||||
index = count - 1;
|
||||
}
|
||||
|
||||
if (isThumbViewLocked) {
|
||||
minValue = values.get(index);
|
||||
maxValue = values.get(index);
|
||||
} else if (minValueThumb.isHighlight) {
|
||||
if (index > values.indexOf(maxValue)) {
|
||||
minValue = maxValue;
|
||||
} else {
|
||||
minValue = values.get(index);
|
||||
}
|
||||
} else if (maxValueThumb.isHighlight) {
|
||||
if (index < values.indexOf(minValue)) {
|
||||
maxValue = minValue;
|
||||
} else {
|
||||
maxValue = values.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (minValueThumb.isHighlight || maxValueThumb.isHighlight) {
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int getIndexFromPosition(int offsetX) {
|
||||
return (int) (((offsetX - sliderPaddingLeft) * getCount()) / sliderWidth);
|
||||
}
|
||||
|
||||
protected float getPositionFromIndex(int value) {
|
||||
return ((sliderWidth / (float) getCount()) * value) + sliderPaddingLeft;
|
||||
}
|
||||
|
||||
public float getDeltaInPixel() {
|
||||
// '* 2' is just an offset factor to increase the visibility
|
||||
return (sliderWidth / getCount()) * delta + (2 * thumbInnerRadius + thumbOutlineSize);
|
||||
}
|
||||
|
||||
public float getDeltaInValues() {
|
||||
return delta;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.thoughtcrime.securesms.components.rangeslider;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
class TextLayer {
|
||||
|
||||
private Paint paint;
|
||||
|
||||
TextLayer(float fontSize, int color) {
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(color);
|
||||
paint.setTextSize(fontSize);
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
}
|
||||
|
||||
void draw(Canvas canvas, String text, float offsetX, float offsetY) {
|
||||
canvas.drawText(text, offsetX, offsetY, paint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.thoughtcrime.securesms.components.rangeslider;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
|
||||
class ThumbLayer {
|
||||
|
||||
private float radius;
|
||||
private float outlineSize;
|
||||
|
||||
private int highlightColor;
|
||||
|
||||
private Paint outlinePaint;
|
||||
private Paint fillPaint;
|
||||
|
||||
boolean isHighlight = false;
|
||||
|
||||
ThumbLayer(float radius, float outlineSize, int outlineColor, int highlightColor) {
|
||||
this.radius = radius;
|
||||
this.outlineSize = outlineSize;
|
||||
this.highlightColor = highlightColor;
|
||||
|
||||
outlinePaint = new Paint();
|
||||
outlinePaint.setAntiAlias(true);
|
||||
outlinePaint.setColor(outlineColor);
|
||||
outlinePaint.setStyle(Paint.Style.STROKE);
|
||||
outlinePaint.setStrokeWidth(outlineSize);
|
||||
|
||||
fillPaint = new Paint();
|
||||
fillPaint.setAntiAlias(true);
|
||||
fillPaint.setStyle(Paint.Style.FILL);
|
||||
fillPaint.setStrokeWidth(0);
|
||||
}
|
||||
|
||||
void draw(Canvas canvas, float cx, float cy) {
|
||||
canvas.drawCircle(cx, cy, radius, outlinePaint);
|
||||
|
||||
if (isHighlight) {
|
||||
fillPaint.setColor(highlightColor);
|
||||
} else {
|
||||
fillPaint.setColor(Color.WHITE);
|
||||
}
|
||||
canvas.drawCircle(cx, cy, radius - outlineSize / 2, fillPaint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package org.thoughtcrime.securesms.components.rangeslider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by cyberta on 24.03.19.
|
||||
*/
|
||||
|
||||
public class TimeRangeSlider extends RangeSliderView implements RangeSliderView.OnValueChangedListener {
|
||||
private static final int DEFAULT_TIMEFRAME_2D = 60 * 60 * 24 * 2; // 2d
|
||||
private static final float DEFAULT_DELTA = 1000*60*30; // 30 min
|
||||
int timeFrame; // timeframe in seconds
|
||||
|
||||
Locale locale;
|
||||
OnTimestampChangedListener listener;
|
||||
private TextLayer minRangeDisplayLabel;
|
||||
private TextLayer maxRangeDisplayLabel;
|
||||
|
||||
float displayLabelOffsetBelow;
|
||||
|
||||
|
||||
public TimeRangeSlider(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public TimeRangeSlider(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public TimeRangeSlider(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RangeSliderView);
|
||||
timeFrame = typedArray.getInt(
|
||||
R.styleable.TimeRangeSlider_timeFrame,
|
||||
DEFAULT_TIMEFRAME_2D
|
||||
);
|
||||
|
||||
locale = DynamicLanguage.getSelectedLocale(context);
|
||||
super.setOnValueChangedListener(this);
|
||||
minRangeDisplayLabel = new TextLayer(displayTextFontSize, trackHighlightTintColor);
|
||||
maxRangeDisplayLabel = new TextLayer(displayTextFontSize, trackHighlightTintColor);
|
||||
delta = DEFAULT_DELTA / (timeFrame * 1000) * getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
displayLabelOffsetBelow = offsetY + thumbInnerRadius + thumbOutlineSize + trackHeight / 2 + displayTextBasicOffsetY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
float minValueOffsetX = getPositionFromIndex(minValue);
|
||||
float maxValueOffsetX = getPositionFromIndex(maxValue);
|
||||
|
||||
if (minValue == maxValue) {
|
||||
if (minValueOffsetX - getDeltaInPixel() >= sliderPaddingLeft) {
|
||||
minRangeDisplayLabel.draw(
|
||||
canvas,
|
||||
getDeltaInTime(getContext()),
|
||||
minValueOffsetX - getDeltaInPixel(),
|
||||
displayLabelOffsetBelow
|
||||
);
|
||||
}
|
||||
|
||||
if (maxValueOffsetX + getDeltaInPixel() <= (getWidth() - sliderPaddingRight)) {
|
||||
maxRangeDisplayLabel.draw(
|
||||
canvas,
|
||||
getDeltaInTime(getContext()),
|
||||
maxValueOffsetX + getDeltaInPixel(),
|
||||
displayLabelOffsetBelow
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTimestampChangedListener {
|
||||
void onTimestampChanged(long startTimestamp, long stopTimestamp);
|
||||
|
||||
/**
|
||||
* filter for lastPosition beginning from startTimestamp to now
|
||||
* @param startTimestamp begin of time frame
|
||||
*/
|
||||
void onFilterLastPosition(long startTimestamp);
|
||||
}
|
||||
|
||||
|
||||
public void setOnTimestampChangedListener(OnTimestampChangedListener timestampChangedListener) {
|
||||
listener = timestampChangedListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueChanged(int minValue, int maxValue) {
|
||||
if (listener != null) {
|
||||
long minTimeStamp = getTimestampForValue(minValue);
|
||||
if (minValue == maxValue) {
|
||||
if (minValue == getCount()) {
|
||||
// filter last location
|
||||
listener.onFilterLastPosition(System.currentTimeMillis() - (long) DEFAULT_DELTA);
|
||||
} else {
|
||||
// filter for time of event with delta before and after
|
||||
listener.onTimestampChanged(minTimeStamp - (long) DEFAULT_DELTA, minTimeStamp + (long) DEFAULT_DELTA);
|
||||
}
|
||||
} else {
|
||||
//filter for time span
|
||||
listener.onTimestampChanged(minTimeStamp, getTimestampForValue(maxValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseMinValueDisplayText(int minValue) {
|
||||
if (minValue == maxValue) {
|
||||
return "";
|
||||
}
|
||||
return getStringForValue(minValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseMaxValueDisplayText(int maxValue) {
|
||||
if (minValue == maxValue && maxValue == getCount()) {
|
||||
return getContext().getResources().getString(R.string.filter_last_position);
|
||||
}
|
||||
return getStringForValue(maxValue);
|
||||
}
|
||||
|
||||
|
||||
private String getStringForValue(int value) {
|
||||
return DateUtils.getExtendedRelativeTimeSpanString(this.getContext(), locale, getTimestampForValue(value));
|
||||
}
|
||||
|
||||
private long getTimestampForValue(int value) {
|
||||
return System.currentTimeMillis() - ((timeFrame / getCount()) * (getCount() - value) * 1000);
|
||||
}
|
||||
|
||||
public String getDeltaInTime(Context context) {
|
||||
return DateUtils.getFormattedTimespan(context, (int) (timeFrame * 1000 / getCount() * getDeltaInValues()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.thoughtcrime.securesms.components.rangeslider;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
class TrackLayer {
|
||||
|
||||
private float height;
|
||||
private float radius;
|
||||
private int paddingLeft = 0;
|
||||
private int paddingRight = 0;
|
||||
|
||||
private Paint centerPaint;
|
||||
private Paint backgoundPaint;
|
||||
|
||||
TrackLayer(int paddingLeft, int paddingRight, float height, int color, int highlightColor) {
|
||||
this.height = height;
|
||||
radius = this.height / 2;
|
||||
|
||||
centerPaint = new Paint();
|
||||
centerPaint.setAntiAlias(true);
|
||||
centerPaint.setColor(highlightColor);
|
||||
centerPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
backgoundPaint = new Paint();
|
||||
backgoundPaint.setAntiAlias(true);
|
||||
backgoundPaint.setColor(color);
|
||||
backgoundPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
this.paddingLeft = paddingLeft;
|
||||
this.paddingRight = paddingRight;
|
||||
}
|
||||
|
||||
void draw(Canvas canvas, int width, float offsetLeft, float offsetRight, float offsetY, float delta) {
|
||||
draw(canvas, backgoundPaint, paddingLeft, width - paddingRight, offsetY);
|
||||
if (offsetLeft == offsetRight) {
|
||||
float maxEndX = width - paddingRight;
|
||||
float minStartX = paddingLeft;
|
||||
float offsetDeltaLeft = offsetLeft - delta;
|
||||
float offsetDeltaRight = offsetRight + delta;
|
||||
|
||||
if (offsetLeft - delta < minStartX) {
|
||||
offsetDeltaLeft = minStartX;
|
||||
} else if (offsetRight + delta > maxEndX) {
|
||||
offsetDeltaRight = maxEndX;
|
||||
}
|
||||
|
||||
draw(canvas, centerPaint, offsetDeltaLeft, offsetDeltaRight, offsetY);
|
||||
}
|
||||
else {
|
||||
draw(canvas, centerPaint, offsetLeft, offsetRight, offsetY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void draw(Canvas canvas, Paint paint, float startX, float endX, float offsetY) {
|
||||
canvas.drawRoundRect(
|
||||
new RectF(startX, offsetY, endX, offsetY + height),
|
||||
radius,
|
||||
radius,
|
||||
paint
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -719,20 +719,4 @@ public class ApplicationDcContext extends DcContext {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* core related helper methods
|
||||
**********************************************************************************************/
|
||||
|
||||
public int[] getChatIds() {
|
||||
DcChatlist chats = getChatlist(0, null, 0);
|
||||
int count = chats.getCnt();
|
||||
int[] chatIds = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
DcChat dcChat = chats.getChat(i);
|
||||
chatIds[i] = dcChat.getId();
|
||||
}
|
||||
return chatIds;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public class GenerateInfoWindowTask extends AsyncTask<ArrayList<Feature>, HashMa
|
||||
String id = feature.getStringProperty(INFO_WINDOW_ID);
|
||||
imagesMap.put(id, bitmap);
|
||||
|
||||
if (i % 10 == 0) {
|
||||
if (i % 20 == 0) {
|
||||
publishProgress(new HashMap<>(imagesMap));
|
||||
imagesMap.clear();
|
||||
}
|
||||
|
||||
@@ -3,15 +3,19 @@ package org.thoughtcrime.securesms.map;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.BottomSheetBehavior;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.Style;
|
||||
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
|
||||
|
||||
@@ -20,6 +24,7 @@ import org.thoughtcrime.securesms.BaseActivity;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.rangeslider.TimeRangeSlider;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.geolocation.DcLocation;
|
||||
|
||||
@@ -27,11 +32,13 @@ import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import static android.support.design.widget.BottomSheetBehavior.STATE_COLLAPSED;
|
||||
import static android.support.design.widget.BottomSheetBehavior.STATE_EXPANDED;
|
||||
import static com.b44t.messenger.DcChat.DC_CHAT_NO_CHAT;
|
||||
import static org.thoughtcrime.securesms.map.MapDataManager.MARKER_SELECTED;
|
||||
import static org.thoughtcrime.securesms.map.MapDataManager.MESSAGE_ID;
|
||||
|
||||
public class MapActivity extends BaseActivity implements Observer {
|
||||
public class MapActivity extends BaseActivity implements Observer, TimeRangeSlider.OnTimestampChangedListener {
|
||||
|
||||
public static final String TAG = MapActivity.class.getSimpleName();
|
||||
public static final String CHAT_ID = "chat_id";
|
||||
@@ -40,6 +47,7 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
|
||||
private DcLocation dcLocation;
|
||||
private MapDataManager mapDataManager;
|
||||
private MapboxMap mapboxMap;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -67,6 +75,7 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
|
||||
mapFragment.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
|
||||
|
||||
this.mapboxMap = mapboxMap;
|
||||
mapboxMap.setCameraPosition(new CameraPosition.Builder()
|
||||
.target(new LatLng(dcLocation.getLastLocation().getLatitude(), dcLocation.getLastLocation().getLongitude()))
|
||||
.zoom(9)
|
||||
@@ -80,6 +89,7 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
}
|
||||
|
||||
mapDataManager = new MapDataManager(this, mapBoxStyle, chatId, (latLngBounds) -> {
|
||||
Log.d(TAG, "on Data initialized");
|
||||
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 50), 1000);
|
||||
});
|
||||
|
||||
@@ -126,6 +136,11 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
}
|
||||
}
|
||||
|
||||
if (chatId == 0) {
|
||||
Log.e(TAG, "Chat id is 0. Cannot open chat");
|
||||
return true;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(MapActivity.this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, chatId);
|
||||
intent.putExtra(ConversationActivity.LAST_SEEN_EXTRA, 0);
|
||||
@@ -151,6 +166,25 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
}
|
||||
}));
|
||||
|
||||
TimeRangeSlider timeRangeSlider = this.findViewById(R.id.timeRangeSlider);
|
||||
timeRangeSlider.setOnTimestampChangedListener(this);
|
||||
|
||||
View bottomSheet = this.findViewById(R.id.bottom_sheet);
|
||||
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
|
||||
|
||||
|
||||
RelativeLayout bottomSheetSlider = this.findViewById(R.id.bottomSheetSlider);
|
||||
bottomSheetSlider.setOnClickListener(v -> {
|
||||
switch (behavior.getState()) {
|
||||
case STATE_EXPANDED:
|
||||
behavior.setState(STATE_COLLAPSED);
|
||||
break;
|
||||
default:
|
||||
behavior.setState(STATE_EXPANDED);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,16 +216,17 @@ public class MapActivity extends BaseActivity implements Observer {
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getChatIds(Intent intent) {
|
||||
if (intent == null) {
|
||||
return new int[]{-1};
|
||||
@Override
|
||||
public void onTimestampChanged(long startTimestamp, long stopTimestamp) {
|
||||
if (this.mapboxMap == null) {
|
||||
return;
|
||||
}
|
||||
mapDataManager.filter(startTimestamp, stopTimestamp);
|
||||
|
||||
int[] chatIds = intent.getIntArrayExtra(CHAT_IDS);
|
||||
if (chatIds == null || chatIds.length == 0) {
|
||||
chatIds = new int[1];
|
||||
chatIds[0] = getIntent().getIntExtra(CHAT_ID, -1);
|
||||
}
|
||||
return chatIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilterLastPosition(long startTimestamp) {
|
||||
mapDataManager.filterLastPositions(startTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,13 @@ import java.util.Map;
|
||||
|
||||
import static com.b44t.messenger.DcContext.DC_EVENT_LOCATION_CHANGED;
|
||||
import static com.b44t.messenger.DcContext.DC_GCL_ADD_SELF;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.gt;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.gte;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.lte;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.toBool;
|
||||
import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_BOTTOM_LEFT;
|
||||
@@ -73,6 +77,8 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
public static final int ALL_CHATS_GLOBAL_MAP = 0;
|
||||
public static final long TIMESTAMP_NOW = 0L;
|
||||
public static final long TIMEOUT = 3 * 60 * 60 * 1000;
|
||||
private static final long DEFAULT_LAST_POSITION_DELTA = 1000*60*30; // 30 min
|
||||
|
||||
private static final String TAG = MapDataManager.class.getSimpleName();
|
||||
private Style mapboxStyle;
|
||||
private HashMap<Integer, MapSource> contactMapSources;
|
||||
@@ -98,9 +104,11 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
|
||||
int[] contactIds = getContactIds(chatId);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
for (int contactId : contactIds) {
|
||||
updateSource(chatId, contactId, boundingBuilder);
|
||||
generateInfoWindows(contactId);
|
||||
filterLastPosition(contactId, now - DEFAULT_LAST_POSITION_DELTA);
|
||||
}
|
||||
|
||||
dcContext.eventCenter.addObserver(DC_EVENT_LOCATION_CHANGED, this);
|
||||
@@ -204,12 +212,50 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void filter(long startTimestamp, long endTimestamp) {
|
||||
int[] contactIds = getContactIds(chatId);
|
||||
for (int contactId : contactIds) {
|
||||
MapSource contactMapMetadata = contactMapSources.get(contactId);
|
||||
SymbolLayer markerLayer = (SymbolLayer) mapboxStyle.getLayer(contactMapMetadata.getMarkerLayer());
|
||||
Expression filter = all(
|
||||
lte(get(TIMESTAMP), endTimestamp),
|
||||
gte(get(TIMESTAMP), startTimestamp));
|
||||
markerLayer.withFilter(filter);
|
||||
LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(contactMapMetadata.getLineLayer());
|
||||
lineLayer.withFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public void filterLastPositions(long startTimestamp) {
|
||||
int[] contactIds = getContactIds(chatId);
|
||||
for (int contactId : contactIds) {
|
||||
filterLastPosition(contactId, startTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
private void filterLastPosition(int contactId, long startTimestamp) {
|
||||
MapSource contactMapMetadata = contactMapSources.get(contactId);
|
||||
SymbolLayer markerLayer = (SymbolLayer) mapboxStyle.getLayer(contactMapMetadata.getMarkerLayer());
|
||||
Expression filter = all(
|
||||
eq((get(LAST_LOCATION)), literal(true)),
|
||||
gte(get(TIMESTAMP), startTimestamp));
|
||||
markerLayer.withFilter(filter);
|
||||
LineLayer lineLayer = (LineLayer) mapboxStyle.getLayer(contactMapMetadata.getLineLayer());
|
||||
lineLayer.withFilter(filter);
|
||||
}
|
||||
|
||||
private void updateSource(int chatId, int contactId) {
|
||||
updateSource(chatId, contactId, null);
|
||||
}
|
||||
|
||||
private void updateSource(int chatId, int contactId, LatLngBounds.Builder boundingBuilder) {
|
||||
DcArray locations = dcContext.getLocations(chatId, contactId, System.currentTimeMillis() - TIMEOUT, TIMESTAMP_NOW);
|
||||
updateSource(chatId, contactId, System.currentTimeMillis() - TIMEOUT, TIMESTAMP_NOW, boundingBuilder );
|
||||
}
|
||||
|
||||
private void updateSource(int chatId, int contactId, long startTimestamp, long endTimestamp, LatLngBounds.Builder boundingBuilder) {
|
||||
//long start = System.currentTimeMillis();
|
||||
DcArray locations = dcContext.getLocations(chatId, contactId, startTimestamp, endTimestamp);
|
||||
MapSource contactMapMetadata = contactMapSources.get(contactId);
|
||||
if (contactMapMetadata == null) {
|
||||
contactMapMetadata = addContactMapSource(contactId);
|
||||
@@ -242,10 +288,21 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
sortedPointFeatures.first().getFeature().addBooleanProperty(LAST_LOCATION, true);
|
||||
}
|
||||
|
||||
FeatureCollection pointFeatureCollection = FeatureCollection.fromFeatures(sortedPointFeatures.getFeatureList());
|
||||
FeatureCollection lineFeatureCollection = FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(
|
||||
LineString.fromLngLats(sortedPointFeatures.getPointList())
|
||||
)});
|
||||
ArrayList<Point> sortedPointList = sortedPointFeatures.getPointList();
|
||||
ArrayList<Feature> sortedFeatureList = sortedPointFeatures.getFeatureList();
|
||||
FeatureCollection pointFeatureCollection = FeatureCollection.fromFeatures(sortedFeatureList);
|
||||
ArrayList<Feature> lineFeatures = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < sortedPointFeatures.size() - 1; i++) {
|
||||
Feature f = sortedFeatureList.get(i);
|
||||
Number numberProperty = f.getNumberProperty(TIMESTAMP);
|
||||
LineString l = LineString.fromLngLats(sortedPointList.subList(i, i+2));
|
||||
Feature lineFeature = Feature.fromGeometry(l, new JsonObject(), "l_" + f.id());
|
||||
lineFeature.addNumberProperty(TIMESTAMP, numberProperty);
|
||||
lineFeatures.add(lineFeature);
|
||||
}
|
||||
|
||||
FeatureCollection lineFeatureCollection = FeatureCollection.fromFeatures(lineFeatures);
|
||||
|
||||
GeoJsonSource lineSource = (GeoJsonSource) mapboxStyle.getSource(contactMapMetadata.getLineSource());
|
||||
lineSource.setGeoJson(lineFeatureCollection);
|
||||
@@ -254,6 +311,8 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
featureCollections.put(contactMapMetadata.getMarkerFeatureCollection(), sortedPointFeatures);
|
||||
|
||||
generateMissingInfoWindows(contactId);
|
||||
|
||||
//Log.d(TAG, "update Source took " + (System.currentTimeMillis() - start) + " ms");
|
||||
}
|
||||
|
||||
private void generateMissingInfoWindows(int contactId) {
|
||||
@@ -281,7 +340,9 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
private void generateInfoWindows(int contactId) {
|
||||
MapSource contactMapMetadata = contactMapSources.get(contactId);
|
||||
FeatureTreeSet collection = featureCollections.get(contactMapMetadata.getMarkerFeatureCollection());
|
||||
new GenerateInfoWindowTask(this, contactId).execute(collection.getFeatureList());
|
||||
if (collection.size() > 0) {
|
||||
new GenerateInfoWindowTask(this, contactId).execute(collection.getFeatureList());
|
||||
}
|
||||
}
|
||||
|
||||
private void initGeoJsonSources(MapSource source) {
|
||||
@@ -328,12 +389,10 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
switchCase(toBool(get(LAST_LOCATION)), literal(1.0f),
|
||||
switchCase(eq(get(MESSAGE_ID), literal(0)), literal(0.7f), literal(1.1f))));
|
||||
Expression markerIcon = switchCase(toBool(get(LAST_LOCATION)), literal(source.getMarkerLastPositon()), literal(source.getMarkerIcon()));
|
||||
Expression allowOverlap = eq(get(LAST_LOCATION), literal(true));
|
||||
mapboxStyle.addLayer(new SymbolLayer(source.getMarkerLayer(), source.getMarkerSource())
|
||||
.withProperties(
|
||||
iconImage(markerIcon),
|
||||
iconSize(markerSize),
|
||||
iconAllowOverlap(allowOverlap))
|
||||
iconSize(markerSize))
|
||||
);
|
||||
|
||||
mapboxStyle.addLayer(new LineLayer(source.getLineLayer(), source.getLineSource())
|
||||
@@ -405,6 +464,14 @@ public class MapDataManager implements DcEventCenter.DcEventDelegate, GenerateIn
|
||||
}
|
||||
}
|
||||
|
||||
private void resetSource(int contactId) {
|
||||
MapSource contactMapMetadata = contactMapSources.get(contactId);
|
||||
if (contactMapMetadata != null) {
|
||||
featureCollections.put(contactMapMetadata.getMarkerFeatureCollection(), new FeatureTreeSet());
|
||||
GeoJsonSource pointSource = (GeoJsonSource) mapboxStyle.getSource(contactMapMetadata.getMarkerSource());
|
||||
pointSource.setGeoJson(FeatureCollection.fromFeatures(new ArrayList<>()));
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceSelectedMarker(String featureId) {
|
||||
Feature feature = getFeatureWithId(featureId);
|
||||
|
||||
@@ -175,4 +175,9 @@ public class DateUtils extends android.text.format.DateUtils {
|
||||
TimeUnit.MILLISECONDS.toMinutes(millis),
|
||||
TimeUnit.MILLISECONDS.toSeconds(millis-(TimeUnit.MILLISECONDS.toMinutes(millis)*60000)));
|
||||
}
|
||||
|
||||
public static String getFormattedTimespan(Context c, int timestamp) {
|
||||
int mins = timestamp / (1000 * 60);
|
||||
return c.getResources().getQuantityString(R.plurals.n_minutes, mins, mins);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user