Skip to content

9 app store button in the repository #18

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 3 commits into from
Jun 4, 2024
Merged
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
22 changes: 21 additions & 1 deletion CloudMaster.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
8D26A31C2C0EA9C100E9B015 /* QuestionNavbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D26A31B2C0EA9C100E9B015 /* QuestionNavbar.swift */; };
8D8D8A862C05A23600ACC61C /* CloudMasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8D8A852C05A23600ACC61C /* CloudMasterTests.swift */; };
8D8D8A902C05A23600ACC61C /* CloudMasterUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8D8A8F2C05A23600ACC61C /* CloudMasterUITests.swift */; };
8D8D8A922C05A23600ACC61C /* CloudMasterUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8D8A912C05A23600ACC61C /* CloudMasterUITestsLaunchTests.swift */; };
Expand Down Expand Up @@ -61,6 +62,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
8D26A31B2C0EA9C100E9B015 /* QuestionNavbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionNavbar.swift; sourceTree = "<group>"; };
8D8D8A712C05A23400ACC61C /* CloudMaster Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CloudMaster Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; };
8D8D8A812C05A23600ACC61C /* CloudMasterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CloudMasterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8D8D8A852C05A23600ACC61C /* CloudMasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudMasterTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -125,6 +127,23 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
8D26A3192C0EA9A400E9B015 /* Components */ = {
isa = PBXGroup;
children = (
8D8D8A9F2C05A27800ACC61C /* ConfirmPopup.swift */,
8D26A31B2C0EA9C100E9B015 /* QuestionNavbar.swift */,
);
path = Components;
sourceTree = "<group>";
};
8D26A31A2C0EA9B300E9B015 /* Shared */ = {
isa = PBXGroup;
children = (
8D26A3192C0EA9A400E9B015 /* Components */,
);
path = Shared;
sourceTree = "<group>";
};
8D8D8A682C05A23400ACC61C = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -183,7 +202,6 @@
isa = PBXGroup;
children = (
8DABB7722C0D7CF900B40E25 /* ViewModels */,
8D8D8A9F2C05A27800ACC61C /* ConfirmPopup.swift */,
8D8D8AA02C05A27800ACC61C /* DownloadOverlayView.swift */,
8D8D8AA12C05A27800ACC61C /* NotificationSettingsView.swift */,
);
Expand Down Expand Up @@ -342,6 +360,7 @@
8D8D8AC32C05A27800ACC61C /* Features */ = {
isa = PBXGroup;
children = (
8D26A31A2C0EA9B300E9B015 /* Shared */,
8D8D8AA22C05A27800ACC61C /* Common */,
8D8D8AA62C05A27800ACC61C /* Course */,
8D8D8AA92C05A27800ACC61C /* Courses */,
Expand Down Expand Up @@ -574,6 +593,7 @@
8D8D8AD92C05A27800ACC61C /* HomeView.swift in Sources */,
8D8D8AD42C05A27800ACC61C /* ExamModesView.swift in Sources */,
8D8D8AE12C05A27800ACC61C /* Courses.swift in Sources */,
8D26A31C2C0EA9C100E9B015 /* QuestionNavbar.swift in Sources */,
8D8D8AD12C05A27800ACC61C /* CourseView.swift in Sources */,
8DABB7742C0D7D0300B40E25 /* DownloadViewModel.swift in Sources */,
);
Expand Down
12 changes: 12 additions & 0 deletions CloudMaster/Assets.xcassets/githubIcon.symbolset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"symbols" : [
{
"filename" : "githubIcon.svg",
"idiom" : "universal"
}
]
}
167 changes: 167 additions & 0 deletions CloudMaster/Assets.xcassets/githubIcon.symbolset/githubIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions CloudMaster/CloudMaster.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ struct CloudMaster: App {
HomeView(favorites: $favorites)
} else {
IntroView(favorites: $favorites, isAppConfigured: $isFirstStart)
.onAppear {
UserDefaults.standard.set(true, forKey: "isFirstStart")
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions CloudMaster/Features/Common/DownloadOverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct DownloadOverlayView: View {
var body: some View {
if isShowing {
ZStack {
Color.black.opacity(0.4)
Color.black.opacity(0.8)
.edgesIgnoringSafeArea(.all)

VStack {
Expand Down Expand Up @@ -61,7 +61,7 @@ struct CircularProgressView: View {
withAnimation(.spring()) {
Image(systemName: "checkmark.circle.fill")
.resizable()
.foregroundColor(Color.green)
.foregroundColor(Color.correct)
.frame(width: 50, height: 50)
}
}
Expand Down
3 changes: 1 addition & 2 deletions CloudMaster/Features/Course/Views/CourseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct CourseView: View {
.padding()
.font(.subheadline)

Link("Sources", destination: URL(string: course.url)!)
Link("Sources", destination: URL(string: course.repositoryURL)!)
.padding()
.font(.subheadline)
}
Expand Down Expand Up @@ -132,7 +132,6 @@ struct CourseView: View {
}
}) {
Image(systemName: notificationsEnabled ? "bell.fill" : "bell")
.foregroundColor(notificationsEnabled ? Color.correct : .gray)
}
}

Expand Down
3 changes: 2 additions & 1 deletion CloudMaster/Features/Courses/Views/CoursesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ struct CoursesView: View {
viewModel.downloadCourses(favorites)
}) {
Image(systemName: "arrow.down.circle")
.foregroundColor(viewModel.isDownloading ? .gray : .accentColor) // Change color based on state (optional)
}
.disabled(viewModel.isDownloading)
}
}

24 changes: 17 additions & 7 deletions CloudMaster/Features/Exam/Views/ExamSummaryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ struct ExamSummaryView: View {
@State private var showDeleteConfirmation = false

@ObservedObject var examDataStore = UserExamDataStore.shared

let exam: UserExamData

// Helper variable to hide backbutton after Exam
let afterExam: Bool

@Environment(\.presentationMode) var presentationMode

var body: some View {
VStack {
Text(exam.isPassed ? "Passed" : "Failed")
Expand Down Expand Up @@ -79,20 +85,24 @@ struct ExamSummaryView: View {
}
.padding()
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(afterExam) // Hide back button based on the flag
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
Spacer()
Button(action: {
showDeleteConfirmation = true
}) {
Image(systemName: "trash")
if (!afterExam){
ToolbarItem(placement: .principal) {
HStack {
Spacer()
Button(action: {
showDeleteConfirmation = true
}) {
Image(systemName: "trash")
}
}
}
}
}
.confirmPopup(isPresented: $showDeleteConfirmation, title: "Delete Exam", message: "Are you sure you want to delete this exam?", confirmAction: {
examDataStore.deleteExam(withId: exam.id)
presentationMode.wrappedValue.dismiss() // Dismiss the view after deletion
})
}

Expand Down
120 changes: 63 additions & 57 deletions CloudMaster/Features/Exam/Views/ExamView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ struct ExamView: View {
@State private var currentQuestionIndex = 0
@State private var selectedChoices: [UUID: Set<UUID>] = [:]
@State private var timeRemaining: Int
@State private var showSummary = false
@State private var examFinished = false
@State private var startTime: Date = Date()
@State private var lastExamData: UserExamData? = nil
@State private var navigateToSummary = false

let questionCount: Int
let timeLimit: Int
Expand All @@ -25,56 +26,56 @@ struct ExamView: View {
}

var body: some View {
VStack {
if !questionLoader.questions.isEmpty {
let questions = Array(questionLoader.questions.prefix(questionCount))
if currentQuestionIndex < questions.count {
HStack {
Spacer()
NavigationStack {
VStack {
if !questionLoader.questions.isEmpty {
let questions = Array(questionLoader.questions.prefix(questionCount))
if currentQuestionIndex < questions.count {
HStack {
Spacer()
Text("\(currentQuestionIndex + 1) of \(questionCount)")
.font(.subheadline)
.foregroundColor(.secondary)
HStack {
Spacer()
Text("\(currentQuestionIndex + 1) of \(questionCount)")
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
}
Spacer()
}
Spacer()
}
.padding(.horizontal)

ExamQuestion(
question: questions[currentQuestionIndex],
selectedChoices: selectedChoices[questions[currentQuestionIndex].id] ?? [],
isMultipleResponse: questions[currentQuestionIndex].multipleResponse,
onChoiceSelected: { choiceId in
if questions[currentQuestionIndex].multipleResponse {
if selectedChoices[questions[currentQuestionIndex].id]?.contains(choiceId) == true {
selectedChoices[questions[currentQuestionIndex].id]?.remove(choiceId)
.padding(.horizontal)

ExamQuestion(
question: questions[currentQuestionIndex],
selectedChoices: selectedChoices[questions[currentQuestionIndex].id] ?? [],
isMultipleResponse: questions[currentQuestionIndex].multipleResponse,
onChoiceSelected: { choiceId in
if questions[currentQuestionIndex].multipleResponse {
if selectedChoices[questions[currentQuestionIndex].id]?.contains(choiceId) == true {
selectedChoices[questions[currentQuestionIndex].id]?.remove(choiceId)
} else {
selectedChoices[questions[currentQuestionIndex].id, default: []].insert(choiceId)
}
} else {
selectedChoices[questions[currentQuestionIndex].id, default: []].insert(choiceId)
selectedChoices[questions[currentQuestionIndex].id] = [choiceId]
}
}
)
Button(action: {
if currentQuestionIndex < questions.count - 1 {
currentQuestionIndex += 1
} else {
selectedChoices[questions[currentQuestionIndex].id] = [choiceId]
storeExamData(questions: questions)
navigateToSummary = true
}
}) {
Text(currentQuestionIndex < questions.count - 1 ? "Next Question" : "Show Exam Result")
.padding()
.frame(maxWidth: .infinity)
.background(Color.customSecondary)
.foregroundColor(.white)
.cornerRadius(10)
}
)

Button(action: {
if currentQuestionIndex < questions.count - 1 {
currentQuestionIndex += 1
} else {
storeExamData(questions: questions)
showSummary = true
}
}) {
Text(currentQuestionIndex < questions.count - 1 ? "Next Question" : "Show Exam Result")
.padding()
.frame(maxWidth: .infinity)
.background(Color.customSecondary)
.foregroundColor(.white)
.cornerRadius(10)
}
.padding(.horizontal, 20)

Spacer()

Expand All @@ -85,23 +86,21 @@ struct ExamView: View {
}
.padding()
} else {
Text("Loading questions...")
Text("No que")
}
}
.navigationDestination(isPresented: $navigateToSummary) {
if let examData = lastExamData {
ExamSummaryView(exam: examData, afterExam: true)
}
} else {
Text("Loading questions...")
}
}
.onAppear(perform: startTimer)
.onDisappear {
if !showSummary {
if !examFinished {
endExamIfNeeded()
}
}
.sheet(isPresented: $showSummary) {
if let examData = lastExamData {
ExamSummaryView(exam: examData)
}
}
}

func startTimer() {
Expand All @@ -112,7 +111,7 @@ struct ExamView: View {
} else {
timer.invalidate()
storeExamData(questions: Array(questionLoader.questions.prefix(questionCount)))
showSummary = true
navigateToSummary = true
}
}
}
Expand Down Expand Up @@ -148,13 +147,14 @@ struct ExamView: View {

UserExamDataStore.shared.saveExamData(examData)
lastExamData = examData
examFinished = true
}

private func endExamIfNeeded() {
if timeRemaining > 0 {
timeRemaining = 0 // End the exam immediately
storeExamData(questions: Array(questionLoader.questions.prefix(questionCount)))
showSummary = true
navigateToSummary = true
}
}

Expand All @@ -180,8 +180,8 @@ struct ExamQuestion: View {
.lineLimit(nil) // Allow text to wrap as needed
.fixedSize(horizontal: false, vertical: true)
.padding(.horizontal)
.frame(alignment: .leading)
.multilineTextAlignment(.center)
.multilineTextAlignment(.leading) // Justify the text
.lineSpacing(2)

if let imagePath = question.imagePath,
let image = loadImage(from: imagePath) {
Expand Down Expand Up @@ -223,9 +223,15 @@ struct ExamQuestion: View {
}

private func adjustedFontSize(for text: String) -> CGFloat {
_ = UIScreen.main.bounds.width - 32 // Adjust for desired padding
let fontSize = max(min(text.count / 80, 24), 14) // Simplified dynamic font sizing
return CGFloat(fontSize)
let maxWidth = UIScreen.main.bounds.width - 32
let baseFontSize: CGFloat = 24
let minFontSize: CGFloat = 14

// Scale the font size based on the text length
let lengthFactor = CGFloat(text.count) / 100.0
let scaledFontSize = max(baseFontSize - lengthFactor, minFontSize)

return scaledFontSize
}
}

Expand Down
2 changes: 1 addition & 1 deletion CloudMaster/Features/Exam/Views/PreviousExamsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct PreviousExamsView: View {

var body: some View {
List(exams) { exam in
NavigationLink(destination: ExamSummaryView(exam: exam)) {
NavigationLink(destination: ExamSummaryView(exam: exam, afterExam: false)) {
HStack {
VStack(alignment: .leading) {
Text(exam.mode)
Expand Down
Loading
Loading