-
Notifications
You must be signed in to change notification settings - Fork 34
Achievements #303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Achievements #303
Changes from 16 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
030f6b8
Add assets & gradient extension
kvld be37415
Add achievements block to profile
kvld 823849d
Add badges to achievements block
kvld e95b20a
Entity & API classes
kvld 7f9fbbe
Add AchievementsRetriever
kvld 20d274b
Working achievements in profile
kvld 6f74184
Badge for locked achievement
kvld 7c90d1c
Working achievements list
kvld ed8cd12
Add gradient & fix layout bugs
kvld ed056ae
Fix padding
kvld c158f01
Add skeleton view
kvld 3aa4311
Add profile placeholders
kvld d612057
Add L10n
kvld ab3f61e
Merge branch 'dev' into feature/achievements
kvld 9874e34
Update vector images
kvld 000aa9d
Merge branch 'dev' into feature/achievements
Ostrenkiy 3bca862
Achievements list
kvld 49439a5
Add popup
kvld 2ae3d95
Merge branch 'feature/achievements' of https://github.com/StepicOrg/s…
kvld 13822a5
Use dynamic layout
kvld 1701f91
Add banner view
kvld cb9f1c1
Fix banner
kvld 88c3a4e
Open achievements in profile
kvld 62c8cbc
Fix achievements order
kvld 0c04f89
Remove frame log
kvld 30876ca
Add sharing
kvld 24245bc
Fix share text
kvld 3d09703
Extract all progresses and all achievements loading
kvld 33fef9c
Add skeletons
kvld 07b6756
Add refresh after connection error
kvld ae041c7
Fix popup
kvld 549e396
Merge branch 'dev' into feature/achievements
kvld File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // | ||
| // Achievement.swift | ||
| // Stepic | ||
| // | ||
| // Created by Vladislav Kiryukhin on 06.06.2018. | ||
| // Copyright © 2018 Alex Karpov. All rights reserved. | ||
| // | ||
| import SwiftyJSON | ||
|
|
||
| class Achievement: JSONSerializable { | ||
| var id: Int | ||
| var kind: String | ||
| var iconImageUrl: String | ||
| var targetScore: Int | ||
|
|
||
| required init(json: JSON) { | ||
| self.id = json["id"].intValue | ||
| self.kind = json["kind"].stringValue | ||
| self.iconImageUrl = json["icon"].stringValue | ||
| self.targetScore = json["target_score"].intValue | ||
| } | ||
|
|
||
| func update(json: JSON) { | ||
| self.id = json["id"].intValue | ||
| self.kind = json["kind"].stringValue | ||
| self.iconImageUrl = json["icon"].stringValue | ||
| self.targetScore = json["target_score"].intValue | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| // | ||
| // AchievementBadgeView.swift | ||
| // Stepic | ||
| // | ||
| // Created by Vladislav Kiryukhin on 04.06.2018. | ||
| // Copyright © 2018 Vladislav Kiryukhin. All rights reserved. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| struct AchievementBadgeViewData { | ||
| static var empty: AchievementBadgeViewData { | ||
| return AchievementBadgeViewData(completedLevel: 0, maxLevel: 0, stageProgress: 0.0, badge: #imageLiteral(resourceName: "achievement-0")) | ||
| } | ||
|
|
||
| let completedLevel: Int | ||
| let maxLevel: Int | ||
| let stageProgress: Float | ||
| let badge: UIImage | ||
| } | ||
|
|
||
| class AchievementBadgeView: UIView { | ||
| // Gradient colors and locations for progress circle | ||
| private static let colors = [ | ||
| UIColor(hex: 0xa9aeff), | ||
| UIColor(hex: 0xa99cff), | ||
| UIColor(hex: 0xa992ff), | ||
| UIColor(hex: 0xaca5ff), | ||
| UIColor(hex: 0xacecfe) | ||
| ] | ||
| private static let locations = [0.0, 0.14, 0.25, 0.425, 1.0] | ||
|
|
||
| private static let relativeBadgeHeight: CGFloat = 0.83 | ||
| private static let relativeStarsHeight: CGFloat = 0.09 | ||
| private static let relativeProgressWidth: CGFloat = 0.022 | ||
| private static let relativeBadgeImagePadding: CGFloat = 0.03 | ||
|
|
||
| @IBOutlet weak var paddingConstraint: NSLayoutConstraint! | ||
| @IBOutlet weak var circleViewHeightConstraint: NSLayoutConstraint! | ||
| @IBOutlet weak var starsStackViewHeightConstraint: NSLayoutConstraint! | ||
| @IBOutlet weak var badgeImageViewHeightConstraint: NSLayoutConstraint! | ||
| @IBOutlet weak var starsStackView: UIStackView! | ||
| @IBOutlet weak var circleView: UIView! | ||
| @IBOutlet weak var badgeImageView: UIImageView! | ||
|
|
||
| var data: AchievementBadgeViewData? { | ||
| didSet { | ||
| updateProgress() | ||
| } | ||
| } | ||
|
|
||
| var circleViewGradientLayer: CAGradientLayer? | ||
| var circleProgressLayer: CAShapeLayer? | ||
| private var previousBadgeFrame: CGRect? | ||
|
|
||
| override func awakeFromNib() { | ||
| super.awakeFromNib() | ||
|
|
||
| clipsToBounds = true | ||
|
|
||
| addGradient() | ||
| } | ||
|
|
||
| private func addGradient() { | ||
| circleViewGradientLayer = CAGradientLayer(colors: AchievementBadgeView.colors, locations: AchievementBadgeView.locations, rotationAngle: 130.0) | ||
|
|
||
| guard let circleViewGradientLayer = circleViewGradientLayer else { | ||
| return | ||
| } | ||
|
|
||
| circleViewGradientLayer.opacity = 0.25 | ||
| circleView.layer.insertSublayer(circleViewGradientLayer, at: 0) | ||
| } | ||
|
|
||
| private func initViews() { | ||
| // Auto-resize: we calculate subviews sizes based on view height | ||
| let height = self.frame.height | ||
| let relativePaddingHeight = 1.0 - AchievementBadgeView.relativeBadgeHeight - AchievementBadgeView.relativeStarsHeight | ||
| let badgeHeight = AchievementBadgeView.relativeBadgeHeight * height | ||
| paddingConstraint.constant = relativePaddingHeight * height | ||
| circleViewHeightConstraint.constant = badgeHeight | ||
| starsStackViewHeightConstraint.constant = AchievementBadgeView.relativeStarsHeight * height | ||
| badgeImageViewHeightConstraint.constant = -2.0 * AchievementBadgeView.relativeBadgeImagePadding * badgeHeight | ||
| layoutIfNeeded() | ||
|
|
||
| let progressWidth = height * AchievementBadgeView.relativeProgressWidth | ||
| let innerCircleRadius = badgeHeight * 0.5 | ||
|
|
||
| // Draw gradient circle | ||
| let gradientCircleLayer = CAShapeLayer() | ||
| gradientCircleLayer.lineWidth = progressWidth | ||
| let bezierPath = UIBezierPath() | ||
|
|
||
| bezierPath.addArc(withCenter: CGPoint(x: circleView.bounds.midX, y: circleView.bounds.midY), radius: innerCircleRadius - progressWidth, startAngle: 0, endAngle: 2 * .pi, clockwise: false) | ||
| gradientCircleLayer.path = bezierPath.cgPath | ||
| gradientCircleLayer.fillColor = nil | ||
| gradientCircleLayer.strokeColor = UIColor.black.cgColor | ||
|
|
||
| circleViewGradientLayer?.mask = gradientCircleLayer | ||
| } | ||
|
|
||
| private func initStageProgress(value: Float) { | ||
| let stageProgress = max(0.0, min(value, 1.0)) | ||
|
|
||
| let height = self.frame.height | ||
| let badgeHeight = AchievementBadgeView.relativeBadgeHeight * height | ||
| let progressWidth = height * AchievementBadgeView.relativeProgressWidth | ||
|
|
||
| let innerCircleRadius = badgeHeight * 0.5 | ||
| let progress = CGFloat(stageProgress) * 2.0 * .pi | ||
|
|
||
| let circlePath = UIBezierPath() | ||
| circlePath.addArc(withCenter: CGPoint(x: circleView.bounds.midX, y: circleView.bounds.midY), radius: innerCircleRadius - progressWidth, startAngle: .pi / 2, endAngle: .pi / 2 + progress, clockwise: true) | ||
|
|
||
| circleProgressLayer?.removeFromSuperlayer() | ||
| circleProgressLayer = CAShapeLayer() | ||
|
|
||
| guard let circleProgressLayer = circleProgressLayer else { | ||
| return | ||
| } | ||
|
|
||
| circleProgressLayer.path = circlePath.cgPath | ||
| circleProgressLayer.fillColor = nil | ||
| circleProgressLayer.strokeColor = UIColor.stepicGreen.cgColor | ||
| circleProgressLayer.lineWidth = progressWidth | ||
|
|
||
| circleView.layer.addSublayer(circleProgressLayer) | ||
| } | ||
|
|
||
| private func initLevelProgress(completedLevel: Int, maxLevel: Int) { | ||
| let completedLevel = max(min(maxLevel, completedLevel), 0) | ||
|
|
||
| for v in starsStackView.arrangedSubviews { | ||
| starsStackView.removeArrangedSubview(v) | ||
| v.removeFromSuperview() | ||
| } | ||
|
|
||
| if completedLevel != 0 { | ||
| // Remove previous width constraint (cause it based on maxLevel) | ||
| for c in starsStackView.constraints { | ||
| if c.firstAttribute == .width { | ||
| starsStackView.removeConstraint(c) | ||
| } | ||
| } | ||
|
|
||
| let filledCount = completedLevel | ||
| let borderedCount = completedLevel == maxLevel ? 0 : 1 | ||
| let grayCount = maxLevel - filledCount - borderedCount | ||
|
|
||
| let spaceBetweenStars = starsStackViewHeightConstraint.constant * 0.3 | ||
| starsStackView.spacing = spaceBetweenStars | ||
|
|
||
| NSLayoutConstraint(item: starsStackView, attribute: .width, relatedBy: .equal, toItem: starsStackView, attribute: .height, multiplier: CGFloat(maxLevel), constant: CGFloat(maxLevel - 1) * spaceBetweenStars).isActive = true | ||
|
|
||
| for _ in 0..<filledCount { | ||
| starsStackView.addArrangedSubview(UIImageView(image: #imageLiteral(resourceName: "star-filled"))) | ||
| } | ||
|
|
||
| for _ in 0..<borderedCount { | ||
| starsStackView.addArrangedSubview(UIImageView(image: #imageLiteral(resourceName: "star-bordered"))) | ||
| } | ||
|
|
||
| for _ in 0..<grayCount { | ||
| starsStackView.addArrangedSubview(UIImageView(image: #imageLiteral(resourceName: "star-gray"))) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private func updateProgress() { | ||
| if let data = data { | ||
| if data.completedLevel == 0 { | ||
| circleViewGradientLayer?.isHidden = true | ||
| circleProgressLayer?.isHidden = true | ||
| } else { | ||
| circleViewGradientLayer?.isHidden = false | ||
| circleProgressLayer?.isHidden = false | ||
|
|
||
| initStageProgress(value: data.stageProgress) | ||
| } | ||
|
|
||
| badgeImageView.image = data.badge | ||
| initLevelProgress(completedLevel: data.completedLevel, maxLevel: data.maxLevel) | ||
| } | ||
| } | ||
|
|
||
| override func layoutSubviews() { | ||
| super.layoutSubviews() | ||
|
|
||
| if previousBadgeFrame != self.bounds { | ||
| if self.bounds.width != self.bounds.height { | ||
| print("achievement badge view: target size is not square, content would be clipped!") | ||
| } | ||
|
|
||
| previousBadgeFrame = self.bounds | ||
|
|
||
| circleViewGradientLayer?.frame = self.bounds | ||
| initViews() | ||
|
|
||
| updateProgress() | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> | ||
| <device id="retina4_7" orientation="portrait"> | ||
| <adaptation id="fullscreen"/> | ||
| </device> | ||
| <dependencies> | ||
| <deployment identifier="iOS"/> | ||
| <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/> | ||
| <capability name="Aspect ratio constraints" minToolsVersion="5.1"/> | ||
| <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | ||
| </dependencies> | ||
| <objects> | ||
| <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> | ||
| <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | ||
| <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="AchievementBadgeView" customModule="Stepic" customModuleProvider="target"> | ||
| <rect key="frame" x="0.0" y="0.0" width="226" height="204"/> | ||
| <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||
| <subviews> | ||
| <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="itK-AC-ShO"> | ||
| <rect key="frame" x="113" y="0.0" width="0.0" height="0.0"/> | ||
| <subviews> | ||
| <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="N3E-L0-3JB"> | ||
| <constraints> | ||
| <constraint firstAttribute="width" secondItem="N3E-L0-3JB" secondAttribute="height" multiplier="1:1" id="PUy-Ig-lLA"/> | ||
| </constraints> | ||
| </imageView> | ||
| </subviews> | ||
| <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | ||
| <constraints> | ||
| <constraint firstAttribute="width" secondItem="itK-AC-ShO" secondAttribute="height" multiplier="1:1" id="OYZ-dz-hem"/> | ||
| <constraint firstItem="N3E-L0-3JB" firstAttribute="width" secondItem="itK-AC-ShO" secondAttribute="width" id="OkG-4d-VcY"/> | ||
| <constraint firstItem="N3E-L0-3JB" firstAttribute="centerX" secondItem="itK-AC-ShO" secondAttribute="centerX" id="pW9-Pa-CL1"/> | ||
| <constraint firstItem="N3E-L0-3JB" firstAttribute="centerY" secondItem="itK-AC-ShO" secondAttribute="centerY" id="soe-fx-Xij"/> | ||
| <constraint firstAttribute="height" id="xPy-eG-dsZ"/> | ||
| </constraints> | ||
| </view> | ||
| <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="sQW-MV-Bkj"> | ||
| <rect key="frame" x="112.5" y="23" width="1" height="0.0"/> | ||
| <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | ||
| <constraints> | ||
| <constraint firstAttribute="height" id="Fnu-Nx-gyG"/> | ||
| <constraint firstAttribute="width" constant="1" id="lZz-FH-VZf"/> | ||
| </constraints> | ||
| </stackView> | ||
| </subviews> | ||
| <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | ||
| <constraints> | ||
| <constraint firstItem="sQW-MV-Bkj" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="iN0-l3-epB" secondAttribute="leading" priority="999" constant="8" id="KZN-x7-poH"/> | ||
| <constraint firstItem="sQW-MV-Bkj" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="RyI-I3-CHB"/> | ||
| <constraint firstItem="sQW-MV-Bkj" firstAttribute="top" secondItem="itK-AC-ShO" secondAttribute="bottom" constant="23" id="ccL-fa-bxp"/> | ||
| <constraint firstItem="itK-AC-ShO" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="mIP-O0-Skb"/> | ||
| <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="sQW-MV-Bkj" secondAttribute="trailing" priority="999" constant="8" id="n0L-ZK-0XO"/> | ||
| <constraint firstItem="itK-AC-ShO" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="xb4-dr-GbO"/> | ||
| </constraints> | ||
| <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> | ||
| <connections> | ||
| <outlet property="badgeImageView" destination="N3E-L0-3JB" id="Ngu-uE-X4h"/> | ||
| <outlet property="badgeImageViewHeightConstraint" destination="OkG-4d-VcY" id="3F7-xG-RRh"/> | ||
| <outlet property="circleView" destination="itK-AC-ShO" id="4ef-ZV-gpZ"/> | ||
| <outlet property="circleViewHeightConstraint" destination="xPy-eG-dsZ" id="Knt-6L-Iq1"/> | ||
| <outlet property="paddingConstraint" destination="ccL-fa-bxp" id="Z7D-jH-hJv"/> | ||
| <outlet property="starsStackView" destination="sQW-MV-Bkj" id="Fqv-ex-OsY"/> | ||
| <outlet property="starsStackViewHeightConstraint" destination="Fnu-Nx-gyG" id="uob-7F-1mQ"/> | ||
| </connections> | ||
| <point key="canvasLocation" x="99" y="-180"/> | ||
| </view> | ||
| </objects> | ||
| </document> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // | ||
| // AchievementDescription.swift | ||
| // Stepic | ||
| // | ||
| // Created by Vladislav Kiryukhin on 12.06.2018. | ||
| // Copyright © 2018 Alex Karpov. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| enum AchievementKind: String { | ||
| // Cases should be declared in correct order | ||
| case stepsSolved = "steps_solved" | ||
| case stepsSolvedStreak = "steps_solved_streak" | ||
| case stepsSolvedChoice = "steps_solved_choice" | ||
| case stepsSolvedCode = "steps_solved_code" | ||
| case stepsSolvedNumber = "steps_solved_number" | ||
| case codeQuizzesSolvedPython = "code_quizzes_solved_python" | ||
| case codeQuizzesSolvedCPP = "code_quizzes_solved_cpp" | ||
| case codeQuizzesSolvedJava = "code_quizzes_solved_java" | ||
| case activeDaysStreak = "active_days_streak" | ||
| case certificatesRegularCount = "certificates_regular_count" | ||
| case certificatesDistinctionCount = "certificates_distinction_count" | ||
| case courseReviewsCount = "course_reviews_count" | ||
|
|
||
| func getBadge(for level: Int) -> UIImage? { | ||
| return UIImage(named: "achievement-\(self.hashValue + 1)-\(level)") | ||
| } | ||
|
|
||
| func getName() -> String { | ||
| switch self { | ||
| case .stepsSolved: | ||
| return NSLocalizedString("AchievementsStepsSolvedKindTitle", comment: "") | ||
| case .stepsSolvedChoice: | ||
| return NSLocalizedString("AchievementsStepsSolvedChoiceKindTitle", comment: "") | ||
| case .stepsSolvedCode: | ||
| return NSLocalizedString("AchievementsStepsSolvedCodeKindTitle", comment: "") | ||
| case .stepsSolvedNumber: | ||
| return NSLocalizedString("AchievementsStepsSolvedNumberKindTitle", comment: "") | ||
| case .codeQuizzesSolvedPython: | ||
| return NSLocalizedString("AchievementsCodeQuizzesSolvedPythonKindTitle", comment: "") | ||
| case .codeQuizzesSolvedJava: | ||
| return NSLocalizedString("AchievementsCodeQuizzesSolvedJavaKindTitle", comment: "") | ||
| case .codeQuizzesSolvedCPP: | ||
| return NSLocalizedString("AchievementsCodeQuizzesSolvedCppKindTitle", comment: "") | ||
| case .certificatesRegularCount: | ||
| return NSLocalizedString("AchievementsCertificatesRegularCountKindTitle", comment: "") | ||
| case .certificatesDistinctionCount: | ||
| return NSLocalizedString("AchievementsCertificatesDistinctionCountKindTitle", comment: "") | ||
| case .courseReviewsCount: | ||
| return NSLocalizedString("AchievementsCourseReviewsCountKindTitle", comment: "") | ||
| case .stepsSolvedStreak: | ||
| return NSLocalizedString("AchievementsStepsSolvedStreakKindTitle", comment: "") | ||
| case .activeDaysStreak: | ||
| return NSLocalizedString("AchievementsActiveDaysStreakKindTitle", comment: "") | ||
| } | ||
| } | ||
|
|
||
| func getDescription(for score: Int) -> String { | ||
| switch self { | ||
| case .stepsSolved: | ||
| return String(format: NSLocalizedString("AchievementsStepsSolvedKindDescription", comment: ""), "\(score)") | ||
| case .stepsSolvedChoice: | ||
| return String(format: NSLocalizedString("AchievementsStepsSolvedChoiceKindDescription", comment: ""), "\(score)") | ||
| case .stepsSolvedCode: | ||
| return String(format: NSLocalizedString("AchievementsStepsSolvedCodeKindDescription", comment: ""), "\(score)") | ||
| case .stepsSolvedNumber: | ||
| return String(format: NSLocalizedString("AchievementsStepsSolvedNumberKindDescription", comment: ""), "\(score)") | ||
| case .codeQuizzesSolvedPython: | ||
| return String(format: NSLocalizedString("AchievementsCodeQuizzesSolvedPythonKindDescription", comment: ""), "\(score)") | ||
| case .codeQuizzesSolvedJava: | ||
| return String(format: NSLocalizedString("AchievementsCodeQuizzesSolvedJavaKindDescription", comment: ""), "\(score)") | ||
| case .codeQuizzesSolvedCPP: | ||
| return String(format: NSLocalizedString("AchievementsCodeQuizzesSolvedCppKindDescription", comment: ""), "\(score)") | ||
| case .certificatesRegularCount: | ||
| return String(format: NSLocalizedString("AchievementsCertificatesRegularCountKindDescription", comment: ""), "\(score)") | ||
| case .certificatesDistinctionCount: | ||
| return String(format: NSLocalizedString("AchievementsCertificatesDistinctionCountKindDescription", comment: ""), "\(score)") | ||
| case .courseReviewsCount: | ||
| return String(format: NSLocalizedString("AchievementsCourseReviewsCountKindDescription", comment: ""), "\(score)") | ||
| case .stepsSolvedStreak: | ||
| return String(format: NSLocalizedString("AchievementsStepsSolvedStreakKindDescription", comment: ""), "\(score)") | ||
| case .activeDaysStreak: | ||
| return String(format: NSLocalizedString("AchievementsActiveDaysStreakKindDescription", comment: ""), "\(score)") | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А что от этого зависит сейчас?