Skip to content

Commit 938945f

Browse files
authored
Merge pull request #1993 from learningequality/release-v0.5.x
0.5 -> Develop
2 parents a6a5a0e + f7d01f6 commit 938945f

File tree

3 files changed

+88
-41
lines changed

3 files changed

+88
-41
lines changed

kolibri/core/assets/src/state/actions.js

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -428,39 +428,53 @@ function saveLogs(store) {
428428
}
429429
}
430430

431+
function fetchPoints(store) {
432+
if (!getters.isSuperuser(store.state) && getters.isUserLoggedIn(store.state)) {
433+
const userProgressModel = UserProgressResource.getModel(getters.currentUserId(store.state));
434+
userProgressModel.fetch().then(progress => {
435+
store.dispatch('SET_TOTAL_PROGRESS', progress.progress);
436+
});
437+
}
438+
}
439+
431440
/**
432-
* Update the progress percentage
433-
* To be called periodically by content renderers on interval or on pause
434-
* Must be called after initContentSession
435-
* @param {float} progressPercent
436-
* @param {boolean} forceSave
441+
* Helper function to handle common functionality between updateProgress and updateExerciseProgress
442+
* @param {VuexStore} store The currently active Vuex store
443+
* @param {Number} sessionProgress The progress made in this session
444+
* @param {[type]} summaryProgress The progress made on this content overall
445+
* @param {boolean} forceSave Force saving of logs?
437446
*/
438-
function updateProgress(store, progressPercent, forceSave = false) {
447+
function _updateProgress(store, sessionProgress, summaryProgress, forceSave = false) {
439448
/* Create aliases for logs */
440449
const summaryLog = store.state.core.logging.summary;
441450
const sessionLog = store.state.core.logging.session;
442451

443452
/* Store original value to check if 100% reached this iteration */
444453
const originalProgress = summaryLog.progress;
445454

446-
/* Calculate progress based on progressPercent */
447-
const sessionProgress = sessionLog.progress + progressPercent;
448-
const summaryProgress = summaryLog.id
449-
? Math.min(1, summaryLog.progress_before_current_session + sessionProgress)
450-
: 0;
451-
452455
/* Update the logging state with new progress information */
453456
store.dispatch('SET_LOGGING_PROGRESS', sessionProgress, summaryProgress);
454457

455-
/* Determine if progress threshold has been met */
456-
const progressThresholdMet =
457-
sessionProgress - sessionLog.progress_at_last_save >= progressThreshold;
458-
459-
/* Mark completion time if 100% progress reached */
458+
/* Mark completion time if 100% progress reached
459+
* Also, increase totalProgress model to avoid a refetch from server
460+
*/
460461
const completedContent = originalProgress < 1 && summaryProgress === 1;
461462
if (completedContent) {
462463
store.dispatch('SET_LOGGING_COMPLETION_TIME', now());
464+
if (!getters.isSuperuser(store.state) && getters.isUserLoggedIn(store.state)) {
465+
const userProgressModel = UserProgressResource.getModel(getters.currentUserId(store.state));
466+
// Fetch first to ensure we never accidentally have an undefined progress
467+
userProgressModel.fetch().then(progress => {
468+
userProgressModel.set({
469+
progress: progress.progress + 1,
470+
});
471+
});
472+
fetchPoints(store);
473+
}
463474
}
475+
/* Determine if progress threshold has been met */
476+
const progressThresholdMet =
477+
sessionProgress - sessionLog.progress_at_last_save >= progressThreshold;
464478

465479
/* Save models if needed */
466480
if (forceSave || completedContent || progressThresholdMet) {
@@ -469,22 +483,34 @@ function updateProgress(store, progressPercent, forceSave = false) {
469483
return summaryProgress;
470484
}
471485

486+
/**
487+
* Update the progress percentage
488+
* To be called periodically by content renderers on interval or on pause
489+
* Must be called after initContentSession
490+
* @param {float} progressPercent
491+
* @param {boolean} forceSave
492+
*/
493+
function updateProgress(store, progressPercent, forceSave = false) {
494+
/* Create aliases for logs */
495+
const summaryLog = store.state.core.logging.summary;
496+
const sessionLog = store.state.core.logging.session;
497+
498+
/* Calculate progress based on progressPercent */
499+
// TODO rtibbles: Delegate this to the renderers?
500+
const sessionProgress = sessionLog.progress + progressPercent;
501+
const summaryProgress = summaryLog.id
502+
? Math.min(1, summaryLog.progress_before_current_session + sessionProgress)
503+
: 0;
504+
505+
return _updateProgress(store, sessionProgress, summaryProgress, forceSave);
506+
}
507+
472508
/**
473509
summary and session log progress update for exercise
474510
**/
475511
function updateExerciseProgress(store, progressPercent, forceSave = false) {
476512
/* Update the logging state with new progress information */
477-
store.dispatch('SET_LOGGING_PROGRESS', progressPercent, progressPercent);
478-
479-
/* Mark completion time if 100% progress reached */
480-
if (progressPercent === 1) {
481-
store.dispatch('SET_LOGGING_COMPLETION_TIME', now());
482-
}
483-
484-
/* Save models if needed */
485-
if (forceSave || progressPercent === 1) {
486-
saveLogs(store);
487-
}
513+
return _updateProgress(store, progressPercent, progressPercent, forceSave);
488514
}
489515

490516
/**
@@ -702,15 +728,6 @@ function updateMasteryAttemptState(
702728
});
703729
}
704730

705-
function fetchPoints(store) {
706-
if (!getters.isSuperuser(store.state) && getters.isUserLoggedIn(store.state)) {
707-
const userProgressModel = UserProgressResource.getModel(store.state.core.session.user_id);
708-
userProgressModel.fetch().then(progress => {
709-
store.dispatch('SET_TOTAL_PROGRESS', progress.progress);
710-
});
711-
}
712-
}
713-
714731
export {
715732
handleError,
716733
handleApiError,

kolibri/core/assets/src/state/store.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ const mutations = {
8585
},
8686
SET_LOGGING_PROGRESS(state, sessionProgress, summaryProgress) {
8787
state.core.logging.session.progress = sessionProgress;
88-
if (state.core.logging.summary.progress < 1.0 && summaryProgress >= 1.0) {
89-
state.core.totalProgress += 1;
90-
}
9188
state.core.logging.summary.progress = summaryProgress;
9289
},
9390
SET_LOGGING_COMPLETION_TIME(state, time) {

kolibri/plugins/learn/assets/src/views/content-page/index.vue

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,42 @@
136136
},
137137
data: () => ({ wasIncomplete: false }),
138138
computed: {
139+
/**
140+
* Detects whether an Android device is using WebView.
141+
* Based on https://developer.chrome.com/multidevice/user-agent#webview_user_agent
142+
*/
143+
isAndroidWebView() {
144+
const ua = window.navigator.userAgent;
145+
const isAndroid = /Android/.test(ua);
146+
147+
if (isAndroid) {
148+
const androidVersion = parseFloat(ua.match(/Android\s([0-9\.]*)/)[1]);
149+
const isChrome = /Chrome/.test(ua);
150+
151+
// WebView UA in Lollipop and Above
152+
// Android >=5.0
153+
if (androidVersion >= 5.0 && isChrome && /wv/.test(ua)) {
154+
return true;
155+
}
156+
157+
// WebView UA in KitKat to Lollipop
158+
// Android >= 4.4
159+
if (androidVersion >= 4.4 && androidVersion < 5.0 && isChrome && /Version\//.test(ua)) {
160+
return true;
161+
}
162+
163+
// Old WebView UA
164+
// Android < 4.4
165+
if (androidVersion < 4.4 && /Version\//.test(ua) && /\/534.30/.test(ua)) {
166+
return true;
167+
}
168+
}
169+
170+
return false;
171+
},
139172
canDownload() {
140173
if (this.content) {
141-
return this.content.kind !== ContentNodeKinds.EXERCISE;
174+
return this.content.kind !== ContentNodeKinds.EXERCISE && !this.isAndroidWebView;
142175
}
143176
return false;
144177
},

0 commit comments

Comments
 (0)