/* * Copyright 2015 Daniel Dittmar * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package dan.dit.whatsthat.util.general; import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; /** * A class that wraps a PercentProgressListener. Allows to divide the progress to be divided into * multiple blocks. Each block can be weighted differently. If the amount of steps is given, each * block will be weighted uniformly. * To advance to the next step you need to manually invoke nextStep(). This can but does not have * to be invoked after the last step was completed. Each step allows invoking this progress listener * from a fresh range of 0% to 100%. This progress will be added to the already reached weighted * progress when notifying the wrapped listener. * Created by daniel on 03.07.15. */ public class MultistepPercentProgressListener implements PercentProgressListener { private PercentProgressListener mListener; private List<Double> mWeights = new ArrayList<>(); private int mCurrentStep; private double mCurrentWeight; /** * Creates a new MultistepPercentProgressListener dividing the progress into the given amount * of steps. These steps will be uniformly weighted. * @param listener The listener to wrap. * @param steps The amount of steps. Must be positive. */ public MultistepPercentProgressListener(@NonNull PercentProgressListener listener, int steps) { mListener = listener; reset(steps); } /** * Creates a new MultistepPercentProgressListener dividing the progress into the given weights. * There must be at least one weight and each array entry must be a value between zero and * one (inclusive). Should sum up to 1, this is NOT checked. * @param listener The listener to wrap. * @param weights The weights for each step. */ public MultistepPercentProgressListener(@NonNull PercentProgressListener listener, @NonNull double[] weights) { mListener = listener; reset(weights); } private MultistepPercentProgressListener reset(int steps) { if (steps <= 0) { throw new IllegalArgumentException("No steps given"); } reset(); // equally distributed for (int i = 0; i < steps; i++) { mWeights.add(1./ (double) steps); } return this; } private MultistepPercentProgressListener reset(double[] weights) { if (weights == null || weights.length == 0) { throw new IllegalArgumentException("No weights given."); } reset(); for (int i = 0; i < weights.length; i++) { if (weights[i] >= 0. && weights[i] <= 1.) { mWeights.add(weights[i]); } else { throw new IllegalArgumentException("Negative or weight > 1 given: " + weights[i]); } } return this; } private MultistepPercentProgressListener reset() { mWeights.clear(); mCurrentStep = 0; mCurrentWeight = 0.; return this; } /** * Advances the multistep listener to the next step. Updates the progress of the wrapped * listener, but does not necessarily increase it, if the last step was already on 100%. */ public void nextStep() { mCurrentWeight += mWeights.get(mCurrentStep); mCurrentStep++; notifyProgress(0); } @Override public void onProgressUpdate(int progress) { if (mCurrentStep >= mWeights.size()) { return; } notifyProgress(progress); } private void notifyProgress(int progress) { if (mCurrentStep >= mWeights.size()) { mListener.onProgressUpdate(PROGRESS_COMPLETE); } else { mListener.onProgressUpdate((int) (PROGRESS_COMPLETE * mCurrentWeight + Math.min(progress, PercentProgressListener.PROGRESS_COMPLETE) * mWeights.get(mCurrentStep))); } } }