Skip to content

Commit 920d4d2

Browse files
authored
Merge pull request #1167 from hyperskill/release/1.70
Release 1.70
2 parents ac33a4b + d4d9269 commit 920d4d2

File tree

45 files changed

+1459
-550
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1459
-550
lines changed

androidHyperskillApp/Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ source "https://rubygems.org"
22
ruby "3.3.0"
33

44
gem "fastlane", "2.222.0"
5-
gem "rexml", ">= 3.3.3"
5+
gem "rexml", ">= 3.3.6"
66

77
eval_gemfile("fastlane/Pluginfile")

androidHyperskillApp/Gemfile.lock

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ GEM
1010
artifactory (3.0.17)
1111
atomos (0.1.3)
1212
aws-eventstream (1.3.0)
13-
aws-partitions (1.962.0)
14-
aws-sdk-core (3.201.3)
13+
aws-partitions (1.968.0)
14+
aws-sdk-core (3.202.0)
1515
aws-eventstream (~> 1, >= 1.3.0)
1616
aws-partitions (~> 1, >= 1.651.0)
17-
aws-sigv4 (~> 1.8)
17+
aws-sigv4 (~> 1.9)
1818
jmespath (~> 1, >= 1.6.1)
1919
aws-sdk-kms (1.88.0)
2020
aws-sdk-core (~> 3, >= 3.201.0)
2121
aws-sigv4 (~> 1.5)
22-
aws-sdk-s3 (1.157.0)
22+
aws-sdk-s3 (1.159.0)
2323
aws-sdk-core (~> 3, >= 3.201.0)
2424
aws-sdk-kms (~> 1)
2525
aws-sigv4 (~> 1.5)
@@ -154,7 +154,7 @@ GEM
154154
os (>= 0.9, < 2.0)
155155
signet (>= 0.16, < 2.a)
156156
highline (2.0.3)
157-
http-cookie (1.0.6)
157+
http-cookie (1.0.7)
158158
domain_name (~> 0.5)
159159
httpclient (2.8.3)
160160
jmespath (1.6.2)
@@ -178,7 +178,7 @@ GEM
178178
trailblazer-option (>= 0.1.1, < 0.2.0)
179179
uber (< 0.2.0)
180180
retriable (3.1.2)
181-
rexml (3.3.4)
181+
rexml (3.3.6)
182182
strscan
183183
rouge (2.0.7)
184184
ruby2_keywords (0.0.5)
@@ -204,12 +204,13 @@ GEM
204204
uber (0.1.0)
205205
unicode-display_width (2.5.0)
206206
word_wrap (1.0.0)
207-
xcodeproj (1.19.0)
207+
xcodeproj (1.25.0)
208208
CFPropertyList (>= 2.3.3, < 4.0)
209209
atomos (~> 0.1.3)
210210
claide (>= 1.0.2, < 2.0)
211211
colored2 (~> 3.1)
212212
nanaimo (~> 0.3.0)
213+
rexml (>= 3.3.2, < 4.0)
213214
xcpretty (0.3.0)
214215
rouge (~> 2.0.7)
215216
xcpretty-travis-formatter (1.0.1)
@@ -225,7 +226,7 @@ PLATFORMS
225226
DEPENDENCIES
226227
fastlane (= 2.222.0)
227228
fastlane-plugin-firebase_app_distribution
228-
rexml (>= 3.3.3)
229+
rexml (>= 3.3.6)
229230

230231
RUBY VERSION
231232
ruby 3.3.0p0
Lines changed: 16 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.hyperskill.app.android.study_plan.delegate
22

33
import android.content.Context
4-
import androidx.annotation.ColorInt
5-
import androidx.core.content.ContextCompat
64
import androidx.recyclerview.widget.LinearLayoutManager
75
import androidx.recyclerview.widget.RecyclerView
86
import org.hyperskill.app.android.R
@@ -14,6 +12,7 @@ import org.hyperskill.app.android.study_plan.adapter.ActivityLoadingAdapterDeleg
1412
import org.hyperskill.app.android.study_plan.adapter.StudyPlanActivityAdapterDelegate
1513
import org.hyperskill.app.android.study_plan.adapter.StudyPlanItemAnimator
1614
import org.hyperskill.app.android.study_plan.adapter.StudyPlanSectionAdapterDelegate
15+
import org.hyperskill.app.android.study_plan.mapper.StudyPlanWidgetUIStateMapper
1716
import org.hyperskill.app.android.study_plan.model.StudyPlanRecyclerItem
1817
import org.hyperskill.app.study_plan.widget.presentation.StudyPlanWidgetFeature
1918
import org.hyperskill.app.study_plan.widget.view.model.StudyPlanWidgetViewState
@@ -27,11 +26,6 @@ class StudyPlanWidgetDelegate(
2726
private val onNewMessage: (StudyPlanWidgetFeature.Message) -> Unit
2827
) {
2928

30-
companion object {
31-
private const val SECTIONS_LOADING_ITEMS_COUNT = 4
32-
private const val ACTIVITIES_LOADING_ITEMS_COUNT = 3
33-
}
34-
3529
private val studyPlanAdapter = DefaultDelegateAdapter<StudyPlanRecyclerItem>().apply {
3630
addDelegate(StudyPlanSectionAdapterDelegate(onNewMessage))
3731
addDelegate(
@@ -46,6 +40,7 @@ class StudyPlanWidgetDelegate(
4640
)
4741
addDelegate(sectionsLoadingAdapterDelegate())
4842
addDelegate(loadAllTopicsButtonDelegate())
43+
addDelegate(expandCompletedActivitiesButtonDelegate())
4944
addDelegate(paywallAdapterDelegate())
5045
addDelegate(ActivityLoadingAdapterDelegate())
5146
addDelegate(
@@ -55,39 +50,15 @@ class StudyPlanWidgetDelegate(
5550
)
5651
}
5752

58-
@ColorInt private val inactiveSectionTextColor: Int =
59-
ContextCompat.getColor(context, org.hyperskill.app.R.color.color_on_surface_alpha_60)
60-
61-
@ColorInt private val activeSectionTextColor: Int =
62-
ContextCompat.getColor(context, org.hyperskill.app.R.color.color_on_surface)
63-
64-
@ColorInt private val activeActivityTextColor: Int =
65-
ContextCompat.getColor(context, org.hyperskill.app.R.color.color_on_surface_alpha_87)
66-
67-
@ColorInt private val inactiveActivityTextColor: Int =
68-
ContextCompat.getColor(context, org.hyperskill.app.R.color.color_on_surface_alpha_60)
53+
private val uiStateMapper: StudyPlanWidgetUIStateMapper = StudyPlanWidgetUIStateMapper(context)
6954

7055
private val sectionTopMargin =
7156
context.resources.getDimensionPixelOffset(R.dimen.study_plan_section_top_margin)
7257
private val activityTopMargin =
7358
context.resources.getDimensionPixelOffset(R.dimen.study_plan_activity_top_margin)
7459

75-
private val activeIcon =
76-
ContextCompat.getDrawable(context, R.drawable.ic_home_screen_arrow_button)
77-
private val skippedIcon =
78-
ContextCompat.getDrawable(context, R.drawable.ic_topic_skipped)
79-
private val completedIcon =
80-
ContextCompat.getDrawable(context, R.drawable.ic_topic_completed)
81-
private val lockedIcon =
82-
ContextCompat.getDrawable(context, R.drawable.ic_activity_locked)
83-
8460
private var studyPlanViewStateDelegate: ViewStateDelegate<StudyPlanWidgetViewState>? = null
8561

86-
private val sectionsLoadingItems: List<StudyPlanRecyclerItem.SectionLoading> =
87-
List(SECTIONS_LOADING_ITEMS_COUNT) { index ->
88-
StudyPlanRecyclerItem.SectionLoading(index)
89-
}
90-
9162
fun setup(recyclerView: RecyclerView, errorViewBinding: ErrorNoConnectionWithButtonBinding) {
9263
studyPlanViewStateDelegate = ViewStateDelegate<StudyPlanWidgetViewState>().apply {
9364
addState<StudyPlanWidgetViewState.Idle>()
@@ -138,7 +109,8 @@ class StudyPlanWidgetDelegate(
138109
is StudyPlanRecyclerItem.ActivityLoading,
139110
is StudyPlanRecyclerItem.Activity,
140111
is StudyPlanRecyclerItem.ActivitiesError,
141-
is StudyPlanRecyclerItem.LoadAllTopicsButton -> activityTopMargin
112+
is StudyPlanRecyclerItem.LoadAllTopicsButton,
113+
is StudyPlanRecyclerItem.ExpandCompletedActivitiesButton -> activityTopMargin
142114
else -> 0
143115
}
144116

@@ -148,17 +120,7 @@ class StudyPlanWidgetDelegate(
148120

149121
fun render(state: StudyPlanWidgetViewState) {
150122
studyPlanViewStateDelegate?.switchState(state)
151-
when (state) {
152-
StudyPlanWidgetViewState.Loading -> {
153-
studyPlanAdapter.items = sectionsLoadingItems
154-
}
155-
is StudyPlanWidgetViewState.Content -> {
156-
studyPlanAdapter.items = mapContentToRecyclerItems(state)
157-
}
158-
else -> {
159-
// no op
160-
}
161-
}
123+
studyPlanAdapter.items = uiStateMapper.map(state)
162124
}
163125

164126
private fun sectionsLoadingAdapterDelegate() =
@@ -188,87 +150,17 @@ class StudyPlanWidgetDelegate(
188150
}
189151
}
190152

191-
private fun mapContentToRecyclerItems(
192-
studyPlanContent: StudyPlanWidgetViewState.Content
193-
): List<StudyPlanRecyclerItem> =
194-
buildList {
195-
if (studyPlanContent.isPaywallBannerShown) {
196-
add(StudyPlanRecyclerItem.PaywallBanner)
197-
}
198-
studyPlanContent.sections.forEachIndexed { sectionIndex, section ->
199-
add(mapSectionToRecyclerItem(sectionIndex, section))
200-
when (val sectionContent = section.content) {
201-
StudyPlanWidgetViewState.SectionContent.Collapsed -> {
202-
// no op
203-
}
204-
StudyPlanWidgetViewState.SectionContent.Loading -> {
205-
addAll(getActivitiesLoadingItems(section.id))
206-
}
207-
is StudyPlanWidgetViewState.SectionContent.Content -> {
208-
addAll(mapSectionItemsToActivityItems(section.id, sectionContent.sectionItems))
209-
if (sectionContent.isLoadAllTopicsButtonShown) {
210-
add(StudyPlanRecyclerItem.LoadAllTopicsButton(section.id))
211-
}
212-
if (sectionContent.isNextPageLoadingShowed) {
213-
addAll(getActivitiesLoadingItems(section.id))
214-
}
215-
}
216-
StudyPlanWidgetViewState.SectionContent.Error -> {
217-
add(StudyPlanRecyclerItem.ActivitiesError(section.id))
218-
}
153+
private fun expandCompletedActivitiesButtonDelegate() =
154+
adapterDelegate<StudyPlanRecyclerItem, StudyPlanRecyclerItem.ExpandCompletedActivitiesButton>(
155+
R.layout.item_study_plan_expand_completed_button
156+
) {
157+
itemView.setOnClickListener {
158+
val sectionId = item?.sectionId
159+
if (sectionId != null) {
160+
onNewMessage(
161+
StudyPlanWidgetFeature.Message.ExpandCompletedActivitiesClicked(sectionId)
162+
)
219163
}
220164
}
221165
}
222-
223-
private fun mapSectionToRecyclerItem(
224-
index: Int,
225-
section: StudyPlanWidgetViewState.Section
226-
): StudyPlanRecyclerItem.Section =
227-
StudyPlanRecyclerItem.Section(
228-
id = section.id,
229-
title = section.title,
230-
titleTextColor = if (index == 0) {
231-
activeSectionTextColor
232-
} else {
233-
inactiveSectionTextColor
234-
},
235-
subtitle = section.subtitle,
236-
formattedTopicsCount = section.formattedTopicsCount,
237-
formattedTimeToComplete = section.formattedTimeToComplete,
238-
isExpanded = section.content !is StudyPlanWidgetViewState.SectionContent.Collapsed,
239-
isCurrentBadgeShown = section.isCurrentBadgeShown
240-
)
241-
242-
private fun mapSectionItemsToActivityItems(
243-
sectionId: Long,
244-
sectionItems: List<StudyPlanWidgetViewState.SectionItem>
245-
): List<StudyPlanRecyclerItem.Activity> =
246-
sectionItems.map { item ->
247-
StudyPlanRecyclerItem.Activity(
248-
id = item.id,
249-
sectionId = sectionId,
250-
title = item.title,
251-
subtitle = item.subtitle,
252-
titleTextColor = if (item.state == StudyPlanWidgetViewState.SectionItemState.NEXT) {
253-
activeActivityTextColor
254-
} else {
255-
inactiveActivityTextColor
256-
},
257-
progress = item.progress,
258-
formattedProgress = item.formattedProgress,
259-
endIcon = when (item.state) {
260-
StudyPlanWidgetViewState.SectionItemState.IDLE -> null
261-
StudyPlanWidgetViewState.SectionItemState.NEXT -> activeIcon
262-
StudyPlanWidgetViewState.SectionItemState.SKIPPED -> skippedIcon
263-
StudyPlanWidgetViewState.SectionItemState.COMPLETED -> completedIcon
264-
StudyPlanWidgetViewState.SectionItemState.LOCKED -> lockedIcon
265-
},
266-
isIdeRequired = item.isIdeRequired
267-
)
268-
}
269-
270-
private fun getActivitiesLoadingItems(sectionId: Long) =
271-
List(ACTIVITIES_LOADING_ITEMS_COUNT) { index ->
272-
StudyPlanRecyclerItem.ActivityLoading(sectionId, index)
273-
}
274166
}

0 commit comments

Comments
 (0)