From c5ff3e398da554ee0410d9720c7d8e324c42710e Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 12:44:41 +0300 Subject: [PATCH 01/30] add stories kit --- app/build.gradle | 1 + build.gradle | 2 ++ dependencies.gradle | 2 ++ 3 files changed, 5 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 15e8b066ce..a5cccd132e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -172,6 +172,7 @@ dependencies { implementation libraries.MPAndroidChart implementation libraries.shortcutBadger + implementation libraries.StoriesKit debugImplementation libraries.leakCanary releaseImplementation libraries.leakCanaryNoOp diff --git a/build.gradle b/build.gradle index 654a132d6b..a9961a9fa1 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ buildscript { google() maven { url "https://jitpack.io" } maven { url "https://maven.fabric.io/public" } + maven { url "https://dl.bintray.com/eadm/ru.nobird.android" } } dependencies { classpath gradlePlugins.android @@ -27,6 +28,7 @@ allprojects { jcenter() google() maven { url "https://jitpack.io" } + maven { url "https://dl.bintray.com/eadm/ru.nobird.android" } } } diff --git a/dependencies.gradle b/dependencies.gradle index 26602e7074..0ff19b4bfc 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -59,6 +59,7 @@ ext.versions = [ MPAndroidChart : 'v3.0.3', shortcutBadger : '1.1.19@aar', + StoriesKit : '1.0.0@aar', stetho : '1.4.2', leakCanary : '1.5.1', @@ -144,6 +145,7 @@ ext.libraries = [ MPAndroidChart : "com.github.PhilJay:MPAndroidChart:$versions.MPAndroidChart", shortcutBadger : "me.leolin:ShortcutBadger:$versions.shortcutBadger", + StoriesKit : "ru.nobird.android:storieskit:$versions.StoriesKit", // Developer Tools leakCanary : "com.squareup.leakcanary:leakcanary-android:$versions.leakCanary", From d3902c81131b2663d058c1f8ad846c18410503a2 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 12:44:56 +0300 Subject: [PATCH 02/30] fix null cursor handling --- .../droid/persistence/storage/dao/SystemDownloadsDaoImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/stepic/droid/persistence/storage/dao/SystemDownloadsDaoImpl.kt b/app/src/main/java/org/stepic/droid/persistence/storage/dao/SystemDownloadsDaoImpl.kt index 8c1511cd5e..464ab9d48c 100644 --- a/app/src/main/java/org/stepic/droid/persistence/storage/dao/SystemDownloadsDaoImpl.kt +++ b/app/src/main/java/org/stepic/droid/persistence/storage/dao/SystemDownloadsDaoImpl.kt @@ -16,7 +16,7 @@ constructor( Observable.just(emptyList()) } else { Observable.create { emitter -> - downloadManager.query(DownloadManager.Query().setFilterById(*ids)).use { cursor -> + downloadManager.query(DownloadManager.Query().setFilterById(*ids))?.use { cursor -> while (cursor.moveToNext()) { emitter.onNext(SystemDownloadRecord( id = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID)), From ec3db3f8fdfdeb905b30110d2480266d2d32af04 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 13:17:25 +0300 Subject: [PATCH 03/30] add story templates model --- .../org/stepik/android/model/StoryTemplate.kt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 model/src/main/java/org/stepik/android/model/StoryTemplate.kt diff --git a/model/src/main/java/org/stepik/android/model/StoryTemplate.kt b/model/src/main/java/org/stepik/android/model/StoryTemplate.kt new file mode 100644 index 0000000000..9bb8555983 --- /dev/null +++ b/model/src/main/java/org/stepik/android/model/StoryTemplate.kt @@ -0,0 +1,56 @@ +package org.stepik.android.model + +import com.google.gson.annotations.SerializedName + +data class StoryTemplate( + val id: Long, + val cover: String, + val title: String, + + @SerializedName("is_published") + val isPublished: Boolean, + + val parts: List, + + val language: String, + val position: Int, + val version: Int +) { + data class Part( + val duration: Long, + val image: String, + val position: Int, + val type: String, + + val button: Button?, + val text: Text? + ) + + data class Text( + @SerializedName("background_style") + val backgroundStyle: String, + + @SerializedName("text") + val text: String, + + @SerializedName("text_color") + val textColor: String, + + @SerializedName("title") + val title: String + ) + + data class Button( + @SerializedName("background_color") + val backgroundColor: String, + + @SerializedName("text_color") + val textColor: String, + + @SerializedName("title") + val title: String, + + @SerializedName("url") + val url: String + ) +} \ No newline at end of file From 59084d4dc200b3b10461d2a7e49816a59e8a0132 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 14:53:12 +0300 Subject: [PATCH 04/30] StoryTemplates dao + api call + repository --- .../stepic/droid/di/network/NetworkModule.kt | 5 ++ .../droid/di/storage/StorageComponent.kt | 4 ++ .../stepic/droid/di/storage/StorageModule.kt | 6 +++ .../stories/model/ViewedStoryTemplate.kt | 3 ++ .../repository/StoryTemplatesRepository.kt | 13 +++++ .../StoryTemplatesRepositoryImpl.kt | 52 +++++++++++++++++++ .../dao/ViewedStoryTemplatesDaoImpl.kt | 32 ++++++++++++ .../DbStructureViewedStoryTemplates.kt | 21 ++++++++ .../storage/operations/DatabaseFacade.kt | 5 +- .../main/java/org/stepic/droid/web/Api.java | 4 ++ .../java/org/stepic/droid/web/ApiImpl.java | 10 +++- .../droid/web/StepicRestLoggedService.java | 8 +++ .../story_templates/StoryTemplatesResponse.kt | 13 +++++ 13 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/features/stories/model/ViewedStoryTemplate.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepository.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/storage/dao/ViewedStoryTemplatesDaoImpl.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/storage/structure/DbStructureViewedStoryTemplates.kt create mode 100644 app/src/main/java/org/stepic/droid/web/model/story_templates/StoryTemplatesResponse.kt diff --git a/app/src/main/java/org/stepic/droid/di/network/NetworkModule.kt b/app/src/main/java/org/stepic/droid/di/network/NetworkModule.kt index 62a6c54b00..95e79d30cb 100644 --- a/app/src/main/java/org/stepic/droid/di/network/NetworkModule.kt +++ b/app/src/main/java/org/stepic/droid/di/network/NetworkModule.kt @@ -8,6 +8,8 @@ import org.stepic.droid.features.achievements.repository.AchievementsRepository import org.stepic.droid.features.achievements.repository.AchievementsRepositoryImpl import org.stepic.droid.features.deadlines.repository.DeadlinesRepository import org.stepic.droid.features.deadlines.repository.DeadlinesRepositoryImpl +import org.stepic.droid.features.stories.repository.StoryTemplatesRepository +import org.stepic.droid.features.stories.repository.StoryTemplatesRepositoryImpl import org.stepic.droid.web.ApiImpl import org.stepic.droid.web.StepicRestLoggedService import org.stepic.droid.web.achievements.AchievementsService @@ -23,6 +25,9 @@ abstract class NetworkModule { @AppSingleton abstract fun bindAchievementsRepository(achievementsRepositoryImpl: AchievementsRepositoryImpl): AchievementsRepository + @Binds + abstract fun bindStoryTemplatesRepository(storyTemplatesRepositoryImpl: StoryTemplatesRepositoryImpl): StoryTemplatesRepository + @Module companion object { @Provides diff --git a/app/src/main/java/org/stepic/droid/di/storage/StorageComponent.kt b/app/src/main/java/org/stepic/droid/di/storage/StorageComponent.kt index 6520e4ed7b..8636ecda86 100644 --- a/app/src/main/java/org/stepic/droid/di/storage/StorageComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/storage/StorageComponent.kt @@ -5,8 +5,10 @@ import dagger.BindsInstance import dagger.Component import org.stepic.droid.features.deadlines.storage.dao.DeadlinesBannerDao import org.stepic.droid.features.deadlines.storage.operations.DeadlinesRecordOperations +import org.stepic.droid.features.stories.model.ViewedStoryTemplate import org.stepic.droid.persistence.storage.dao.PersistentItemDao import org.stepic.droid.persistence.storage.dao.PersistentStateDao +import org.stepic.droid.storage.dao.IDao import org.stepic.droid.storage.operations.DatabaseFacade @Component(modules = [StorageModule::class]) @@ -27,4 +29,6 @@ interface StorageComponent { val deadlinesBannerDao: DeadlinesBannerDao val persistentItemDao: PersistentItemDao val persistentStateDao: PersistentStateDao + + val viewedStoryTemplatesDao: IDao } diff --git a/app/src/main/java/org/stepic/droid/di/storage/StorageModule.kt b/app/src/main/java/org/stepic/droid/di/storage/StorageModule.kt index a59d6679ec..9d50ce776c 100644 --- a/app/src/main/java/org/stepic/droid/di/storage/StorageModule.kt +++ b/app/src/main/java/org/stepic/droid/di/storage/StorageModule.kt @@ -15,6 +15,8 @@ import org.stepic.droid.features.deadlines.storage.operations.DeadlinesRecordOpe import org.stepic.droid.features.deadlines.storage.operations.DeadlinesRecordOperationsImpl import org.stepic.droid.features.deadlines.storage.dao.PersonalDeadlinesDao import org.stepic.droid.features.deadlines.storage.dao.PersonalDeadlinesDaoImpl +import org.stepic.droid.features.stories.model.ViewedStoryTemplate +import org.stepic.droid.features.stories.storage.dao.ViewedStoryTemplatesDaoImpl import org.stepic.droid.jsonHelpers.adapters.UTCDateAdapter import org.stepic.droid.model.* import org.stepic.droid.model.code.CodeSubmission @@ -136,6 +138,10 @@ abstract class StorageModule { @Binds internal abstract fun providePersistentStateDao(persistentStateDaoImpl: PersistentStateDaoImpl): PersistentStateDao + @StorageSingleton + @Binds + internal abstract fun provideViewedStoryTemplatesDao(viewedStoryTemplatesDaoImpl: ViewedStoryTemplatesDaoImpl): IDao + @Module companion object { diff --git a/app/src/main/java/org/stepic/droid/features/stories/model/ViewedStoryTemplate.kt b/app/src/main/java/org/stepic/droid/features/stories/model/ViewedStoryTemplate.kt new file mode 100644 index 0000000000..87e213e7c6 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/model/ViewedStoryTemplate.kt @@ -0,0 +1,3 @@ +package org.stepic.droid.features.stories.model + +class ViewedStoryTemplate(val storyTemplateId: Long) \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepository.kt b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepository.kt new file mode 100644 index 0000000000..523ad6e259 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepository.kt @@ -0,0 +1,13 @@ +package org.stepic.droid.features.stories.repository + +import io.reactivex.Completable +import io.reactivex.Single +import org.stepik.android.model.StoryTemplate + +interface StoryTemplatesRepository { + fun getStoryTemplates(): Single> + + fun getViewedStoriesIds(): Single> + + fun markStoryAsViewed(storyTemplateId: Long): Completable +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt new file mode 100644 index 0000000000..58011d4378 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt @@ -0,0 +1,52 @@ +package org.stepic.droid.features.stories.repository + +import io.reactivex.Completable +import io.reactivex.Observable +import io.reactivex.Single +import io.reactivex.rxkotlin.toObservable +import org.stepic.droid.di.AppSingleton +import org.stepic.droid.features.stories.model.ViewedStoryTemplate +import org.stepic.droid.storage.dao.IDao +import org.stepic.droid.web.Api +import org.stepic.droid.web.model.story_templates.StoryTemplatesResponse +import org.stepik.android.model.StoryTemplate +import javax.inject.Inject + +@AppSingleton +class StoryTemplatesRepositoryImpl +@Inject +constructor( + private val api: Api, + private val viewedStoryTemplateDao: IDao +) : StoryTemplatesRepository { + override fun getStoryTemplates(): Single> = + getStoryTemplatesByPage(1) + .concatMap { it.storyTemplates.toObservable() } + .toList() + .map { it.sortedBy(StoryTemplate::position) } + + private fun getStoryTemplatesByPage(page: Int): Observable = + api.getStoryTemplates(page) + .concatMap { + val templatesObservable = Observable.just(it) + if (it.meta.hasNext) { + templatesObservable.concatWith(getStoryTemplatesByPage(it.meta.page + 1)) + } else { + templatesObservable + } + } + + override fun getViewedStoriesIds(): Single> = Single.create { emitter -> + emitter.onSuccess( + viewedStoryTemplateDao + .getAll() + .asSequence() + .map(ViewedStoryTemplate::storyTemplateId) + .toSet() + ) + } + + override fun markStoryAsViewed(storyTemplateId: Long): Completable = Completable.fromAction { + viewedStoryTemplateDao.insertOrReplace(ViewedStoryTemplate(storyTemplateId)) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/storage/dao/ViewedStoryTemplatesDaoImpl.kt b/app/src/main/java/org/stepic/droid/features/stories/storage/dao/ViewedStoryTemplatesDaoImpl.kt new file mode 100644 index 0000000000..2f658b2d55 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/storage/dao/ViewedStoryTemplatesDaoImpl.kt @@ -0,0 +1,32 @@ +package org.stepic.droid.features.stories.storage.dao + +import android.content.ContentValues +import android.database.Cursor +import org.stepic.droid.di.storage.StorageSingleton +import org.stepic.droid.features.stories.model.ViewedStoryTemplate +import org.stepic.droid.features.stories.storage.structure.DbStructureViewedStoryTemplates +import org.stepic.droid.storage.dao.DaoBase +import org.stepic.droid.storage.operations.DatabaseOperations +import javax.inject.Inject + +@StorageSingleton +class ViewedStoryTemplatesDaoImpl +@Inject +constructor(databaseOperations: DatabaseOperations): DaoBase(databaseOperations) { + override fun getDbName(): String = + DbStructureViewedStoryTemplates.VIEWED_STORY_TEMPLATES + + override fun getDefaultPrimaryColumn(): String = + DbStructureViewedStoryTemplates.Columns.ID + + override fun getDefaultPrimaryValue(persistentObject: ViewedStoryTemplate): String = + persistentObject.storyTemplateId.toString() + + override fun getContentValues(persistentObject: ViewedStoryTemplate): ContentValues = ContentValues(1).apply { + put(DbStructureViewedStoryTemplates.Columns.ID, persistentObject.storyTemplateId) + } + + override fun parsePersistentObject(cursor: Cursor): ViewedStoryTemplate = + ViewedStoryTemplate(cursor.getLong(cursor.getColumnIndex(DbStructureViewedStoryTemplates.Columns.ID))) + +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/storage/structure/DbStructureViewedStoryTemplates.kt b/app/src/main/java/org/stepic/droid/features/stories/storage/structure/DbStructureViewedStoryTemplates.kt new file mode 100644 index 0000000000..85a4d9411d --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/storage/structure/DbStructureViewedStoryTemplates.kt @@ -0,0 +1,21 @@ +package org.stepic.droid.features.stories.storage.structure + +import android.database.sqlite.SQLiteDatabase + +object DbStructureViewedStoryTemplates { + const val VIEWED_STORY_TEMPLATES = "viewed_story_templates" + + object Columns { + const val ID = "id" + } + + fun createTable(db: SQLiteDatabase) { + val sql = """ + CREATE TABLE IF NOT EXISTS $VIEWED_STORY_TEMPLATES ( + ${Columns.ID} LONG, + PRIMARY KEY(${Columns.ID}) + )""".trimIndent() + + db.execSQL(sql) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/storage/operations/DatabaseFacade.kt b/app/src/main/java/org/stepic/droid/storage/operations/DatabaseFacade.kt index 4da258aafd..9dc7c73445 100644 --- a/app/src/main/java/org/stepic/droid/storage/operations/DatabaseFacade.kt +++ b/app/src/main/java/org/stepic/droid/storage/operations/DatabaseFacade.kt @@ -12,6 +12,7 @@ import org.stepic.droid.notifications.model.Notification import org.stepic.droid.storage.dao.AdaptiveExpDao import org.stepic.droid.storage.dao.IDao import org.stepic.droid.features.deadlines.storage.dao.PersonalDeadlinesDao +import org.stepic.droid.features.stories.model.ViewedStoryTemplate import org.stepic.droid.storage.dao.SearchQueryDao import org.stepic.droid.storage.structure.* import org.stepic.droid.util.AppConstants @@ -48,7 +49,8 @@ class DatabaseFacade private val externalVideoUrlDao: IDao, private val blockDao: IDao, private val personalDeadlinesDao: PersonalDeadlinesDao, - private val deadlinesBannerDao: DeadlinesBannerDao + private val deadlinesBannerDao: DeadlinesBannerDao, + private val viewedStoryTemplatesDao: IDao ) { fun dropDatabase() { @@ -73,6 +75,7 @@ class DatabaseFacade adaptiveExpDao.removeAll() personalDeadlinesDao.removeAll() deadlinesBannerDao.removeAll() + viewedStoryTemplatesDao.removeAll() } fun getCourseDao(table: Table) = diff --git a/app/src/main/java/org/stepic/droid/web/Api.java b/app/src/main/java/org/stepic/droid/web/Api.java index 2572cb3b0d..38c5c49b38 100644 --- a/app/src/main/java/org/stepic/droid/web/Api.java +++ b/app/src/main/java/org/stepic/droid/web/Api.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.stepic.droid.web.model.story_templates.StoryTemplatesResponse; import org.stepik.android.model.adaptive.RatingItem; import org.stepik.android.model.Course; import org.stepic.droid.model.NotificationCategory; @@ -21,6 +22,7 @@ import java.util.List; import io.reactivex.Completable; +import io.reactivex.Observable; import io.reactivex.Single; import retrofit2.Call; @@ -185,4 +187,6 @@ enum TokenType { Completable putRating(long courseId, long exp); Single restoreRating(long courseId); + + Observable getStoryTemplates(int page); } diff --git a/app/src/main/java/org/stepic/droid/web/ApiImpl.java b/app/src/main/java/org/stepic/droid/web/ApiImpl.java index 661bbae231..c323de1af9 100644 --- a/app/src/main/java/org/stepic/droid/web/ApiImpl.java +++ b/app/src/main/java/org/stepic/droid/web/ApiImpl.java @@ -2,6 +2,7 @@ import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -21,6 +22,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.stepic.droid.R; +import org.stepic.droid.util.CompatibilityExtensionsKt; +import org.stepic.droid.web.model.story_templates.StoryTemplatesResponse; import org.stepik.android.model.adaptive.RatingItem; import org.stepic.droid.analytic.Analytic; import org.stepic.droid.configuration.Config; @@ -82,6 +85,7 @@ import javax.inject.Inject; import io.reactivex.Completable; +import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.functions.Function; import kotlin.Unit; @@ -927,7 +931,11 @@ public Single restoreRating(long courseId) { } - + @Override + public Observable getStoryTemplates(int page) { + final Locale locale = CompatibilityExtensionsKt.getDefaultLocale(Resources.getSystem().getConfiguration()); + return loggedService.getStoryTemplate(page, false, locale.getLanguage()); + } @Override public Single getSearchResultsOfTag(int page, @NotNull Tag tag) { diff --git a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java index 4f2cffd56f..d09b70983a 100644 --- a/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java +++ b/app/src/main/java/org/stepic/droid/web/StepicRestLoggedService.java @@ -3,11 +3,13 @@ import org.jetbrains.annotations.Nullable; import org.stepic.droid.web.model.adaptive.RecommendationReactionsRequest; import org.stepic.droid.web.model.adaptive.RecommendationsResponse; +import org.stepic.droid.web.model.story_templates.StoryTemplatesResponse; import org.stepik.android.model.EnrollmentWrapper; import java.util.List; import io.reactivex.Completable; +import io.reactivex.Observable; import io.reactivex.Single; import retrofit2.Call; import retrofit2.http.Body; @@ -244,4 +246,10 @@ Single getNextRecommendations( Completable createRecommendationReaction( @Body final RecommendationReactionsRequest reactionsRequest ); + + Observable getStoryTemplate( + @Query("page") final int page, + @Query("is_published") final boolean isPublished, + @Query("language") final String language + ); } diff --git a/app/src/main/java/org/stepic/droid/web/model/story_templates/StoryTemplatesResponse.kt b/app/src/main/java/org/stepic/droid/web/model/story_templates/StoryTemplatesResponse.kt new file mode 100644 index 0000000000..328ce424a6 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/web/model/story_templates/StoryTemplatesResponse.kt @@ -0,0 +1,13 @@ +package org.stepic.droid.web.model.story_templates + +import com.google.gson.annotations.SerializedName +import org.stepic.droid.web.MetaResponseBase +import org.stepik.android.model.Meta +import org.stepik.android.model.StoryTemplate + +class StoryTemplatesResponse( + meta: Meta, + + @SerializedName("story-templates") + val storyTemplates: List +) : MetaResponseBase(meta) \ No newline at end of file From 1855434d5cdb4d63a329dd6eab19fbe158544f77 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 15:34:49 +0300 Subject: [PATCH 05/30] use support version of stories kit --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 0ff19b4bfc..3eb9b1ff4c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -145,7 +145,7 @@ ext.libraries = [ MPAndroidChart : "com.github.PhilJay:MPAndroidChart:$versions.MPAndroidChart", shortcutBadger : "me.leolin:ShortcutBadger:$versions.shortcutBadger", - StoriesKit : "ru.nobird.android:storieskit:$versions.StoriesKit", + StoriesKit : "ru.nobird.android:storieskitsupport:$versions.StoriesKit", // Developer Tools leakCanary : "com.squareup.leakcanary:leakcanary-android:$versions.leakCanary", From f57fc0139f6a132b5e174e4f6674b5e7153c8b9c Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 15:55:52 +0300 Subject: [PATCH 06/30] add StoriesActivity + delegate --- app/src/main/AndroidManifest.xml | 4 +++ .../stories/ui/activity/StoriesActivity.kt | 22 ++++++++++++++++ .../ui/delegate/StoriesActivityDelegate.kt | 25 +++++++++++++++++++ app/src/main/res/layout/activity_stories.xml | 12 +++++++++ 4 files changed, 63 insertions(+) create mode 100644 app/src/main/java/org/stepic/droid/features/stories/ui/activity/StoriesActivity.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/ui/delegate/StoriesActivityDelegate.kt create mode 100644 app/src/main/res/layout/activity_stories.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bbaeb972db..95dd2b1004 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -373,6 +373,10 @@ + + diff --git a/app/src/main/java/org/stepic/droid/features/stories/ui/activity/StoriesActivity.kt b/app/src/main/java/org/stepic/droid/features/stories/ui/activity/StoriesActivity.kt new file mode 100644 index 0000000000..15368bf751 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/ui/activity/StoriesActivity.kt @@ -0,0 +1,22 @@ +package org.stepic.droid.features.stories.ui.activity + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import org.stepic.droid.R +import org.stepic.droid.features.stories.ui.delegate.StoriesActivityDelegate + +class StoriesActivity : AppCompatActivity() { + private lateinit var storiesDelegate: StoriesActivityDelegate + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_stories) + storiesDelegate = StoriesActivityDelegate(this) + storiesDelegate.onCreate(savedInstanceState) + } + + override fun onPause() { + storiesDelegate.onPause() + super.onPause() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/ui/delegate/StoriesActivityDelegate.kt b/app/src/main/java/org/stepic/droid/features/stories/ui/delegate/StoriesActivityDelegate.kt new file mode 100644 index 0000000000..ea9cf9f7f1 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/ui/delegate/StoriesActivityDelegate.kt @@ -0,0 +1,25 @@ +package org.stepic.droid.features.stories.ui.delegate + +import android.os.Bundle +import android.support.v4.view.ViewPager +import android.support.v7.app.AppCompatActivity +import kotlinx.android.synthetic.main.activity_stories.* +import ru.nobird.android.stories.ui.custom.DismissableLayout +import ru.nobird.android.stories.ui.delegate.StoriesActivityDelegateBase +import ru.nobird.android.stories.ui.delegate.StoryPartViewDelegate + +class StoriesActivityDelegate( + activity: AppCompatActivity +) : StoriesActivityDelegateBase(activity) { + override val dismissableLayout: DismissableLayout = + activity.content + + override val storiesViewPager: ViewPager = + activity.storiesPager + + override val arguments: Bundle = + activity.intent.extras ?: Bundle.EMPTY + + override val storyPartDelegates: List = + listOf() +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_stories.xml b/app/src/main/res/layout/activity_stories.xml new file mode 100644 index 0000000000..0b3119b292 --- /dev/null +++ b/app/src/main/res/layout/activity_stories.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file From c16692b0f91087c06c126574de0e56b5e865a852 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 17:03:31 +0300 Subject: [PATCH 07/30] story template mapper + plain text with button story part --- .../stories/mapper/StoryTemplatesMapper.kt | 22 ++++++++++++ .../model/PlainTextWithButtonStoryPart.kt | 35 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 app/src/main/java/org/stepic/droid/features/stories/mapper/StoryTemplatesMapper.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/model/PlainTextWithButtonStoryPart.kt diff --git a/app/src/main/java/org/stepic/droid/features/stories/mapper/StoryTemplatesMapper.kt b/app/src/main/java/org/stepic/droid/features/stories/mapper/StoryTemplatesMapper.kt new file mode 100644 index 0000000000..8b1d82ac80 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/mapper/StoryTemplatesMapper.kt @@ -0,0 +1,22 @@ +package org.stepic.droid.features.stories.mapper + +import org.stepic.droid.features.stories.model.PlainTextWithButtonStoryPart +import org.stepik.android.model.StoryTemplate +import ru.nobird.android.stories.model.Story +import ru.nobird.android.stories.model.StoryPart + +fun StoryTemplate.toStory(): Story = + Story( + id, + title, + cover, + parts.map(StoryTemplate.Part::toStoryPart) + ) + +fun StoryTemplate.Part.toStoryPart(): StoryPart = + PlainTextWithButtonStoryPart( + duration * 1000, // convert seconds to ms + image, + button, + text + ) \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/model/PlainTextWithButtonStoryPart.kt b/app/src/main/java/org/stepic/droid/features/stories/model/PlainTextWithButtonStoryPart.kt new file mode 100644 index 0000000000..ffcad31009 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/model/PlainTextWithButtonStoryPart.kt @@ -0,0 +1,35 @@ +package org.stepic.droid.features.stories.model + +import android.os.Parcel +import android.os.Parcelable +import org.stepik.android.model.StoryTemplate +import ru.nobird.android.stories.model.StoryPart + +class PlainTextWithButtonStoryPart( + duration: Long, + image: String, + + val button: StoryTemplate.Button?, + val text: StoryTemplate.Text? +): StoryPart(duration, image) { + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeLong(duration) + parcel.writeString(cover) + parcel.writeParcelable(button, flags) + parcel.writeParcelable(text, flags) + } + + override fun describeContents(): Int = 0 + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel) = PlainTextWithButtonStoryPart( + parcel.readLong(), + parcel.readString(), + parcel.readParcelable(StoryTemplate.Button::class.java.classLoader), + parcel.readParcelable(StoryTemplate.Text::class.java.classLoader) + ) + + override fun newArray(size: Int) = + arrayOfNulls(size) + } +} \ No newline at end of file From 073db9c060ba6c3c14ed9554985efc744b223b65 Mon Sep 17 00:00:00 2001 From: Ruslan Davletshin Date: Tue, 18 Sep 2018 17:04:14 +0300 Subject: [PATCH 08/30] stories view MVP --- .../stories/presentation/StoriesPresenter.kt | 68 +++++++++++++++++++ .../stories/presentation/StoriesView.kt | 14 ++++ .../StoryTemplatesRepositoryImpl.kt | 11 ++- .../org/stepik/android/model/StoryTemplate.kt | 48 ++++++++++++- 4 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesPresenter.kt create mode 100644 app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesView.kt diff --git a/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesPresenter.kt b/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesPresenter.kt new file mode 100644 index 0000000000..4ef906ffca --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesPresenter.kt @@ -0,0 +1,68 @@ +package org.stepic.droid.features.stories.presentation + +import io.reactivex.Scheduler +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.Singles.zip +import io.reactivex.rxkotlin.subscribeBy +import org.stepic.droid.core.presenters.PresenterBase +import org.stepic.droid.di.qualifiers.BackgroundScheduler +import org.stepic.droid.di.qualifiers.MainScheduler +import org.stepic.droid.features.stories.mapper.toStory +import org.stepic.droid.features.stories.repository.StoryTemplatesRepository +import org.stepic.droid.util.addDisposable +import org.stepik.android.model.StoryTemplate +import javax.inject.Inject + +class StoriesPresenter +@Inject +constructor( + private val storiesRepository: StoryTemplatesRepository, + + @BackgroundScheduler + private val backgroundScheduler: Scheduler, + @MainScheduler + private val mainScheduler: Scheduler +) : PresenterBase() { + private var state : StoriesView.State = StoriesView.State.Idle + set(value) { + field = value + view?.setState(value) + } + + private val compositeDisposable = CompositeDisposable() + + init { + fetchStories() + } + + private fun fetchStories() { + if (state != StoriesView.State.Idle) return + state = StoriesView.State.Loading + + compositeDisposable addDisposable + zip(storiesRepository.getStoryTemplates().map { it.map(StoryTemplate::toStory) }, storiesRepository.getViewedStoriesIds()) + .subscribeOn(backgroundScheduler) + .observeOn(mainScheduler) + .subscribeBy({ + state = StoriesView.State.Empty + }) { (stories, viewedIds) -> + state = StoriesView.State.Success(stories, viewedIds) + } + } + + override fun attachView(view: StoriesView) { + super.attachView(view) + view.setState(state) + } + + fun onStoryViewed(storyId: Long) { + compositeDisposable addDisposable storiesRepository + .markStoryAsViewed(storyId) + .subscribeBy({ /* ignore */ }) { + val state = this.state + if (state is StoriesView.State.Success) { + this.state = state.copy(viewedStoriesIds = state.viewedStoriesIds + storyId) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesView.kt b/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesView.kt new file mode 100644 index 0000000000..27cd716a86 --- /dev/null +++ b/app/src/main/java/org/stepic/droid/features/stories/presentation/StoriesView.kt @@ -0,0 +1,14 @@ +package org.stepic.droid.features.stories.presentation + +import ru.nobird.android.stories.model.Story + +interface StoriesView { + fun setState(state: State) + + sealed class State { + object Idle : State() + object Loading : State() + object Empty : State() + data class Success(val stories: List, val viewedStoriesIds: Set) : State() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt index 58011d4378..1ef4729a27 100644 --- a/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt +++ b/app/src/main/java/org/stepic/droid/features/stories/repository/StoryTemplatesRepositoryImpl.kt @@ -19,11 +19,20 @@ constructor( private val api: Api, private val viewedStoryTemplateDao: IDao ) : StoryTemplatesRepository { + companion object { + const val STORY_TEMPLATES_VERSION = 1 + } + override fun getStoryTemplates(): Single> = getStoryTemplatesByPage(1) .concatMap { it.storyTemplates.toObservable() } .toList() - .map { it.sortedBy(StoryTemplate::position) } + .map { + it.asSequence() + .filter { template -> template.version <= STORY_TEMPLATES_VERSION } + .sortedBy(StoryTemplate::position) + .toList() + } private fun getStoryTemplatesByPage(page: Int): Observable = api.getStoryTemplates(page) diff --git a/model/src/main/java/org/stepik/android/model/StoryTemplate.kt b/model/src/main/java/org/stepik/android/model/StoryTemplate.kt index 9bb8555983..945cf87bd8 100644 --- a/model/src/main/java/org/stepik/android/model/StoryTemplate.kt +++ b/model/src/main/java/org/stepik/android/model/StoryTemplate.kt @@ -1,5 +1,7 @@ package org.stepik.android.model +import android.os.Parcel +import android.os.Parcelable import com.google.gson.annotations.SerializedName data class StoryTemplate( @@ -38,7 +40,28 @@ data class StoryTemplate( @SerializedName("title") val title: String - ) + ) : Parcelable { + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(backgroundStyle) + parcel.writeString(text) + parcel.writeString(textColor) + parcel.writeString(title) + } + + override fun describeContents(): Int = 0 + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel) = Text( + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readString() + ) + + override fun newArray(size: Int) = + arrayOfNulls(size) + } + } data class Button( @SerializedName("background_color") @@ -52,5 +75,26 @@ data class StoryTemplate( @SerializedName("url") val url: String - ) + ) : Parcelable { + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(backgroundColor) + parcel.writeString(textColor) + parcel.writeString(title) + parcel.writeString(url) + } + + override fun describeContents(): Int = 0 + + companion object CREATOR : Parcelable.Creator