<?xml version="1.0" encoding="UTF-8" standalone="no"?><addon xmlns="http://icplayer.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Completion_Progress" xsi:schemaLocation="http://icplayer.com ../../tools/addon.xsd">
    <model>
        <property name="Turn off automatic counting" nameLabel="Completion_Progress_property_turn_off_automatic_counting" type="boolean"/>
    </model>
<css>.addon_Completion_Progress {
    padding: 2px;
    width: 130px;
    height: 25px;
    border-radius: 5px;
    border: 2px solid black;
}

.addon_Completion_Progress .progress-bar {
    background-color: #FA8805;
    border-radius: 5px;
    height: 100%;
}

.addon_Completion_Progress .progress-text {
    color: #000000;
    font-size: 18px;
    position: absolute;
    width: 10%;
    left: 45%;
    height: 50%;
    top: 25%;
    text-align: center;
}
</css><view>&lt;div class="progress-bar" style="width: 0;"&gt;&lt;/div&gt;
&lt;div class="progress-text"&gt;0%&lt;/div&gt;
</view><preview>&lt;div class="progress-bar" style="width: 45%;"&gt;&lt;/div&gt;
&lt;div class="progress-text"&gt;45%&lt;/div&gt;
</preview><presenter>function AddonCompletion_Progress_create() {
    var presenter = function () { };

    var playerController;
    var eventBus;

    presenter.currentProgress = 0;
    presenter.modules = [];

    presenter.setPlayerController = function(controller) {
        playerController = controller;
        eventBus = controller.getEventBus();
        eventBus.addEventListener('PageLoaded', this);

        presenter.page = controller.getPresentation().getPage(controller.getCurrentPageIndex());
    };

    presenter.updateProgress = function () {
        if (presenter.modules.length == 0) {
            presenter.currentProgress = 0;
        } else {
            var attemptedCount = 0;

            for (var i = 0; i &lt; presenter.modules.length; i++) {
                if (presenter.modules[i].isAttempted()) {
                    attemptedCount++;
                }
            }

            presenter.currentProgress = Math.floor((attemptedCount / presenter.modules.length) * 100);
        }

        presenter.updateProgressUI(presenter.currentProgress);
    };

    presenter.loadModules = function () {
        if (!presenter.page.isReportable()) {
            return;
        }

        var modules = presenter.page.getModulesAsJS(),
            module, loadedModules = [];

        for (var i = 0; i &lt; modules.length; i++) {
            module = playerController.getModule(modules[i]);

            if (module &amp;&amp; module.isAttempted !== undefined) {
                loadedModules.push(module);
            }
        }

        presenter.modules = loadedModules;
    };

    presenter.validateModel = function (model) {
        return {
            automaticCounting: !ModelValidationUtils.validateBoolean(model['Turn off automatic counting']),
            isVisible: ModelValidationUtils.validateBoolean(model['Is Visible'])
        };
    };

    presenter.presenterLogic = function (view, model, isPreview) {
        presenter.pageLoadedDeferred = new $.Deferred();
        presenter.pageLoaded = presenter.pageLoadedDeferred.promise();

        presenter.$view = $(view);
        presenter.model = model;
        presenter.configuration = presenter.validateModel(model);

        presenter.setVisibility(presenter.configuration.isVisible || isPreview);

        if (!isPreview &amp;&amp; presenter.configuration.automaticCounting) {
            eventBus.addEventListener('ValueChanged', this);
            presenter.pageLoaded.then(function() {
                presenter.loadModules();
                presenter.updateProgress();
            });
        }
    };

    presenter.onEventReceived = function (eventName) {
        if (eventName == "ValueChanged") {
            presenter.updateProgress();
        }
        if (eventName == 'PageLoaded') {
            presenter.pageLoadedDeferred.resolve();
        }
    };

    presenter.run = function (view, model) {
        presenter.presenterLogic(view, model, false);
    };
    
    presenter.createPreview = function (view, model) {
        presenter.presenterLogic(view, model, true);
    };


    presenter.getState = function () {
        return JSON.stringify({
            isVisible: presenter.configuration.isVisible,
            currentProgress: presenter.currentProgress
        });
    };

    presenter.setState = function (state) {
       if (!state) return;

        var parsedState = JSON.parse(state);

        presenter.configuration.isVisible = parsedState.isVisible;
        presenter.setVisibility(presenter.configuration.isVisible);

        presenter.currentProgress = parsedState.currentProgress;
        presenter.updateProgressUI(presenter.currentProgress);
    };
    
    presenter.executeCommand = function (name, params) {
        var commands = {
            'show': presenter.show,
            'hide': presenter.hide,
            'setProgress': presenter.setProgressCommand,
            'getProgress': presenter.getProgress
        };

        return Commands.dispatch(commands, name, params, presenter);
    };

    presenter.setVisibility = function (isVisible) {
        presenter.$view.css('visibility', isVisible ? 'visible' : 'hidden');
    };
    
    presenter.hide = function () {
        presenter.setVisibility(false);
        presenter.configuration.isVisible = false;
    };

    presenter.show = function () {
        presenter.setVisibility(true);
        presenter.configuration.isVisible = true;
    };

    presenter.updateProgressUI = function (progress) {
        presenter.$view.find('.progress-bar').css('width', progress + '%');
        presenter.$view.find('.progress-text').text(progress + '%');
    };

    presenter.reset = function () {
        presenter.currentProgress = 0;

        presenter.updateProgressUI(0);
    };

    presenter.getProgress = function () {
        return presenter.currentProgress;
    };

    presenter.setProgress = function (progress) {
        var validatedProgress = ModelValidationUtils.validateIntegerInRange(progress, 100);

        if (!validatedProgress.isValid) {
            return;
        }

        presenter.currentProgress = validatedProgress.value;
        presenter.updateProgressUI(presenter.currentProgress);
    };

    presenter.setProgressCommand = function (params) {
        presenter.setProgress(params[0]);
    };

    return presenter;
}
</presenter></addon>