Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import org.stepic.droid.di.home.HomeScope
import org.stepic.droid.di.qualifiers.BackgroundScheduler
import org.stepic.droid.di.qualifiers.MainScheduler
import org.stepic.droid.preferences.SharedPreferenceHelper
import org.stepic.droid.util.StepikUtil
import org.stepik.android.domain.user_activity.repository.UserActivityRepository
import ru.nobird.android.domain.rx.emptyOnErrorStub
import ru.nobird.android.domain.rx.toMaybe
import javax.inject.Inject

@HomeScope
Expand All @@ -32,14 +30,8 @@ constructor(
fun onNeedShowStreak() {
compositeDisposable += Maybe
.fromCallable { sharedPreferences.profile?.id }
.flatMapSingleElement(userActivityRepository::getUserActivities)
.flatMap { userActivities ->
userActivities
.firstOrNull()
?.pins
?.let(StepikUtil::getCurrentStreak)
.toMaybe()
}
.flatMapSingleElement(userActivityRepository::getUserActivitySummary)
.map { it.recentStrike }
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.subscribeBy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.reactivex.Single
import org.stepik.android.data.user_activity.source.UserActivityRemoteDataSource
import org.stepik.android.domain.user_activity.repository.UserActivityRepository
import org.stepik.android.model.user.UserActivity
import org.stepik.android.model.user.UserActivitySummary
import javax.inject.Inject

class UserActivityRepositoryImpl
Expand All @@ -14,4 +15,7 @@ constructor(

override fun getUserActivities(userId: Long): Single<List<UserActivity>> =
userActivityRemoteDataSource.getUserActivities(userId)

override fun getUserActivitySummary(userId: Long): Single<UserActivitySummary> =
userActivityRemoteDataSource.getUserActivitySummary(userId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package org.stepik.android.data.user_activity.source

import io.reactivex.Single
import org.stepik.android.model.user.UserActivity
import org.stepik.android.model.user.UserActivitySummary

interface UserActivityRemoteDataSource {
fun getUserActivities(userId: Long): Single<List<UserActivity>>

fun getUserActivitySummary(userId: Long): Single<UserActivitySummary>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package org.stepik.android.domain.profile_activities.interactor
import io.reactivex.Single
import org.stepik.android.domain.profile_activities.model.ProfileActivitiesData
import org.stepik.android.domain.user_activity.repository.UserActivityRepository
import org.stepik.android.model.user.UserActivity
import ru.nobird.android.domain.rx.first
import org.stepik.android.model.user.UserActivitySummary
import javax.inject.Inject
import kotlin.math.max

class ProfileActivitiesInteractor
@Inject
Expand All @@ -15,28 +13,14 @@ constructor(
) {
fun getProfileActivities(userId: Long): Single<ProfileActivitiesData> =
userActivityRepository
.getUserActivities(userId)
.first()
.getUserActivitySummary(userId)
.map(::mapToProfileActivities)

private fun mapToProfileActivities(userActivity: UserActivity): ProfileActivitiesData {
var streak = 0
var maxStreak = 0
var buffer = 0

for (i in 0..userActivity.pins.size) {
val pin = userActivity.pins.getOrElse(i) { 0 }
if (pin > 0) {
buffer++
} else {
maxStreak = max(maxStreak, buffer)
if (buffer == i || buffer == i - 1) { // first is solved today, second not solved
streak = buffer
}
buffer = 0
}
}

return ProfileActivitiesData(userActivity.pins, streak, maxStreak, isSolvedToday = userActivity.pins[0] > 0)
}
private fun mapToProfileActivities(userActivitySummary: UserActivitySummary): ProfileActivitiesData =
ProfileActivitiesData(
pins = userActivitySummary.pins,
streak = userActivitySummary.recentStrike,
maxStreak = userActivitySummary.maxStrike,
isSolvedToday = userActivitySummary.solvedToday > 0
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package org.stepik.android.domain.streak.interactor

import io.reactivex.Maybe
import org.stepic.droid.preferences.SharedPreferenceHelper
import org.stepic.droid.util.StepikUtil
import ru.nobird.android.domain.rx.toMaybe
import org.stepik.android.domain.user_activity.repository.UserActivityRepository
import org.stepik.android.view.streak.notification.StreakNotificationDelegate
import javax.inject.Inject
Expand All @@ -24,9 +22,8 @@ constructor(
fun onNeedShowStreak(): Maybe<Int> =
Maybe
.fromCallable { sharedPreferenceHelper.profile?.id }
.flatMapSingleElement { userActivityRepository.getUserActivities(it) }
.flatMap { it.firstOrNull()?.pins.toMaybe() }
.map { StepikUtil.getCurrentStreak(it) }
.flatMapSingleElement { userActivityRepository.getUserActivitySummary(it) }
.map { it.recentStrike }

fun setStreakTime(timeIntervalCode: Int) {
sharedPreferenceHelper.isStreakNotificationEnabled = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package org.stepik.android.domain.user_activity.repository

import io.reactivex.Single
import org.stepik.android.model.user.UserActivity
import org.stepik.android.model.user.UserActivitySummary

interface UserActivityRepository {
fun getUserActivities(userId: Long): Single<List<UserActivity>>

fun getUserActivitySummary(userId: Long): Single<UserActivitySummary>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import io.reactivex.Single
import io.reactivex.functions.Function
import org.stepik.android.data.user_activity.source.UserActivityRemoteDataSource
import org.stepik.android.model.user.UserActivity
import org.stepik.android.model.user.UserActivitySummary
import org.stepik.android.remote.user_activity.model.UserActivityResponse
import org.stepik.android.remote.user_activity.model.UserActivitySummaryResponse
import org.stepik.android.remote.user_activity.service.UserActivityService
import javax.inject.Inject

Expand All @@ -16,8 +18,16 @@ constructor(
private val userActivityResponseMapper =
Function<UserActivityResponse, List<UserActivity>>(UserActivityResponse::userActivities)

private val userActivitySummaryResponseMapper =
Function<UserActivitySummaryResponse, UserActivitySummary> { it.userActivitySummaries.first() }

override fun getUserActivities(userId: Long): Single<List<UserActivity>> =
userActivityService
.getUserActivitiesReactive(userId)
.map(userActivityResponseMapper)

override fun getUserActivitySummary(userId: Long): Single<UserActivitySummary> =
userActivityService
.getUserActivitySummaryReactive(userId)
.map(userActivitySummaryResponseMapper)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.stepik.android.remote.user_activity.model

import com.google.gson.annotations.SerializedName
import org.stepik.android.model.Meta
import org.stepik.android.model.user.UserActivitySummary
import org.stepik.android.remote.base.model.MetaResponse

class UserActivitySummaryResponse(
@SerializedName("meta")
override val meta: Meta,
@SerializedName("user-activity-summaries")
val userActivitySummaries: List<UserActivitySummary>
) : MetaResponse
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package org.stepik.android.remote.user_activity.service

import io.reactivex.Single
import org.stepik.android.remote.user_activity.model.UserActivityResponse
import org.stepik.android.remote.user_activity.model.UserActivitySummaryResponse
import retrofit2.http.GET
import retrofit2.http.Path

interface UserActivityService {
@GET("api/user-activities/{userId}")
fun getUserActivitiesReactive(@Path("userId") userId: Long): Single<UserActivityResponse>

@GET("api/user-activity-summaries/{userId}")
fun getUserActivitySummaryReactive(@Path("userId") userId: Long): Single<UserActivitySummaryResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import org.stepic.droid.core.ScreenManager
import org.stepic.droid.preferences.SharedPreferenceHelper
import org.stepic.droid.util.AppConstants
import org.stepic.droid.util.DateTimeHelper
import org.stepic.droid.util.StepikUtil
import org.stepik.android.domain.base.analytic.BUNDLEABLE_ANALYTIC_EVENT
import org.stepik.android.domain.base.analytic.toBundle
import org.stepik.android.domain.streak.analytic.StreakNotificationClicked
Expand Down Expand Up @@ -48,23 +47,35 @@ constructor(
val numberOfStreakNotifications = sharedPreferenceHelper.numberOfStreakNotifications
if (numberOfStreakNotifications < AppConstants.MAX_NUMBER_OF_NOTIFICATION_STREAK) {
try {
val pins: ArrayList<Long> = userActivityRepository.getUserActivities(sharedPreferenceHelper.profile?.id ?: throw Exception("User is not auth"))
val userId = sharedPreferenceHelper.profile?.id
?: throw Exception("User is not auth")
val userActivitySummary = userActivityRepository
.getUserActivitySummary(userId)
.blockingGet()
.firstOrNull()
?.pins!!
val (currentStreak, isSolvedToday) = StepikUtil.getCurrentStreakExtended(pins)
if (currentStreak <= 0) {
analytic.reportEvent(Analytic.Streak.GET_ZERO_STREAK_NOTIFICATION)
showNotificationWithoutStreakInfo(StreakNotificationType.ZERO)
} else {
// if current streak is > 0 -> streaks works! -> continue send it
// it will reset before sending, after sending it will be incremented
sharedPreferenceHelper.resetNumberOfStreakNotifications()
if (isSolvedToday) {
showNotificationStreakImprovement(currentStreak)
} else {
showNotificationWithStreakCallToAction(currentStreak)

val notificationType = getStreakNotificationType(
userActivitySummary.recentStrike,
userActivitySummary.solvedToday
)

when (notificationType) {
StreakNotificationType.ZERO -> {
analytic.reportEvent(Analytic.Streak.GET_ZERO_STREAK_NOTIFICATION)
showNotificationWithoutStreakInfo(StreakNotificationType.ZERO)
}

StreakNotificationType.SOLVED_TODAY -> {
sharedPreferenceHelper.resetNumberOfStreakNotifications()
showNotificationStreakImprovement(userActivitySummary.recentStrike)
}

StreakNotificationType.NOT_SOLVED_TODAY -> {
sharedPreferenceHelper.resetNumberOfStreakNotifications()
showNotificationWithStreakCallToAction(userActivitySummary.recentStrike)
}

StreakNotificationType.NO_INTERNET ->
Unit
}
} catch (exception: Exception) {
// no internet || cant get streaks -> show some notification without streak information.
Expand Down Expand Up @@ -157,4 +168,14 @@ constructor(
.createStreakNotificationIntent(context, StreakNotificationDismissed(notificationType.type).toBundle())
return PendingIntentCompat.getBroadcast(context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT)
}
}
}

internal fun getStreakNotificationType(recentStrike: Int, solvedToday: Int): StreakNotificationType =
when {
recentStrike <= 0 ->
StreakNotificationType.ZERO
solvedToday > 0 ->
StreakNotificationType.SOLVED_TODAY
else ->
StreakNotificationType.NOT_SOLVED_TODAY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.stepik.android.domain.profile_activities.interactor

import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import io.reactivex.Single
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.stepik.android.domain.profile_activities.model.ProfileActivitiesData
import org.stepik.android.domain.user_activity.repository.UserActivityRepository
import org.stepik.android.model.user.UserActivitySummary

@RunWith(MockitoJUnitRunner::class)
class ProfileActivitiesInteractorTest {
@Mock
private lateinit var userActivityRepository: UserActivityRepository

@Test
fun `summary without solved today maps to continue streak data`() {
val pins = listOf(0L, 2L, 1L, 3L, 0L, 1L, 4L)
val summary = UserActivitySummary(
recentStrike = 377,
solvedToday = 0,
maxStrike = 412,
pins = pins
)
whenever(userActivityRepository.getUserActivitySummary(USER_ID)) doReturn Single.just(summary)

ProfileActivitiesInteractor(userActivityRepository)
.getProfileActivities(USER_ID)
.test()
.assertComplete()
.assertResult(
ProfileActivitiesData(pins, streak = 377, maxStreak = 412, isSolvedToday = false)
)

verify(userActivityRepository).getUserActivitySummary(USER_ID)
}

@Test
fun `summary with solved today maps to active streak data`() {
val pins = listOf(0L, 0L, 0L, 0L, 0L, 0L, 0L)
val summary = UserActivitySummary(
recentStrike = 378,
solvedToday = 2,
maxStrike = 412,
pins = pins
)
whenever(userActivityRepository.getUserActivitySummary(USER_ID)) doReturn Single.just(summary)

ProfileActivitiesInteractor(userActivityRepository)
.getProfileActivities(USER_ID)
.test()
.assertComplete()
.assertResult(
ProfileActivitiesData(pins, streak = 378, maxStreak = 412, isSolvedToday = true)
)

verify(userActivityRepository).getUserActivitySummary(USER_ID)
}

@Test
fun `zero summary maps to start streak data`() {
val pins = listOf(0L, 0L, 0L, 0L, 0L, 0L, 0L)
val summary = UserActivitySummary(
recentStrike = 0,
solvedToday = 0,
maxStrike = 0,
pins = pins
)
whenever(userActivityRepository.getUserActivitySummary(USER_ID)) doReturn Single.just(summary)

ProfileActivitiesInteractor(userActivityRepository)
.getProfileActivities(USER_ID)
.test()
.assertComplete()
.assertResult(
ProfileActivitiesData(pins, streak = 0, maxStreak = 0, isSolvedToday = false)
)

verify(userActivityRepository).getUserActivitySummary(USER_ID)
}

private companion object {
const val USER_ID = 1L
}
}
Loading