#anyway the cake is great, it's so delicious and moist#

This commit is contained in:
Mariotaku Lee 2015-06-26 17:00:05 +08:00
parent 86f3584139
commit 011301fcd3
12 changed files with 554 additions and 56 deletions

View File

@ -0,0 +1,132 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.sprite.library;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Shader;
import android.view.Gravity;
/**
* Created by mariotaku on 15/6/26.
*/
public class AnimatedBitmapLayer implements Layer {
private final Bitmap mBitmap;
private final int mFrames;
private final boolean mVerticalFrames;
private final Point mPosition = new Point();
private final Point mFrameSize = new Point(), mScaledSize = new Point();
private final Paint mPaint = new Paint();
private Rect mSource = new Rect(), mDestination = new Rect(), mDisplayBounds = new Rect();
private Rect mTempDestination = new Rect();
private int mGravity;
private int mCurrentFrame;
private Shader.TileMode mTileModeX, mTileModeY;
public AnimatedBitmapLayer(Resources resources, int bitmapRes, int frames, boolean verticalFrames) {
this(BitmapFactory.decodeResource(resources, bitmapRes), frames, verticalFrames);
}
public AnimatedBitmapLayer(Bitmap bitmap, int frames, boolean verticalFrames) {
mBitmap = bitmap;
mFrames = frames;
mVerticalFrames = verticalFrames;
final int bitmapWidth = bitmap.getWidth(), bitmapHeight = bitmap.getHeight();
mFrameSize.x = verticalFrames ? bitmapWidth : bitmapWidth / frames;
mFrameSize.y = verticalFrames ? bitmapHeight / frames : bitmapHeight;
setGravity(Gravity.NO_GRAVITY);
setAntiAlias(true);
setScale(1);
}
@Override
public void onDraw(final Canvas canvas) {
final int frame = mCurrentFrame++;
if (mVerticalFrames) {
final int top = mFrameSize.y * frame;
mSource.set(0, top, mFrameSize.x, top + mFrameSize.y);
} else {
final int left = mFrameSize.x * frame;
mSource.set(left, 0, left + mFrameSize.x, mFrameSize.y);
}
final int destWidth = mTileModeX == Shader.TileMode.REPEAT ? mScaledSize.x : mDestination.width();
final int destHeight = mTileModeY == Shader.TileMode.REPEAT ? mScaledSize.y : mDestination.height();
for (int l = mDestination.left, r = mDestination.right; l < r; l += destWidth) {
for (int t = mDestination.top, b = mDestination.bottom; t < b; t += destHeight) {
mTempDestination.left = l;
mTempDestination.right = l + destWidth;
mTempDestination.top = t;
mTempDestination.bottom = t + destHeight;
canvas.drawBitmap(mBitmap, mSource, mTempDestination, mPaint);
}
}
if (mCurrentFrame >= mFrames) {
mCurrentFrame = 0;
}
}
@Override
public void onSizeChanged(final int width, final int height) {
mDisplayBounds.set(0, 0, width, height);
updateDestination();
}
public void setGravity(int gravity) {
mGravity = gravity;
updateDestination();
}
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
}
public void setTileMode(Shader.TileMode tileModeX, Shader.TileMode tileModeY) {
mTileModeX = tileModeX;
mTileModeY = tileModeY;
}
/**
* Set position relative to gravity
*/
public void setPosition(int x, int y) {
mPosition.set(x, y);
updateDestination();
}
public void setScale(int scale) {
mScaledSize.x = mFrameSize.x * scale;
mScaledSize.y = mFrameSize.y * scale;
updateDestination();
}
private void updateDestination() {
Gravity.apply(mGravity, mScaledSize.x, mScaledSize.y, mDisplayBounds, mPosition.x, mPosition.y, mDestination);
}
}

View File

@ -0,0 +1,32 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.sprite.library;
import android.graphics.Canvas;
/**
* Created by mariotaku on 15/6/26.
*/
public interface Layer {
void onDraw(Canvas canvas);
void onSizeChanged(int width, int height);
}

View File

@ -0,0 +1,88 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.sprite.library;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by mariotaku on 15/6/26.
*/
public class LayeredCanvasView extends View {
private Layer[] mLayers;
private Runnable mAnimateCallback;
public LayeredCanvasView(final Context context) {
super(context);
}
public LayeredCanvasView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public LayeredCanvasView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setLayers(Layer[] layers, int fps) {
mLayers = layers;
if (layers == null || fps <= 0) {
removeCallbacks(mAnimateCallback);
return;
}
notifySizeChanged();
final long delay = 1000 / fps;
post(mAnimateCallback = new Runnable() {
@Override
public void run() {
invalidate();
postDelayed(this, delay);
}
});
}
public Layer[] getLayers() {
return mLayers;
}
@Override
protected void onDraw(final Canvas canvas) {
if (mLayers == null) return;
for (Layer layer : mLayers) {
layer.onDraw(canvas);
}
}
@Override
protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
notifySizeChanged();
}
private void notifySizeChanged() {
if (mLayers == null) return;
final int width = getWidth(), height = getHeight();
for (Layer layer : mLayers) {
layer.onSizeChanged(width, height);
}
}
}

View File

@ -76,6 +76,7 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.View.OnTouchListener; import android.view.View.OnTouchListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -149,6 +150,7 @@ import org.mariotaku.twidere.view.TintedStatusFrameLayout;
import org.mariotaku.twidere.view.TwidereToolbar; import org.mariotaku.twidere.view.TwidereToolbar;
import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener; import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener;
import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -173,7 +175,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
private static final String TAB_TYPE_MEDIA = "media"; private static final String TAB_TYPE_MEDIA = "media";
private static final String TAB_TYPE_FAVORITES = "favorites"; private static final String TAB_TYPE_FAVORITES = "favorites";
private MediaLoaderWrapper mProfileImageLoader; private MediaLoaderWrapper mMediaLoader;
private UserColorNameManager mUserColorNameManager; private UserColorNameManager mUserColorNameManager;
private SharedPreferencesWrapper mPreferences; private SharedPreferencesWrapper mPreferences;
@ -219,6 +221,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
private int mUiColor; private int mUiColor;
private boolean mNameFirst; private boolean mNameFirst;
private int mPreviousTabItemIsDark, mPreviousActionBarItemIsDark; private int mPreviousTabItemIsDark, mPreviousActionBarItemIsDark;
private boolean mHideBirthdayView;
private final LoaderCallbacks<SingleResponse<Relationship>> mFriendshipLoaderCallbacks = new LoaderCallbacks<SingleResponse<Relationship>>() { private final LoaderCallbacks<SingleResponse<Relationship>> mFriendshipLoaderCallbacks = new LoaderCallbacks<SingleResponse<Relationship>>() {
@ -544,7 +547,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mFollowersCount.setText(Utils.getLocalizedNumber(mLocale, user.followers_count)); mFollowersCount.setText(Utils.getLocalizedNumber(mLocale, user.followers_count));
mFriendsCount.setText(Utils.getLocalizedNumber(mLocale, user.friends_count)); mFriendsCount.setText(Utils.getLocalizedNumber(mLocale, user.friends_count));
mProfileImageLoader.displayProfileImage(mProfileImageView, Utils.getOriginalTwitterProfileImage(user.profile_image_url)); mMediaLoader.displayProfileImage(mProfileImageView, Utils.getOriginalTwitterProfileImage(user.profile_image_url));
if (userColor != 0) { if (userColor != 0) {
setUiColor(userColor); setUiColor(userColor);
} else { } else {
@ -552,13 +555,21 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
} }
final int defWidth = resources.getDisplayMetrics().widthPixels; final int defWidth = resources.getDisplayMetrics().widthPixels;
final int width = mBannerWidth > 0 ? mBannerWidth : defWidth; final int width = mBannerWidth > 0 ? mBannerWidth : defWidth;
mProfileImageLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, width); mMediaLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, width);
final Relationship relationship = mRelationship; final Relationship relationship = mRelationship;
if (relationship == null || relationship.getTargetUserId() != user.id) { if (relationship == null || relationship.getTargetUserId() != user.id) {
getFriendship(); getFriendship();
} }
activity.setTitle(manager.getDisplayName(user, mNameFirst, true)); activity.setTitle(manager.getDisplayName(user, mNameFirst, true));
Calendar cal = Calendar.getInstance();
final int currentMonth = cal.get(Calendar.MONTH), currentDay = cal.get(Calendar.DAY_OF_MONTH);
cal.setTimeInMillis(user.created_at);
if (cal.get(Calendar.MONTH) == currentMonth && cal.get(Calendar.DAY_OF_MONTH) == currentDay && !mHideBirthdayView) {
mProfileBirthdayBannerView.setVisibility(View.VISIBLE);
} else {
mProfileBirthdayBannerView.setVisibility(View.GONE);
}
updateTitleAlpha(); updateTitleAlpha();
invalidateOptionsMenu(); invalidateOptionsMenu();
updateSubtitle(); updateSubtitle();
@ -701,7 +712,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
ThemeUtils.getUserThemeBackgroundAlpha(activity)); ThemeUtils.getUserThemeBackgroundAlpha(activity));
mActionBarShadowColor = 0xA0000000; mActionBarShadowColor = 0xA0000000;
final TwidereApplication app = TwidereApplication.getInstance(activity); final TwidereApplication app = TwidereApplication.getInstance(activity);
mProfileImageLoader = app.getMediaLoaderWrapper(); mMediaLoader = app.getMediaLoaderWrapper();
final Bundle args = getArguments(); final Bundle args = getArguments();
long accountId = -1, userId = -1; long accountId = -1, userId = -1;
String screenName = null; String screenName = null;
@ -778,6 +789,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mFollowersContainer.setOnClickListener(this); mFollowersContainer.setOnClickListener(this);
mFriendsContainer.setOnClickListener(this); mFriendsContainer.setOnClickListener(this);
mHeaderErrorIcon.setOnClickListener(this); mHeaderErrorIcon.setOnClickListener(this);
mProfileBirthdayBannerView.setOnClickListener(this);
mProfileBannerView.setOnSizeChangedListener(this); mProfileBannerView.setOnSizeChangedListener(this);
mProfileBannerSpace.setOnTouchListener(this); mProfileBannerSpace.setOnTouchListener(this);
@ -1244,6 +1256,12 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
Utils.openProfileEditor(getActivity(), user.account_id); Utils.openProfileEditor(getActivity(), user.account_id);
break; break;
} }
case R.id.profile_birthday_banner: {
mHideBirthdayView = true;
mProfileBirthdayBannerView.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));
mProfileBirthdayBannerView.setVisibility(View.GONE);
break;
}
} }
} }
@ -1304,6 +1322,9 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
@Override @Override
public boolean onTouch(final View v, final MotionEvent event) { public boolean onTouch(final View v, final MotionEvent event) {
if (mProfileBirthdayBannerView.getVisibility() == View.VISIBLE) {
return mProfileBirthdayBannerView.dispatchTouchEvent(event);
}
return mProfileBannerView.dispatchTouchEvent(event); return mProfileBannerView.dispatchTouchEvent(event);
} }

View File

@ -28,8 +28,7 @@ import com.db.chart.model.BarSet;
import com.db.chart.model.ChartSet; import com.db.chart.model.ChartSet;
import org.mariotaku.querybuilder.Expression; import org.mariotaku.querybuilder.Expression;
import org.mariotaku.twidere.preference.NetworkUsageSummaryPreferences; import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.util.MathUtils; import org.mariotaku.twidere.util.MathUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,33 +39,39 @@ import java.util.concurrent.TimeUnit;
* Created by mariotaku on 15/6/25. * Created by mariotaku on 15/6/25.
*/ */
public class NetworkUsageInfo { public class NetworkUsageInfo {
private final double totalSent; private final double[][] chartUsage;
private final double totalReceived; private final double totalSent, totalReceived;
private final ArrayList<ChartSet> chartData; private final double[] usageTotal;
private final double dayMax; private final double dayUsageMax;
private final int dayMin;
private final int dayMax;
public NetworkUsageInfo(ArrayList<ChartSet> chartData, double totalReceived, double totalSent, double dayMax) { public NetworkUsageInfo(double[][] chartUsage, double[] usageTotal, double totalReceived, double totalSent, double dayUsageMax, int dayMin, int dayMax) {
this.chartData = chartData; this.chartUsage = chartUsage;
this.usageTotal = usageTotal;
this.totalReceived = totalReceived; this.totalReceived = totalReceived;
this.totalSent = totalSent; this.totalSent = totalSent;
this.dayUsageMax = dayUsageMax;
this.dayMin = dayMin;
this.dayMax = dayMax; this.dayMax = dayMax;
} }
public static NetworkUsageInfo get(Context context, Date start, Date end) { public static NetworkUsageInfo get(Context context, Date start, Date end, int dayMin, int dayMax) {
final ContentResolver cr = context.getContentResolver(); final ContentResolver cr = context.getContentResolver();
final long startTime = TimeUnit.HOURS.convert(start.getTime(), TimeUnit.MILLISECONDS); final long startTime = TimeUnit.HOURS.convert(start.getTime(), TimeUnit.MILLISECONDS);
final long endTime = TimeUnit.HOURS.convert(end.getTime(), TimeUnit.MILLISECONDS); final long endTime = TimeUnit.HOURS.convert(end.getTime(), TimeUnit.MILLISECONDS);
final Expression where = Expression.and(Expression.greaterEquals(TwidereDataStore.NetworkUsages.TIME_IN_HOURS, startTime), final Expression where = Expression.and(Expression.greaterEquals(NetworkUsages.TIME_IN_HOURS, startTime),
Expression.lesserThan(TwidereDataStore.NetworkUsages.TIME_IN_HOURS, endTime)); Expression.lesserThan(NetworkUsages.TIME_IN_HOURS, endTime));
final int days = (int) TimeUnit.DAYS.convert(endTime - startTime, TimeUnit.HOURS); final int days = (int) TimeUnit.DAYS.convert(endTime - startTime, TimeUnit.HOURS);
final Cursor c = cr.query(TwidereDataStore.NetworkUsages.CONTENT_URI, TwidereDataStore.NetworkUsages.COLUMNS, final Cursor c = cr.query(NetworkUsages.CONTENT_URI, NetworkUsages.COLUMNS,
where.getSQL(), null, TwidereDataStore.NetworkUsages.TIME_IN_HOURS); where.getSQL(), null, NetworkUsages.TIME_IN_HOURS);
final int idxDate = c.getColumnIndex(TwidereDataStore.NetworkUsages.TIME_IN_HOURS); final int idxDate = c.getColumnIndex(NetworkUsages.TIME_IN_HOURS);
final int idxSent = c.getColumnIndex(TwidereDataStore.NetworkUsages.KILOBYTES_SENT); final int idxSent = c.getColumnIndex(NetworkUsages.KILOBYTES_SENT);
final int idxReceived = c.getColumnIndex(TwidereDataStore.NetworkUsages.KILOBYTES_RECEIVED); final int idxReceived = c.getColumnIndex(NetworkUsages.KILOBYTES_RECEIVED);
final int idxType = c.getColumnIndex(TwidereDataStore.NetworkUsages.REQUEST_TYPE); final int idxType = c.getColumnIndex(NetworkUsages.REQUEST_TYPE);
final double[][] usageArray = new double[days][RequestType.values().length]; final double[][] chartUsage = new double[days][RequestType.values().length];
double totalReceived = 0, totalSent = 0; double totalReceived = 0, totalSent = 0;
final double[] usageTotal = new double[RequestType.values().length];
c.moveToFirst(); c.moveToFirst();
while (!c.isAfterLast()) { while (!c.isAfterLast()) {
final long hours = c.getLong(idxDate); final long hours = c.getLong(idxDate);
@ -74,9 +79,12 @@ public class NetworkUsageInfo {
final double sent = c.getDouble(idxSent); final double sent = c.getDouble(idxSent);
final double received = c.getDouble(idxReceived); final double received = c.getDouble(idxReceived);
final String type = c.getString(idxType); final String type = c.getString(idxType);
usageArray[idx][RequestType.getValue(type)] += (sent + received); final double hourTypeTotal = sent + received;
final int typeIdx = RequestType.getValue(type);
chartUsage[idx][typeIdx] += hourTypeTotal;
totalReceived += received; totalReceived += received;
totalSent += sent; totalSent += sent;
usageTotal[typeIdx] += hourTypeTotal;
c.moveToNext(); c.moveToNext();
} }
c.close(); c.close();
@ -85,14 +93,14 @@ public class NetworkUsageInfo {
final BarSet mediaSet = new BarSet(); final BarSet mediaSet = new BarSet();
final BarSet usageStatisticsSet = new BarSet(); final BarSet usageStatisticsSet = new BarSet();
double dayMax = 0; double dayUsageMax = 0;
for (int i = 0; i < days; i++) { for (int i = 0; i < days; i++) {
String day = String.valueOf(i + 1); String day = String.valueOf(i + 1);
final double[] dayUsage = usageArray[i]; final double[] dayUsage = chartUsage[i];
apiSet.addBar(day, (float) dayUsage[RequestType.API.getValue()]); apiSet.addBar(day, (float) dayUsage[RequestType.API.getValue()]);
mediaSet.addBar(day, (float) dayUsage[RequestType.MEDIA.getValue()]); mediaSet.addBar(day, (float) dayUsage[RequestType.MEDIA.getValue()]);
usageStatisticsSet.addBar(day, (float) dayUsage[RequestType.USAGE_STATISTICS.getValue()]); usageStatisticsSet.addBar(day, (float) dayUsage[RequestType.USAGE_STATISTICS.getValue()]);
dayMax = Math.max(dayMax, MathUtils.sum(dayUsage)); dayUsageMax = Math.max(dayUsageMax, MathUtils.sum(dayUsage));
} }
apiSet.setColor(Color.RED); apiSet.setColor(Color.RED);
@ -103,22 +111,34 @@ public class NetworkUsageInfo {
data.add(apiSet); data.add(apiSet);
data.add(mediaSet); data.add(mediaSet);
data.add(usageStatisticsSet); data.add(usageStatisticsSet);
return new NetworkUsageInfo(data, totalReceived, totalSent, dayMax); return new NetworkUsageInfo(chartUsage, usageTotal, totalReceived, totalSent, dayUsageMax, dayMin, dayMax);
} }
public double getDayMax() { public int getDayMax() {
return dayMax; return dayMax;
} }
public int getDayMin() {
return dayMin;
}
public double getDayUsageMax() {
return dayUsageMax;
}
public double getTotalSent() { public double getTotalSent() {
return totalSent; return totalSent;
} }
public double[] getUsageTotal() {
return usageTotal;
}
public double getTotalReceived() { public double getTotalReceived() {
return totalReceived; return totalReceived;
} }
public ArrayList<ChartSet> getChartData() { public double[][] getChartUsage() {
return chartData; return chartUsage;
} }
} }

View File

@ -20,6 +20,8 @@
package org.mariotaku.twidere.preference; package org.mariotaku.twidere.preference;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.preference.Preference; import android.preference.Preference;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -27,15 +29,17 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.db.chart.model.BarSet;
import com.db.chart.model.ChartSet; import com.db.chart.model.ChartSet;
import com.db.chart.view.AxisController; import com.db.chart.view.AxisController;
import com.db.chart.view.StackBarChartView; import com.db.chart.view.StackBarChartView;
import com.desmond.asyncmanager.AsyncManager; import com.desmond.asyncmanager.AsyncManager;
import com.desmond.asyncmanager.TaskRunnable; import com.desmond.asyncmanager.TaskRunnable;
import org.apache.commons.lang3.tuple.Triple;
import org.mariotaku.twidere.R; import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.NetworkUsageInfo; import org.mariotaku.twidere.model.NetworkUsageInfo;
import org.mariotaku.twidere.model.RequestType;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.Utils;
import java.util.ArrayList; import java.util.ArrayList;
@ -50,6 +54,8 @@ public class NetworkUsageSummaryPreferences extends Preference {
private StackBarChartView mChartView; private StackBarChartView mChartView;
private NetworkUsageInfo mUsage; private NetworkUsageInfo mUsage;
private TextView mTotalUsage; private TextView mTotalUsage;
private TextView mDayUsageMax;
private TextView mDayMin, mDayMid, mDayMax;
public NetworkUsageSummaryPreferences(Context context, AttributeSet attrs, int defStyleAttr) { public NetworkUsageSummaryPreferences(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
@ -70,22 +76,37 @@ public class NetworkUsageSummaryPreferences extends Preference {
final View view = super.onCreateView(parent); final View view = super.onCreateView(parent);
mChartView = (StackBarChartView) view.findViewById(R.id.chart); mChartView = (StackBarChartView) view.findViewById(R.id.chart);
mTotalUsage = (TextView) view.findViewById(R.id.total_usage); mTotalUsage = (TextView) view.findViewById(R.id.total_usage);
mChartView.setXLabels(AxisController.LabelPosition.NONE); mDayUsageMax = (TextView) view.findViewById(R.id.day_usage_max);
mDayMin = (TextView) view.findViewById(R.id.day_min);
mDayMid = (TextView) view.findViewById(R.id.day_mid);
mDayMax = (TextView) view.findViewById(R.id.day_max);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(0x20000000);
mChartView.setYLabels(AxisController.LabelPosition.NONE); mChartView.setYLabels(AxisController.LabelPosition.NONE);
mChartView.setXLabels(AxisController.LabelPosition.NONE);
return view; return view;
} }
private void getUsageInfo() { private void getUsageInfo() {
final Calendar now = Calendar.getInstance();
final Calendar cal = Calendar.getInstance(); final Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH)); cal.clear();
cal.set(Calendar.YEAR, now.get(Calendar.YEAR));
cal.set(Calendar.MONTH, now.get(Calendar.MONTH));
final int dayMin = now.getActualMinimum(Calendar.DAY_OF_MONTH);
final int dayMax = now.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, dayMin);
cal.setTimeZone(now.getTimeZone());
final Date start = cal.getTime(); final Date start = cal.getTime();
cal.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH)); cal.set(Calendar.DAY_OF_MONTH, dayMax);
cal.add(Calendar.DATE, 1);
final Date end = cal.getTime(); final Date end = cal.getTime();
TaskRunnable<Triple<Context, Date, Date>, NetworkUsageInfo, NetworkUsageSummaryPreferences> task; final TaskRunnable<Object[], NetworkUsageInfo, NetworkUsageSummaryPreferences> task;
task = new TaskRunnable<Triple<Context, Date, Date>, NetworkUsageInfo, NetworkUsageSummaryPreferences>() { task = new TaskRunnable<Object[], NetworkUsageInfo, NetworkUsageSummaryPreferences>() {
@Override @Override
public NetworkUsageInfo doLongOperation(Triple<Context, Date, Date> params) throws InterruptedException { public NetworkUsageInfo doLongOperation(Object[] params) throws InterruptedException {
return NetworkUsageInfo.get(params.getLeft(), params.getMiddle(), params.getRight()); return NetworkUsageInfo.get((Context) params[0], (Date) params[1], (Date) params[2], dayMin, dayMax);
} }
@Override @Override
@ -94,7 +115,7 @@ public class NetworkUsageSummaryPreferences extends Preference {
} }
}; };
task.setResultHandler(this); task.setResultHandler(this);
task.setParams(Triple.of(getContext(), start, end)); task.setParams(new Object[]{getContext(), start, end});
AsyncManager.runBackgroundTask(task); AsyncManager.runBackgroundTask(task);
} }
@ -108,12 +129,38 @@ public class NetworkUsageSummaryPreferences extends Preference {
super.onBindView(view); super.onBindView(view);
final NetworkUsageInfo usage = mUsage; final NetworkUsageInfo usage = mUsage;
if (usage == null) return; if (usage == null) return;
final ArrayList<ChartSet> chartData = usage.getChartData(); final double[][] chartUsage = usage.getChartUsage();
if (mChartView.getData() != chartData) { final int days = chartUsage.length;
mChartView.addData(chartData);
mChartView.show(); final BarSet apiSet = new BarSet();
final BarSet mediaSet = new BarSet();
final BarSet usageStatisticsSet = new BarSet();
double dayUsageMax = 0;
for (int i = 0; i < days; i++) {
String day = String.valueOf(i + 1);
final double[] dayUsage = chartUsage[i];
apiSet.addBar(day, (float) dayUsage[RequestType.API.getValue()]);
mediaSet.addBar(day, (float) dayUsage[RequestType.MEDIA.getValue()]);
usageStatisticsSet.addBar(day, (float) dayUsage[RequestType.USAGE_STATISTICS.getValue()]);
dayUsageMax = Math.max(dayUsageMax, MathUtils.sum(dayUsage));
} }
apiSet.setColor(Color.RED);
mediaSet.setColor(Color.GREEN);
usageStatisticsSet.setColor(Color.BLUE);
final ArrayList<ChartSet> data = new ArrayList<>();
data.add(apiSet);
data.add(mediaSet);
data.add(usageStatisticsSet);
mChartView.addData(data);
mChartView.show();
mTotalUsage.setText(Utils.calculateProperSize((usage.getTotalSent() + usage.getTotalReceived()) * 1024)); mTotalUsage.setText(Utils.calculateProperSize((usage.getTotalSent() + usage.getTotalReceived()) * 1024));
mDayUsageMax.setText(Utils.calculateProperSize((usage.getDayUsageMax()) * 1024));
mDayMin.setText(String.valueOf(usage.getDayMin()));
mDayMid.setText(String.valueOf((usage.getDayMin() + usage.getDayMax()) / 2));
mDayMax.setText(String.valueOf(usage.getDayMax()));
} }
} }

View File

@ -0,0 +1,90 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.Gravity;
import org.mariotaku.sprite.library.AnimatedBitmapLayer;
import org.mariotaku.sprite.library.Layer;
import org.mariotaku.sprite.library.LayeredCanvasView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 15/6/26.
*/
public final class BirthdayView extends LayeredCanvasView {
public BirthdayView(final Context context) {
super(context);
init();
}
public BirthdayView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
public BirthdayView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setBackgroundColor(0xFF203040);
final AnimatedBitmapLayer tableLayer = new AnimatedBitmapLayer(getResources(), R.drawable.sprite_birthday_table_frames, 4, true);
final AnimatedBitmapLayer cakeLayer = new AnimatedBitmapLayer(getResources(), R.drawable.sprite_birthday_cake_frames, 4, false);
final AnimatedBitmapLayer lightStripLayer = new AnimatedBitmapLayer(getResources(), R.drawable.sprite_birthday_light_strip_frames, 4, true);
tableLayer.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
tableLayer.setAntiAlias(false);
cakeLayer.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
cakeLayer.setAntiAlias(false);
lightStripLayer.setGravity(Gravity.TOP | Gravity.FILL_HORIZONTAL);
lightStripLayer.setAntiAlias(false);
lightStripLayer.setTileMode(Shader.TileMode.REPEAT, null);
super.setLayers(new Layer[]{tableLayer, cakeLayer, lightStripLayer}, 1);
}
@Override
public void setLayers(final Layer[] layers, final int fps) {
// No-op
}
@Override
protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
final Layer[] layers = getLayers();
((AnimatedBitmapLayer) layers[0]).setScale(Math.max(1, w / 160));
((AnimatedBitmapLayer) layers[1]).setScale(Math.max(1, w / 160));
((AnimatedBitmapLayer) layers[2]).setScale(Math.max(1, w / 160));
}
@Override
protected boolean fitSystemWindows(@NonNull Rect insets) {
final int stripTop = Utils.getInsetsTopWithoutActionBarHeight(getContext(), insets.top);
final Layer[] layers = getLayers();
((AnimatedBitmapLayer) layers[2]).setPosition(0, stripTop);
return super.fitSystemWindows(insets);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!--
~ Twidere - Twitter client for Android ~ Twidere - Twitter client for Android
~ ~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com> ~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
@ -18,8 +17,7 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>. ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -39,15 +37,19 @@
android:id="@+id/profile_banner" android:id="@+id/profile_banner"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scaleType="centerCrop"/> android:scaleType="centerCrop" />
<FrameLayout <FrameLayout
android:id="@+id/profile_birthday_banner" android:id="@+id/profile_birthday_banner"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBottom="@+id/profile_banner" android:layout_alignBottom="@+id/profile_banner"
android:layout_alignTop="@+id/profile_banner"> android:layout_alignTop="@+id/profile_banner"
android:visibility="gone">
<org.mariotaku.twidere.view.BirthdayView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout> </FrameLayout>
</RelativeLayout> </RelativeLayout>
@ -56,7 +58,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:hdl_contentLayout="@layout/fragment_content_pages" app:hdl_contentLayout="@layout/fragment_content_pages"
app:hdl_headerLayout="@layout/header_user"/> app:hdl_headerLayout="@layout/header_user" />
</org.mariotaku.twidere.view.ExtendedFrameLayout> </org.mariotaku.twidere.view.ExtendedFrameLayout>
</FrameLayout> </FrameLayout>

View File

@ -22,19 +22,85 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical"
android:padding="@dimen/element_spacing_normal">
<TextView <TextView
android:id="@+id/total_usage" android:id="@+id/total_usage"
android:layout_marginTop="@dimen/element_spacing_large"
android:layout_marginBottom="@dimen/element_spacing_large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceLarge" android:textAppearance="?android:textAppearanceLarge"
android:textColor="?android:textColorPrimary"
tools:text="124.50mb" /> tools:text="124.50mb" />
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/total_usage">
<TextView
android:id="@+id/day_usage_max"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_row="0"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
tools:text="10mb" />
<com.db.chart.view.StackBarChartView <com.db.chart.view.StackBarChartView
android:id="@+id/chart" android:id="@+id/chart"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_below="@+id/total_usage" android:layout_column="1"
android:layout_gravity="fill"
android:layout_row="0"
app:chart_barSpacing="2dp" /> app:chart_barSpacing="2dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_gravity="fill"
android:layout_row="1"
android:orientation="horizontal">
<TextView
android:id="@+id/day_min"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="left"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
tools:ignore="RtlHardcoded"
tools:text="1" />
<TextView
android:id="@+id/day_mid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
tools:text="15" />
<TextView
android:id="@+id/day_max"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="right"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
tools:ignore="RtlHardcoded"
tools:text="30" />
</LinearLayout>
</GridLayout>
</RelativeLayout> </RelativeLayout>