Skip to content

Commit

Permalink
Merge branch 'release/1.51'
Browse files Browse the repository at this point in the history
  • Loading branch information
eadm committed Jan 25, 2018
2 parents aed87bc + 2b3a4df commit 02338be
Show file tree
Hide file tree
Showing 121 changed files with 3,239 additions and 183 deletions.
3 changes: 3 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
-keep class org.stepic.droid.model.** { *; }
-keep interface org.stepic.droid.model.** { *; }

-keep class org.stepic.droid.adaptive.model.** { *; }
-keep interface org.stepic.droid.adaptive.model.** { *; }

-keep class org.stepic.droid.web.** { *; }
-keep interface org.stepic.droid.web.** { *; }
-dontwarn org.stepic.droid.web.**
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@

<activity android:name=".ui.activities.TagActivity" />

<activity
android:name=".adaptive.ui.activities.AdaptiveCourseActivity"
android:theme="@style/Adaptive" />

<activity
android:name=".adaptive.ui.activities.AdaptiveOnboardingActivity"
android:theme="@style/Adaptive" />


<receiver
android:name="org.stepic.droid.receivers.DownloadCompleteReceiver"
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/assets/web/images/arrow_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions app/src/main/assets/web/images/arrow_right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.stepic.droid.adaptive.listeners

import org.stepic.droid.adaptive.model.Reaction

interface AdaptiveReactionListener {
fun createReaction(lessonId: Long, reaction: Reaction)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.stepic.droid.adaptive.listeners

interface AnswerListener {
fun onCorrectAnswer(submissionId: Long)
fun onWrongAnswer()
}
150 changes: 150 additions & 0 deletions app/src/main/java/org/stepic/droid/adaptive/math/LinearRegression.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package org.stepic.droid.adaptive.math;

/******************************************************************************
*
* Compute least squares solution to y = beta * x + alpha.
* Simple linear regression.
*
******************************************************************************/


import java.util.Locale;

/**
* The {@code LinearRegression} class performs a simple linear regression
* on an set of <em>n</em> data points (<em>y<sub>i</sub></em>, <em>x<sub>i</sub></em>).
* That is, it fits a straight line <em>y</em> = &alpha; + &beta; <em>x</em>,
* (where <em>y</em> is the response variable, <em>x</em> is the predictor variable,
* &alpha; is the <em>y-intercept</em>, and &beta; is the <em>slope</em>)
* that minimizes the sum of squared residuals of the linear regression model.
* It also computes associated statistics, including the coefficient of
* determination <em>R</em><sup>2</sup> and the standard deviation of the
* estimates for the slope and <em>y</em>-intercept.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public class LinearRegression {
private final double intercept, slope;
private final double r2;
private final double svar0, svar1;

/**
* Performs a linear regression on the data points {@code (y[i], x[i])}.
*
* @param x the values of the predictor variable
* @param y the corresponding values of the response variable
* @throws IllegalArgumentException if the lengths of the two arrays are not equal
*/
public LinearRegression(double[] x, double[] y) {
if (x.length != y.length) {
throw new IllegalArgumentException("array lengths are not equal");
}
int n = x.length;

// first pass
double sumx = 0.0, sumy = 0.0, sumx2 = 0.0;
for (int i = 0; i < n; i++) {
sumx += x[i];
sumx2 += x[i] * x[i];
sumy += y[i];
}
double xbar = sumx / n;
double ybar = sumy / n;

// second pass: compute summary statistics
double xxbar = 0.0, yybar = 0.0, xybar = 0.0;
for (int i = 0; i < n; i++) {
xxbar += (x[i] - xbar) * (x[i] - xbar);
yybar += (y[i] - ybar) * (y[i] - ybar);
xybar += (x[i] - xbar) * (y[i] - ybar);
}
slope = xybar / xxbar;
intercept = ybar - slope * xbar;

// more statistical analysis
double rss = 0.0; // residual sum of squares
double ssr = 0.0; // regression sum of squares
for (int i = 0; i < n; i++) {
double fit = slope * x[i] + intercept;
rss += (fit - y[i]) * (fit - y[i]);
ssr += (fit - ybar) * (fit - ybar);
}

int degreesOfFreedom = n - 2;
r2 = ssr / yybar;
double svar = rss / degreesOfFreedom;
svar1 = svar / xxbar;
svar0 = svar / n + xbar * xbar * svar1;
}

/**
* Returns the <em>y</em>-intercept &alpha; of the best of the best-fit line <em>y</em> = &alpha; + &beta; <em>x</em>.
*
* @return the <em>y</em>-intercept &alpha; of the best-fit line <em>y = &alpha; + &beta; x</em>
*/
public double intercept() {
return intercept;
}

/**
* Returns the slope &beta; of the best of the best-fit line <em>y</em> = &alpha; + &beta; <em>x</em>.
*
* @return the slope &beta; of the best-fit line <em>y</em> = &alpha; + &beta; <em>x</em>
*/
public double slope() {
return slope;
}

/**
* Returns the coefficient of determination <em>R</em><sup>2</sup>.
*
* @return the coefficient of determination <em>R</em><sup>2</sup>,
* which is a real number between 0 and 1
*/
public double R2() {
return r2;
}

/**
* Returns the standard error of the estimate for the intercept.
*
* @return the standard error of the estimate for the intercept
*/
public double interceptStdErr() {
return Math.sqrt(svar0);
}

/**
* Returns the standard error of the estimate for the slope.
*
* @return the standard error of the estimate for the slope
*/
public double slopeStdErr() {
return Math.sqrt(svar1);
}

/**
* Returns the expected response {@code y} given the value of the predictor
* variable {@code x}.
*
* @param x the value of the predictor variable
* @return the expected response {@code y} given the value of the predictor
* variable {@code x}
*/
public double predict(double x) {
return slope * x + intercept;
}

/**
* Returns a string representation of the simple linear regression model.
*
* @return a string representation of the simple linear regression model,
* including the best-fit line and the coefficient of determination
* <em>R</em><sup>2</sup>
*/
public String toString() {
return String.format(Locale.ENGLISH, "%.2f n + %.2f (R^2 = %.3f)", slope(), intercept(), R2());
}

}
139 changes: 139 additions & 0 deletions app/src/main/java/org/stepic/droid/adaptive/model/Card.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package org.stepic.droid.adaptive.model

import io.reactivex.Observable
import io.reactivex.Scheduler
import io.reactivex.Single
import io.reactivex.SingleObserver
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import org.stepic.droid.base.App
import org.stepic.droid.di.qualifiers.BackgroundScheduler
import org.stepic.droid.di.qualifiers.MainScheduler
import org.stepic.droid.model.Attempt
import org.stepic.droid.model.Lesson
import org.stepic.droid.model.Step
import org.stepic.droid.web.Api
import javax.inject.Inject

class Card(
val courseId: Long,
val lessonId: Long,

var lesson: Lesson? = null,
var step: Step? = null,
var attempt: Attempt? = null
) : Single<Card>() {
@Inject
lateinit var api: Api

@Inject
@field:MainScheduler
lateinit var mainScheduler: Scheduler

@Inject
@field:BackgroundScheduler
lateinit var backgroundScheduler: Scheduler

init {
App.componentManager()
.adaptiveCourseComponent(courseId)
.inject(this)
}

private var observer: SingleObserver<in Card>? = null

private var error: Throwable? = null

private var lessonDisposable: Disposable? = null
private var stepSubscription: Disposable? = null
private var attemptDisposable: Disposable? = null

private val compositeDisposable = CompositeDisposable()

var correct = false
private set

fun initCard() {
error = null

if (stepSubscription == null || stepSubscription?.isDisposed == true && step == null) {
stepSubscription = api.getStepsByLessonId(lessonId)
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.subscribe({ setStep(it.steps?.firstOrNull()) }, { onError(it) })
} else {
setStep(step)
}

if (lessonDisposable == null || lessonDisposable?.isDisposed == true && lesson == null) {
lessonDisposable = api.getLessons(lessonId)
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.subscribe({ setLesson(it.lessons?.firstOrNull()) }, { onError(it) })
}
}

private fun setStep(newStep: Step?) = newStep?.let {
this.step = newStep
if (attemptDisposable == null || attemptDisposable?.isDisposed == true && attempt == null) {
attemptDisposable = Observable.concat(
api.getExistingAttemptsReactive(newStep.id).toObservable(),
api.createNewAttemptReactive(newStep.id).toObservable()
)
.filter { it.attempts.isNotEmpty() }
.take(1)
.map { it.attempts.firstOrNull() }
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.subscribe({ setAttempt(it) }, { onError(it) })
}

notifyDataChanged()
}

private fun setLesson(lesson: Lesson?) = lesson?.let {
this.lesson = it
notifyDataChanged()
}

private fun setAttempt(attempt: Attempt?) = attempt?.let {
this.attempt = it
notifyDataChanged()
}

private fun onError(error: Throwable?) {
this.error = error
notifyDataChanged()
}

private fun notifyDataChanged() = observer?.let {
error?.let(it::onError)

if (lesson != null && step != null && attempt != null) {
it.onSuccess(this)
}
}

/**
* Free resources
*/
fun recycle() {
App.componentManager()
.releaseAdaptiveCourseComponent(courseId)
lessonDisposable?.dispose()
stepSubscription?.dispose()
attemptDisposable?.dispose()
compositeDisposable.dispose()
observer = null
}

override fun subscribeActual(observer: SingleObserver<in Card>) {
this.observer = observer
initCard()
notifyDataChanged()
}

fun onCorrect() {
correct = true
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/org/stepic/droid/adaptive/model/Reaction.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.stepic.droid.adaptive.model

enum class Reaction(val value: Int) {
SOLVED(2), INTERESTING(1), MAYBE_LATER(0), NEVER_AGAIN(-1)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.stepic.droid.adaptive.model

class Recommendation(
val id: Long,
val lesson: Long,
val reasons: List<String>?)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.stepic.droid.adaptive.model


class RecommendationReaction(val lesson: Long, reaction: Reaction, var user: Long = 0) {
private val reaction = reaction.value
}
Loading

0 comments on commit 02338be

Please sign in to comment.