From db2892981b434094c86bba50ac6e9eeb61f7c8d5 Mon Sep 17 00:00:00 2001 From: Phillip Dykman Date: Thu, 5 Dec 2019 23:52:56 -0800 Subject: [PATCH] Full pieces view graphic --- .../core/gui/lists/DetailsAdapter.java | 34 ++-- .../core/gui/lists/PiecesMapView.java | 150 ++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/org/transdroid/core/gui/lists/PiecesMapView.java diff --git a/app/src/main/java/org/transdroid/core/gui/lists/DetailsAdapter.java b/app/src/main/java/org/transdroid/core/gui/lists/DetailsAdapter.java index dcfb7a1f..d04927b7 100644 --- a/app/src/main/java/org/transdroid/core/gui/lists/DetailsAdapter.java +++ b/app/src/main/java/org/transdroid/core/gui/lists/DetailsAdapter.java @@ -21,6 +21,7 @@ import java.util.List; import org.transdroid.R; import org.transdroid.core.gui.navigation.*; +import org.transdroid.core.gui.lists.PiecesMapView; import org.transdroid.daemon.Torrent; import org.transdroid.daemon.TorrentFile; @@ -29,7 +30,6 @@ import android.text.util.Linkify; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.TextView; /** * List adapter that holds a header view showing torrent details and show the list list contained by the torrent. @@ -39,8 +39,9 @@ public class DetailsAdapter extends MergeAdapter { private ViewHolderAdapter torrentDetailsViewAdapter = null; private TorrentDetailsView torrentDetailsView = null; + private ViewHolderAdapter piecesSeparatorAdapter = null; private ViewHolderAdapter piecesMapViewAdapter = null; - private TextView piecesMapView = null; + private PiecesMapView piecesMapView = null; private ViewHolderAdapter trackersSeparatorAdapter = null; private SimpleListItemAdapter trackersAdapter = null; private ViewHolderAdapter errorsSeparatorAdapter = null; @@ -60,10 +61,15 @@ public class DetailsAdapter extends MergeAdapter { addAdapter(torrentDetailsViewAdapter); // Pieces map - piecesMapView = new TextView(context); + piecesSeparatorAdapter = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText( + context.getString(R.string.status_pieces))); + piecesSeparatorAdapter.setViewEnabled(false); + piecesSeparatorAdapter.setViewVisibility(View.GONE); + addAdapter(piecesSeparatorAdapter); + piecesMapView = new PiecesMapView(context); piecesMapViewAdapter = new ViewHolderAdapter(piecesMapView); - piecesMapViewAdapter.setViewEnabled(true); - piecesMapViewAdapter.setViewVisibility(View.VISIBLE); + piecesMapViewAdapter.setViewEnabled(false); + piecesMapViewAdapter.setViewVisibility(View.GONE); addAdapter(piecesMapViewAdapter); // Tracker errors @@ -149,15 +155,17 @@ public class DetailsAdapter extends MergeAdapter { public void updatePieces(List pieces) { if (pieces == null || pieces.isEmpty()) { - //errorsAdapter.update(new ArrayList()); - //errorsSeparatorAdapter.setViewVisibility(View.GONE); + piecesSeparatorAdapter.setViewEnabled(false); + piecesSeparatorAdapter.setViewVisibility(View.GONE); + piecesMapViewAdapter.setViewEnabled(false); + piecesMapViewAdapter.setViewVisibility(View.GONE); } else { - String piecesText = ""; - for (int piece : pieces) { - piecesText += piece; - } - piecesMapView.setText(piecesText.substring(0,40)); - //errorsSeparatorAdapter.setViewVisibility(View.VISIBLE); + piecesMapView.setPieces(pieces); + + piecesMapViewAdapter.setViewEnabled(true); + piecesMapViewAdapter.setViewVisibility(View.VISIBLE); + piecesSeparatorAdapter.setViewEnabled(true); + piecesSeparatorAdapter.setViewVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/org/transdroid/core/gui/lists/PiecesMapView.java b/app/src/main/java/org/transdroid/core/gui/lists/PiecesMapView.java new file mode 100644 index 00000000..805a3cbd --- /dev/null +++ b/app/src/main/java/org/transdroid/core/gui/lists/PiecesMapView.java @@ -0,0 +1,150 @@ +package org.transdroid.core.gui.lists; + +import org.transdroid.R; + +import android.content.Context; +import android.view.View; +import android.graphics.Canvas; +import android.graphics.Paint; + +import java.util.ArrayList; +import java.util.List; +import java.lang.Math; + +class PiecesMapView extends View { + + private final float scale = getContext().getResources().getDisplayMetrics().density; + private final int MINIMUM_HEIGHT = (int) (25 * scale); + private final int MINIMUM_PIECE_WIDTH = (int) (2 * scale); + + private ArrayList pieces = null; + + private final Paint downloadingPaint = new Paint(); + private final Paint donePaint = new Paint(); + private final Paint partialDonePaint = new Paint(); + + public PiecesMapView(Context context) { + super(context); + initPaints(); + } + + private void initPaints() { + downloadingPaint.setColor(getResources().getColor(R.color.torrent_downloading)); + donePaint.setColor(getResources().getColor(R.color.torrent_seeding)); + partialDonePaint.setColor(getResources().getColor(R.color.file_low)); + } + + public void setPieces(List pieces) { + this.pieces = new ArrayList(pieces); + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int ws = MeasureSpec.getSize(widthMeasureSpec); + int hs = Math.max(getHeight(), MINIMUM_HEIGHT); + setMeasuredDimension(ws, hs); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (this.pieces == null) { + return; + } + + int height = getHeight(); + int width = getWidth(); + + // downscale + ArrayList piecesScaled; + int pieceWidth; + + pieceWidth = MINIMUM_PIECE_WIDTH; + piecesScaled = new ArrayList(); + + int bucketCount = (int) Math.ceil((double) width / (double) pieceWidth); + int bucketSize = (int) Math.floor((double)this.pieces.size() / (double) bucketCount); + + // loop buckets + for (int i = 0; i < bucketCount; i++) { + + // Get segment of pieces that fall into bucket + int start = i * bucketSize; + + // If this is the last bucket, throw the remainder of the pieces array into it + int end = (i == bucketCount-1) ? this.pieces.size() : (i+1) * bucketSize; + + ArrayList bucket = new ArrayList(this.pieces.subList(start, end)); + + int doneCount = 0; + int downloadingCount = 0; + + // loop pieces in bucket + for(int j = 0; j < bucket.size(); j++) { + // Count downloading pieces + if (bucket.get(j) == 1) { + downloadingCount++; + } + // Count finished pieces + else if (bucket.get(j) == 2) { + doneCount++; + } + } + + int state; + // If a piece is downloading show bucket as downloading + if (downloadingCount > 0) { + state = 1; + } + // If all pieces are done, show bucket as done + else if (doneCount == bucket.size()) { + state = 2; + } + // Some done pieces, show bucket as partially done + else if (doneCount > 0) { + state = 3; + } + // bucket is not downloaded + else { + state = 0; + } + + piecesScaled.add(state); + } + + String scaledPiecesString = ""; + for (int s : piecesScaled) + { + scaledPiecesString += s; + } + + // Draw downscaled peices + for (int i = 0; i < piecesScaled.size(); i++) { + int piece = piecesScaled.get(i); + + if (piece == 0) { + continue; + } + + Paint paint = new Paint(); + switch (piece) { + case 1: + paint = downloadingPaint; + break; + case 2: + paint = donePaint; + break; + case 3: + paint = partialDonePaint; + break; + } + int x = i * pieceWidth; + + canvas.drawRect(x, 0, x + pieceWidth, height, paint); + } + } + +} + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7eb5dc56..d0a76a70 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -128,6 +128,7 @@ Low priority Normal priority High priority + PIECES TRACKERS ERRORS FILES