Skip to content

Commit

Permalink
Shared, iOS: Code blanks math expressions (#1163)
Browse files Browse the repository at this point in the history
^ALTAPPS-1324
  • Loading branch information
ivan-magda authored Aug 26, 2024
1 parent 2768d4a commit b53ba7d
Show file tree
Hide file tree
Showing 23 changed files with 1,084 additions and 157 deletions.
6 changes: 6 additions & 0 deletions config/detekt/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<ID>CyclomaticComplexMethod:StepQuizActionDispatcher.kt$StepQuizActionDispatcher$override suspend fun doSuspendableAction(action: Action)</ID>
<ID>CyclomaticComplexMethod:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleDeleteButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?</ID>
<ID>CyclomaticComplexMethod:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSuggestionClicked( state: State, message: Message.SuggestionClicked ): StepQuizCodeBlanksReducerResult?</ID>
<ID>CyclomaticComplexMethod:StepQuizCodeBlanksViewStateMapper.kt$StepQuizCodeBlanksViewStateMapper$private fun mapContentState( state: StepQuizCodeBlanksFeature.State.Content ): StepQuizCodeBlanksViewState.Content</ID>
<ID>CyclomaticComplexMethod:StepQuizHintsReducer.kt$StepQuizHintsReducer$override fun reduce(state: State, message: Message): StepQuizHintsReducerResult</ID>
<ID>CyclomaticComplexMethod:StepQuizReducer.kt$StepQuizReducer$override fun reduce(state: State, message: Message): StepQuizReducerResult</ID>
<ID>CyclomaticComplexMethod:StepQuizReplyValidator.kt$StepQuizReplyValidator$fun validate(dataset: Dataset?, reply: Reply, stepBlockName: String): ReplyValidationResult</ID>
Expand Down Expand Up @@ -67,7 +68,9 @@
<ID>LongMethod:ProfileBadges.kt$@Composable fun ProfileBadges( viewState: BadgesViewState, windowWidthSizeClass: WindowWidthSizeClass, onBadgeClick: (BadgeKind) -&gt; Unit, onExpandButtonClick: (ProfileFeature.Message.BadgesVisibilityButton) -&gt; Unit, modifier: Modifier = Modifier )</ID>
<ID>LongMethod:ProfileSettingsDialogFragment.kt$ProfileSettingsDialogFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleDeleteButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?</ID>
<ID>LongMethod:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSpaceButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?</ID>
<ID>LongMethod:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSuggestionClicked( state: State, message: Message.SuggestionClicked ): StepQuizCodeBlanksReducerResult?</ID>
<ID>LongMethod:StepQuizCodeBlanksViewStateMapper.kt$StepQuizCodeBlanksViewStateMapper$private fun mapContentState( state: StepQuizCodeBlanksFeature.State.Content ): StepQuizCodeBlanksViewState.Content</ID>
<ID>LongMethod:StreakFreezeDialogFragment.kt$StreakFreezeDialogFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:TrackProgressContent.kt$@Composable fun TrackProgressContent( viewState: ProgressScreenViewState.TrackProgressViewState.Content, onNewMessage: (ProgressScreenFeature.Message) -&gt; Unit, modifier: Modifier = Modifier )</ID>
<ID>LongParameterList:AppInteractor.kt$AppInteractor$( private val appRepository: AppRepository, private val authInteractor: AuthInteractor, private val currentProfileStateRepository: CurrentProfileStateRepository, private val userStorageInteractor: UserStorageInteractor, private val analyticInteractor: AnalyticInteractor, private val progressesRepository: ProgressesRepository, private val trackRepository: TrackRepository, private val providersRepository: ProvidersRepository, private val projectsRepository: ProjectsRepository, private val shareStreakRepository: ShareStreakRepository, private val pushNotificationsInteractor: PushNotificationsInteractor )</ID>
Expand Down Expand Up @@ -155,6 +158,7 @@
<ID>MagicNumber:StepDelegate.kt$StepDelegate$25</ID>
<ID>MagicNumber:StepDelegate.kt$StepDelegate$5</ID>
<ID>MagicNumber:StepDelegate.kt$StepDelegate$50</ID>
<ID>MagicNumber:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$47580L</ID>
<ID>MagicNumber:StudyPlanActivityAdapterDelegate.kt$StudyPlanActivityAdapterDelegate.ViewHolder$100f</ID>
<ID>MagicNumber:SubscriptionSyncLoading.kt$0.5f</ID>
<ID>MagicNumber:TableSelectionItemAdapterDelegate.kt$TableSelectionItemAdapterDelegate.ViewHolder$0.2f</ID>
Expand Down Expand Up @@ -202,6 +206,7 @@
<ID>ModifierReused:LeaderboardPlaceInfo.kt$Row( modifier = modifier, horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = placeNumber.toString(), style = MaterialTheme.typography.body2, color = colorResource(id = R.color.color_on_surface_alpha_60), modifier = Modifier.align(Alignment.CenterVertically) ) if (placeNumber in 1..3) { Image( painter = painterResource( id = when (placeNumber) { 1 -&gt; org.hyperskill.app.android.R.drawable.ic_leaderboard_first_place 2 -&gt; org.hyperskill.app.android.R.drawable.ic_leaderboard_second_place 3 -&gt; org.hyperskill.app.android.R.drawable.ic_leaderboard_third_place else -&gt; error("Place icon should not be visible for the place number $placeNumber") } ), contentDescription = null, modifier = modifier .requiredSize(24.dp) .align(Alignment.CenterVertically) ) } }</ID>
<ID>ModifierWithoutDefault:BadgeImage.kt$modifier</ID>
<ID>NestedBlockDepth:AuthSocialWebViewClient.kt$AuthSocialWebViewClient$override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? ): Boolean</ID>
<ID>NestedBlockDepth:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun setCodeBlockIsActive(codeBlock: CodeBlock, isActive: Boolean): CodeBlock</ID>
<ID>PreviewPublic:BadgeCard.kt$BadgeCardPreview</ID>
<ID>PreviewPublic:BadgeCard.kt$LastLevelBadgeCardPreview</ID>
<ID>PreviewPublic:BadgeGrid.kt$PhoneBadgeGridPreview</ID>
Expand Down Expand Up @@ -247,6 +252,7 @@
<ID>ReturnCount:SharedDateFormatter.kt$SharedDateFormatter$fun formatTimeDistance(millis: Long): String</ID>
<ID>ReturnCount:StateExtentions.kt$internal fun ChallengeWidgetFeature.State.Content.setCurrentChallengeIntervalProgressAsCompleted(): Challenge?</ID>
<ID>ReturnCount:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleDeleteButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?</ID>
<ID>ReturnCount:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSpaceButtonClicked( state: State ): StepQuizCodeBlanksReducerResult?</ID>
<ID>ReturnCount:StepQuizCodeBlanksReducer.kt$StepQuizCodeBlanksReducer$private fun handleSuggestionClicked( state: State, message: Message.SuggestionClicked ): StepQuizCodeBlanksReducerResult?</ID>
<ID>ReturnCount:StepQuizHintsInteractor.kt$StepQuizHintsInteractor$suspend fun getLastSeenHint(stepId: Long): Comment?</ID>
<ID>ReturnCount:StepQuizHintsInteractor.kt$StepQuizHintsInteractor$suspend fun getNotSeenHintsIds(stepId: Long): List&lt;Long&gt;</ID>
Expand Down
4 changes: 4 additions & 0 deletions iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@
2CE58C5A2B07662300E5EBBE /* ChallengeWidgetContentStateProgressGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE58C592B07662300E5EBBE /* ChallengeWidgetContentStateProgressGridView.swift */; };
2CE58C5C2B0768F300E5EBBE /* ChallengeWidgetContentStateProgressGridItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE58C5B2B0768F300E5EBBE /* ChallengeWidgetContentStateProgressGridItemView.swift */; };
2CE601362B3345DD00E9CC46 /* ColorResource+UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE601352B3345DD00E9CC46 /* ColorResource+UIColor.swift */; };
2CE7AA1B2C7C4255000ABCD7 /* StepQuizCodeBlanksCodeBlockChildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE7AA1A2C7C4255000ABCD7 /* StepQuizCodeBlanksCodeBlockChildView.swift */; };
2CE7B4842AB0593F00DCBE4D /* AttributedTextLabelWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE7B4832AB0593F00DCBE4D /* AttributedTextLabelWrapper.swift */; };
2CE7B4872AB05D0400DCBE4D /* StepQuizParsonsViewDataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE7B4862AB05D0400DCBE4D /* StepQuizParsonsViewDataMapper.swift */; };
2CE7B48A2AB0973D00DCBE4D /* HTMLString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE7B4892AB0973D00DCBE4D /* HTMLString.swift */; };
Expand Down Expand Up @@ -1352,6 +1353,7 @@
2CE58C592B07662300E5EBBE /* ChallengeWidgetContentStateProgressGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeWidgetContentStateProgressGridView.swift; sourceTree = "<group>"; };
2CE58C5B2B0768F300E5EBBE /* ChallengeWidgetContentStateProgressGridItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeWidgetContentStateProgressGridItemView.swift; sourceTree = "<group>"; };
2CE601352B3345DD00E9CC46 /* ColorResource+UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ColorResource+UIColor.swift"; sourceTree = "<group>"; };
2CE7AA1A2C7C4255000ABCD7 /* StepQuizCodeBlanksCodeBlockChildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizCodeBlanksCodeBlockChildView.swift; sourceTree = "<group>"; };
2CE7B4832AB0593F00DCBE4D /* AttributedTextLabelWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedTextLabelWrapper.swift; sourceTree = "<group>"; };
2CE7B4862AB05D0400DCBE4D /* StepQuizParsonsViewDataMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizParsonsViewDataMapper.swift; sourceTree = "<group>"; };
2CE7B4892AB0973D00DCBE4D /* HTMLString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTMLString.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3724,6 +3726,7 @@
children = (
2C008A262C5771350041D8BB /* StepQuizCodeBlanksActionButton.swift */,
2CD67CA02C452B2400240C17 /* StepQuizCodeBlanksBlankView.swift */,
2CE7AA1A2C7C4255000ABCD7 /* StepQuizCodeBlanksCodeBlockChildView.swift */,
2CD67CA22C452DED00240C17 /* StepQuizCodeBlanksOptionView.swift */,
2CB3BC552C46171000F5354F /* StepQuizCodeBlanksPrintInstructionView.swift */,
2C677D012C4A3F860019AF03 /* StepQuizCodeBlanksSuggestionsView.swift */,
Expand Down Expand Up @@ -5579,6 +5582,7 @@
2C99B1002A14255F0018627B /* StudyPlanWidgetViewStateSectionItemStateWrapper.swift in Sources */,
2C9320F52B68F14100999992 /* PaywallContentView.swift in Sources */,
2C8CD9AE2994EFC5008DC09D /* DebugFeatureViewStateKsExtensions.swift in Sources */,
2CE7AA1B2C7C4255000ABCD7 /* StepQuizCodeBlanksCodeBlockChildView.swift in Sources */,
2C83FBC02B177F68007AD7E2 /* LeaderboardListView.swift in Sources */,
2C967432288824370091B6C9 /* StepQuizCodeViewModel.swift in Sources */,
E9A1DA722AD00D41006A9D4B /* FirstProblemOnboardingContentView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extension Block.Options {
files: [Block.OptionsFile]? = nil,
codeBlanksStrings: [String]? = nil,
codeBlanksVariables: [String]? = nil,
codeBlanksOperations: [String]? = nil,
codeBlanksEnabled: Bool? = nil
) {
self.init(
Expand All @@ -25,6 +26,7 @@ extension Block.Options {
files: files,
codeBlanksStrings: codeBlanksStrings,
codeBlanksVariables: codeBlanksVariables,
codeBlanksOperations: codeBlanksOperations,
codeBlanksEnabled: codeBlanksEnabled.flatMap(KotlinBoolean.init(value:))
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ extension StepQuizViewModel: StepQuizCodeBlanksOutputProtocol {
)
)
}

func handleStepQuizCodeBlanksDidTapSpace() {
onNewMessage(
StepQuizFeatureMessageStepQuizCodeBlanksMessage(
message: StepQuizCodeBlanksFeatureMessageSpaceButtonClicked()
)
)
}
}

// MARK: - StepQuizViewModel: StepQuizProblemOnboardingModalViewControllerDelegate -
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ protocol StepQuizCodeBlanksOutputProtocol: AnyObject {
)
func handleStepQuizCodeBlanksDidTapDelete()
func handleStepQuizCodeBlanksDidTapEnter()
func handleStepQuizCodeBlanksDidTapSpace()
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ final class StepQuizCodeBlanksViewModel {
impactFeedbackGenerator.triggerFeedback()
moduleOutput?.handleStepQuizCodeBlanksDidTapEnter()
}

@MainActor
func doSpaceAction() {
impactFeedbackGenerator.triggerFeedback()
moduleOutput?.handleStepQuizCodeBlanksDidTapSpace()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import SwiftUI

extension StepQuizCodeBlanksActionButton {
struct Appearance {
var padding = LayoutInsets(
horizontal: LayoutInsets.smallInset,
vertical: LayoutInsets.smallInset / 2
)

let cornerRadius: CGFloat = 8
}
}

struct StepQuizCodeBlanksActionButton: View {
private(set) var appearance = Appearance()

let imageSystemName: String

let action: () -> Void
Expand All @@ -13,14 +26,13 @@ struct StepQuizCodeBlanksActionButton: View {
label: {
Image(systemName: imageSystemName)
.imageScale(.large)
.padding(.vertical, LayoutInsets.smallInset / 2)
.padding(.horizontal, LayoutInsets.smallInset)
.padding(appearance.padding.edgeInsets)
.background(
Color(ColorPalette.primary)
.conditionalOpacity(isEnabled: isEnabled)
)
.foregroundColor(Color(ColorPalette.onPrimary))
.cornerRadius(8)
.cornerRadius(appearance.cornerRadius)
}
)
.buttonStyle(BounceButtonStyle())
Expand All @@ -35,6 +47,21 @@ extension StepQuizCodeBlanksActionButton {
static func enter(action: @escaping () -> Void) -> StepQuizCodeBlanksActionButton {
StepQuizCodeBlanksActionButton(imageSystemName: "return", action: action)
}

static func space(
action: @escaping () -> Void
) -> StepQuizCodeBlanksActionButton {
StepQuizCodeBlanksActionButton(
appearance: .init(
padding: LayoutInsets(
horizontal: LayoutInsets.smallInset,
vertical: 10.5
)
),
imageSystemName: "space",
action: action
)
}
}

#if DEBUG
Expand All @@ -43,11 +70,13 @@ extension StepQuizCodeBlanksActionButton {
HStack {
StepQuizCodeBlanksActionButton.delete(action: {})
StepQuizCodeBlanksActionButton.enter(action: {})
StepQuizCodeBlanksActionButton.space(action: {})
}

HStack {
StepQuizCodeBlanksActionButton.delete(action: {})
StepQuizCodeBlanksActionButton.enter(action: {})
StepQuizCodeBlanksActionButton.space(action: {})
}
.disabled(true)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import shared
import SwiftUI

struct StepQuizCodeBlanksCodeBlockChildView: View {
let child: StepQuizCodeBlanksViewStateCodeBlockChildItem

let action: (StepQuizCodeBlanksViewStateCodeBlockChildItem) -> Void

var body: some View {
childView(child: child)
.onTapGesture {
action(child)
}
}

@ViewBuilder
private func childView(
child: StepQuizCodeBlanksViewStateCodeBlockChildItem
) -> some View {
if let value = child.value {
StepQuizCodeBlanksOptionView(text: value, isActive: child.isActive)
} else {
StepQuizCodeBlanksBlankView(style: .small, isActive: child.isActive)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import shared
import SwiftUI

struct StepQuizCodeBlanksPrintInstructionView: View {
let isActive: Bool
let printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint

let output: String?
let onChildTap: (StepQuizCodeBlanksViewStateCodeBlockChildItem) -> Void

var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
Expand All @@ -12,10 +13,8 @@ struct StepQuizCodeBlanksPrintInstructionView: View {
.font(StepQuizCodeBlanksAppearance.blankFont)
.foregroundColor(StepQuizCodeBlanksAppearance.blankTextColor)

if let output, !output.isEmpty {
StepQuizCodeBlanksOptionView(text: output, isActive: isActive)
} else {
StepQuizCodeBlanksBlankView(style: .small, isActive: isActive)
ForEach(printItem.children, id: \.id) { child in
StepQuizCodeBlanksCodeBlockChildView(child: child, action: onChildTap)
}

Text(")")
Expand All @@ -25,9 +24,7 @@ struct StepQuizCodeBlanksPrintInstructionView: View {
.padding(.horizontal, LayoutInsets.defaultInset)
.padding(.vertical, LayoutInsets.smallInset)
.background(Color(ColorPalette.violet400Alpha7))
.cornerRadius(8)
.animation(.default, value: isActive)
.animation(.default, value: output)
.cornerRadius(StepQuizCodeBlanksAppearance.cornerRadius)
.padding(.horizontal)
}
.scrollBounceBehaviorBasedOnSize(axes: .horizontal)
Expand All @@ -37,10 +34,45 @@ struct StepQuizCodeBlanksPrintInstructionView: View {
#if DEBUG
#Preview {
VStack {
StepQuizCodeBlanksPrintInstructionView(isActive: false, output: "")
StepQuizCodeBlanksPrintInstructionView(isActive: true, output: "")
StepQuizCodeBlanksPrintInstructionView(isActive: true, output: "There is a cat on the keyboard, it is true")
StepQuizCodeBlanksPrintInstructionView(isActive: false, output: "There is a cat on the keyboard, it is true")
StepQuizCodeBlanksPrintInstructionView(
printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint(
id: 0,
children: [.init(id: 0, isActive: false, value: "")]
),
onChildTap: { _ in }
)
StepQuizCodeBlanksPrintInstructionView(
printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint(
id: 0,
children: [.init(id: 0, isActive: true, value: "")]
),
onChildTap: { _ in }
)
StepQuizCodeBlanksPrintInstructionView(
printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint(
id: 0,
children: [.init(id: 0, isActive: true, value: "There is a cat on the keyboard, it is true")]
),
onChildTap: { _ in }
)
StepQuizCodeBlanksPrintInstructionView(
printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint(
id: 0,
children: [.init(id: 0, isActive: false, value: "There is a cat on the keyboard, it is true")]
),
onChildTap: { _ in }
)

StepQuizCodeBlanksPrintInstructionView(
printItem: StepQuizCodeBlanksViewStateCodeBlockItemPrint(
id: 0,
children: [
.init(id: 0, isActive: false, value: "x"),
.init(id: 1, isActive: true, value: "")
]
),
onChildTap: { _ in }
)
}
.frame(maxWidth: .infinity)
.padding()
Expand Down
Loading

0 comments on commit b53ba7d

Please sign in to comment.