change repo

This commit is contained in:
Ruben Kallinich
2024-07-11 10:44:44 +02:00
commit 4a034b660f
88 changed files with 21963 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, combineLatest, map } from 'rxjs';
import { Question } from '../Model/question';
@Injectable({
providedIn: 'root',
})
export class DataInput {
constructor(private http: HttpClient) {}
private katalog1Url = 'assets/LPI-2019-1-101d-QA.json';
private katalog2Url = 'assets/LPI-2019-1-102d-QA.json';
getQuestion1(): Observable<Question[]> {
return this.http.get<Question[]>(this.katalog1Url);
}
getQuestion2(): Observable<Question[]> {
return this.http.get<Question[]>(this.katalog2Url);
}
getKatalog1Url(): string {
return this.katalog1Url;
}
getKaltalog2Url(): string {
return this.katalog2Url;
}
getAllQuestions(): Observable<Question[]>{
const question1 = this.getQuestion1();
const question2 = this.getQuestion2();
return combineLatest([question1, question2]).pipe(
map(([question1,question2]) => [...question1, ...question2])
);
}
}

View File

@@ -0,0 +1,62 @@
import { Injectable } from '@angular/core';
import { Question } from '../Model/question';
import { BehaviorSubject } from 'rxjs';
import { DataInput } from './data-input';
@Injectable({
providedIn: 'root'
})
export class FilterService {
selectedType: string = '';
filteredQuestionsLPI101: Question[] = [];
filteredQuestionsLPI102: Question[] = [];
questions: Question[] = [];
qustionTypesToShow: string[] = [];
constructor(
private mainService: DataInput,
) {
}
private selectedTypeSource = new BehaviorSubject<string>(''); // Initialwert
selectedType$ = this.selectedTypeSource.asObservable();
setQuestionTypesToShow(questionTypes: string[]): void {
this.qustionTypesToShow = questionTypes;
}
setSelectedType(selectedType: string): void {
this.selectedTypeSource.next(selectedType);
this.updateFilteredQuestions(selectedType);
}
setQuestions(questions: Question[]): void {
this.questions = questions;
}
filterByQuestionsTypes(questions: Question[], questionType: string): Question[] {
console.log(questions,'Questions');
console.log(this.questions,'Katalog');
const filtered = questions.filter(question => question.questionType == questionType)
console.log(questionType,'Filtered');
console.log(filtered,'Filtered');
return filtered;
}
updateFilteredQuestions(selectedType: string): void {
this.mainService.getQuestion1().subscribe(questionsLPI101 => {
this.filteredQuestionsLPI101 = this.filterByQuestionsTypes(questionsLPI101, selectedType);
});
this.mainService.getQuestion2().subscribe(questionsLPI102 => {
const filteredQuestionsLPI102 = this.filterByQuestionsTypes(questionsLPI102, selectedType);
this.filteredQuestionsLPI102 = filteredQuestionsLPI102;
});
}
}

View File

@@ -0,0 +1,54 @@
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { PopUpComponent } from '../Popup/pop-up/pop-up.component';
import { StatistikComponent } from '../Popup/statistik/statistik.component';
import { ErrorMessageComponent } from '../Popup/error-message/error-message.component';
@Injectable({
providedIn: 'root',
})
export class PopupService {
constructor(
private dialog: MatDialog,
) {}
openPopUp(message: string): void {
this.dialog.open(PopUpComponent, {
data: { message: message },
});
}
errorPopup(message: string): void {
this.dialog.open(ErrorMessageComponent , {
data: { message: message },
});
}
openStatisticPopup(message: string): void {
this.dialog.open(StatistikComponent, {
data: { message: message },
});
}
dontMoveWitNowAnswer(): void {
this.openPopUp('Please provide an answer before proceeding');
}
wrongAnswerMessage(): void {
this.openPopUp( //ändern
"There are two possibilities:\n\nA) You were not paying attention\nB) You were not honest\nIf you really don't know, skip the question."
);
}
backToLearningCenterExam(): void {
this.errorPopup(
'You have already answered more than 20% of the questions incorrectly. The exam will be terminated.'
);
}
backToLearningCenterCheck(): void {
this.errorPopup(
'You have already answered 7 of the questions incorrectly. The check will be terminated.'
);
}
}

View File

@@ -0,0 +1,292 @@
import { Injectable } from '@angular/core';
import { TrueOrFalesService } from './true-or-false.service';
import { Question } from '../Model/question';
import { AnswerData } from '../Model/answer-data';
import { PopupService } from './popup.service';
import { StatistikService } from './statistik.service';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class QuestionNavigationService {
private currentQuestionIndex: number = 0;
private currentQuestion!: Question;
private isFirstQuestion: boolean = true;
private isLastQuestion: boolean = false;
private answeredQuestions: boolean[] = [];
private totalQuestions: number = 0;
private answerData: AnswerData[] = [];
constructor(
private trueOrFalseService: TrueOrFalesService,
private popupServ: PopupService,
private statistServ: StatistikService,
private router: Router
) {}
initializeNavigation(totalQuestions: number): void {
this.totalQuestions = totalQuestions;
this.currentQuestionIndex = 0;
this.isFirstQuestion = true;
this.isLastQuestion = totalQuestions === 1;
}
private recordAnswerData(userAnswer: string, isAnswerCorrect: boolean): void {
this.answerData.push({
question: this.trueOrFalseService.getCurrentQuestion(),
userAnswer: userAnswer,
isCorrect: isAnswerCorrect,
});
}
moveNextQuestionCheckMode(): void {
const currentAnswers = this.trueOrFalseService.getCurrentAnswers();
const userAnswer = currentAnswers.userAnswer;
if (!this.isLastQuestion) {
//Überprüfen ob die Antwort korrekt ist
if (this.shouldSkipQuestion(userAnswer)) {
if (this.trueOrFalseService.getSkipped()) {
this.statistServ.incrementCounterOfSkip();
this.moveNextQuestionWithOutCheck();
this.trueOrFalseService.setSkipped(false);
} else {
this.popupServ.dontMoveWitNowAnswer();
}
} else {
const isAnswerCorrect = this.trueOrFalseService.checkAnswer(userAnswer);
this.evalueteAnswer(userAnswer, isAnswerCorrect);
}
} else {
if (this.shouldSkipQuestion(userAnswer)) {
if (this.trueOrFalseService.getSkipped()) {
this.statistServ.incrementCounterOfSkip();
this.moveNextQuestionWithOutCheck();
this.trueOrFalseService.setSkipped(false);
} else {
this.popupServ.dontMoveWitNowAnswer();
}
} else {
const isAnswerCorrect = this.trueOrFalseService.checkAnswer(userAnswer);
this.evalueteAnswer(userAnswer, isAnswerCorrect);
}
}
}
shouldSkipQuestion(userAnser: string): boolean {
return userAnser === undefined || userAnser.trim() === '';
}
evalueteAnswer(userAnswer: string, isAnswerCorrect: boolean): void {
this.recordAnswerData(userAnswer, isAnswerCorrect);
if (isAnswerCorrect) {
this.statistServ.incrementCounterOfCorrect();
if (this.isLastQuestion) {
this.endExam();
} else {
this.forwardQuestion();
}
} else {
//Answer is wrong
if (this.statistServ.getCounterOfIncorrect() === 6) {
this.popupServ.backToLearningCenterCheck();
} else{
this.statistServ.incrementCounterOfIncorrect();
this.popupServ.wrongAnswerMessage();
}
if (this.isLastQuestion) {
this.popupServ.wrongAnswerMessage();
this.statistServ.incrementCounterOfIncorrect();
this.previusQuestion();
} else{
this.previusQuestion();
}
}
}
forwardQuestion(): void {
const currentIndex = this.trueOrFalseService.getCurrentQuestionIndex();
if (
!(
this.trueOrFalseService.getCurrentQuestionIndex() ===
this.totalQuestions - 1
)
) {
this.trueOrFalseService.incrementQuestionIndex();
this.isFirstQuestion = false;
this.isLastQuestion = currentIndex === this.totalQuestions - 1;
this.loadCurrentQuestion();
}
}
previusQuestion(): void {
const currentIndex = this.trueOrFalseService.getCurrentQuestionIndex();
if (currentIndex > 0 ) {
this.trueOrFalseService.decrementQuestionIndex();
this.isFirstQuestion = currentIndex === 1;
this.isLastQuestion = currentIndex === this.totalQuestions - 1;
}
}
moveNextQuestionWithOutCheck(): void {
if (!this.isLastQuestion) {
this.trueOrFalseService.incrementQuestionIndex();
this.isFirstQuestion = false;
this.isLastQuestion =
this.trueOrFalseService.getCurrentQuestionIndex() ===
this.totalQuestions - 1;
this.loadCurrentQuestion();
}
}
skipQuestion(): void {
if (!this.isLastQuestion) {
this.trueOrFalseService.setSkipped(true);
this.trueOrFalseService.updateCurrentAnswers({
selectedChoice: [],
userAnswer: '',
});
this.moveNextQuestionCheckMode();
}
}
movePreviusQuestion(): void {
if (!this.isFirstQuestion) {
const currentAnswers = this.trueOrFalseService.getCurrentAnswers();
this.trueOrFalseService.updateCurrentAnswers(currentAnswers);
this.trueOrFalseService.decrementQuestionIndex();
this.isFirstQuestion =
this.trueOrFalseService.getCurrentQuestionIndex() === 0;
this.isLastQuestion = false;
this.loadCurrentQuestion();
}
}
moveNextQuestionExamMode(): void {
const currentAnswers = this.trueOrFalseService.getCurrentAnswers();
const userAnswer = currentAnswers.userAnswer;
if (!this.isLastQuestion) {
//Überprüfen ob die Antwort korrekt ist
if (this.shouldSkipQuestion(userAnswer)) {
if (this.trueOrFalseService.getSkipped()) {
this.statistServ.incrementCounterOfSkip();
this.trueOrFalseService.setSkipped(false);
} else {
this.skipQuestion();
}
} else {
const isAnswerCorrect = this.trueOrFalseService.checkAnswer(userAnswer);
this.evalueteAnswerExam(userAnswer, isAnswerCorrect);
}
} else {
if (this.shouldSkipQuestion(userAnswer)) {
if (this.trueOrFalseService.getSkipped()) {
this.statistServ.incrementCounterOfSkip();
this.trueOrFalseService.setSkipped(false);
} else {
this.skipQuestion();
}
}
this.evalueteAnswerExam(userAnswer,this.trueOrFalseService.checkAnswer(userAnswer));
}
}
evalueteAnswerExam(userAnswer: string, isAnswerCorrect: boolean): void {
this.recordAnswerData(userAnswer, isAnswerCorrect);
if (isAnswerCorrect) {
//Answer is correct
this.statistServ.incrementCounterOfCorrect();
} else {
//Answer is incorrect
this.statistServ.incrementCounterOfIncorrect();
this.twentyPercentThrsholdRule();
}
if(this.isLastQuestion){
this.endExam();
}else{
this.forwardQuestion();
}
}
twentyPercentThrsholdRule(): void{
const incorrectAnswers = this.statistServ.getCounterOfIncorrect();
const totalQuestions = this.trueOrFalseService.getKatalog1().length;
const twentyPercentThrshold = totalQuestions * 0.2;
if (incorrectAnswers >= twentyPercentThrshold) {
this.popupServ.backToLearningCenterExam();
} else {
if (this.thisIsLastQuestion()) {
this.endExam();
}
}
}
endExam(): void {
this.popupSaticMessages()
}
thisIsLastQuestion(): boolean {
if (
this.trueOrFalseService.getCurrentQuestionIndex() ===
this.trueOrFalseService.getKatalog1().length - 1
) {
this.isLastQuestion = true;
return this.isLastQuestion;
} else {
return false;
}
}
thisIsFirstQuesteion(): boolean {
return this.isFirstQuestion;
}
getCurrentQuestion(): Question {
return this.trueOrFalseService.getKatalog1()[
this.trueOrFalseService.getCurrentQuestionIndex()
];
}
setCurrentQuestion(question: Question): void {
this.currentQuestion = question;
}
loadCurrentQuestion(): void {
const currentQuestion = this.trueOrFalseService.getCurrentQuestion();
if (currentQuestion) {
this.setCurrentQuestion(currentQuestion);
}
}
markQuestionAnswered(index: number): void {
if (index >= 0 && index < this.answeredQuestions.length) {
this.answeredQuestions[index] = true;
}
}
hasQuestionBeenAnswered(index: number): boolean {
if (index >= 0 && index < this.answeredQuestions.length) {
return this.answeredQuestions[index];
}
return false;
}
popupSaticMessages():void{
const totalQuestions = this.trueOrFalseService.getKatalog1().length;
const correctCounter = this.statistServ.getCounterOfCorrect();
const incorrectCounter = this.statistServ.getCounterOfIncorrect();
const skipCount = this.statistServ.getCounterOfSkip();
const message = `Total number of questions: ${totalQuestions}\nCorrectly answered: ${correctCounter}\nIncorrectly answered: ${incorrectCounter}\nSkipped: ${skipCount}`;
this.popupServ.openStatisticPopup(message);
}
}

View File

@@ -0,0 +1,67 @@
import { Injectable } from '@angular/core';
import { TrueOrFalesService } from './true-or-false.service';
import { FrageOption } from '../Model/frage-option';
import { NavigationEnd, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class QuestionToggleService {
private showAnswer: boolean = false;
private shuffleEnabled: boolean = false;
constructor(
private trueFalse: TrueOrFalesService,
) { }
toggleChoiceSelectionSingle(choice: FrageOption) {
const currentQuestion = this.trueFalse.getCurrentQuestion();
if (currentQuestion) {
currentQuestion.choices.map((c) => (c.selected = false));
choice.selected = !choice.selected;
this.trueFalse.updateCurrentAnswers({
selectedChoice: currentQuestion.choices,
userAnswer: currentQuestion.answer as string,
});
}
}
toggleChoiceSelectionMulti(choice: FrageOption) {
const currentQuestion = this.trueFalse.getCurrentQuestion();
if (currentQuestion) {
choice.selected = !choice.selected;
const selectedChoices = currentQuestion.choices.filter((c) => c.selected);
this.trueFalse.updateCurrentAnswers({
selectedChoice: selectedChoices,
userAnswer: currentQuestion.answer as string,
});
}
}
toggleInputAnswer(answer: string | undefined) {
if (answer !== undefined) {
const currentQuestion = this.trueFalse.getCurrentQuestion();
if (currentQuestion) {
const normalizedUserAnswer = this.trueFalse.normalizeUserAnswer(answer);
if (normalizedUserAnswer !== undefined) {
this.trueFalse.setCurrentAnswers(normalizedUserAnswer);
} else {
console.log('Normalized answer is undefined.'); // Handle undefined normalized answer
}
}
} else {
console.log('Answer is undefined.'); // Handle undefined answer
}
}
toggleAnswerVisibility(): void{
this.showAnswer = !this.showAnswer;
}
getShowAnswer(): boolean{
return this.showAnswer;
}
}

View File

@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class StatistikService {
private correct: number = 0;
private incorrect: number = 0;
private skip: number = 0;
incrementCounterOfCorrect(): void {
this.correct++;
}
incrementCounterOfIncorrect(): void {
this.incorrect++;
}
incrementCounterOfSkip(): void {
this.skip++;
}
getCounterOfCorrect(): number {
return this.correct;
}
getCounterOfIncorrect(): number {
return this.incorrect;
}
getCounterOfSkip(): number {
return this.skip;
}
resetStatistics(): void{
this.correct = 0;
this.incorrect = 0;
this.skip = 0;
}
}

View File

@@ -0,0 +1,206 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { EMPTY, Observable, catchError,tap } from 'rxjs';
import { Question } from '../Model/question';
import { DataInput } from './data-input';
import { Answers } from '../Model/answers';
@Injectable({
providedIn: 'root',
})
export class TrueOrFalesService {
private katalog1: Question[] = [];
private katalog2: Question[] = [];
private answer: Answers[] = [];
private currentQuestionIndex: number = 0;
public isLastQuestion: boolean = true;
public isFirstQuestion: boolean = false;
private skipped: boolean = false;
private userAnswer:string = '';
private shuffleEnabled: boolean = false;
constructor(
private fragenService: DataInput,
private http: HttpClient,
) {
}
initializeAnswer(): void {
this.answer = this.katalog1.map(() => ({
selectedChoice: [],
userAnswer: '',
}));
}
setQuestionsAndAnswers(questions: Question[]): void {
this.katalog1 = questions;
this.isFirstQuestion = true;
this.isLastQuestion = this.katalog1.length === 1;
this.initializeAnswer();
}
getCurrentQuestionIndex(): number {
return this.currentQuestionIndex;
}
setCurrentQuestionIndex(index: number):void {
this.currentQuestionIndex = index;
}
incrementQuestionIndex():void{
this.currentQuestionIndex++;
}
decrementQuestionIndex():void{
this.currentQuestionIndex--;
}
getCurrentQuestion(): Question {
return this.katalog1[this.getCurrentQuestionIndex()];
}
getCurrentAnswers(): Answers {
const currentAnswers = this.answer[this.getCurrentQuestionIndex()];
return currentAnswers || {selectedChoice: [], userAnswer: ''}
}
setCurrentAnswers(userAnswer: string): void {
this.setUserAnswer(userAnswer);
const currentAnswers = this.getCurrentAnswers();
this.updateCurrentAnswers(currentAnswers);
}
setUserAnswer(userAnswer: string): void {
this.userAnswer = userAnswer;
}
getUserAnswer(): string {
return this.userAnswer;
}
updateCurrentAnswers(updatedAnswers: Answers): void {
this.answer[this.getCurrentQuestionIndex()] = updatedAnswers;
}
private setKatalogAndQuestions(data: Question[]): void {
this.katalog1 = data;
this.currentQuestionIndex = 0;
this.isLastQuestion = false;
this.isFirstQuestion = true;
}
loadKatalogAndQuestions(): Observable<Question[]> {
this.initializeAnswer()
return this.http
.get<Question[]>(this.fragenService.getKatalog1Url())
.pipe(
tap((data) => {
this.setKatalogAndQuestions(data);
}),
catchError((error) => {
console.log('Fehler beim Laden des Katalogs aufgetreten', error);
return EMPTY;
})
);
}
loadKatalog2AndQuestions(): Observable<Question[]> {
this.initializeAnswer()
return this.http
.get<Question[]>(this.fragenService.getKaltalog2Url())
.pipe(
tap((data) => {
this.setKatalogAndQuestions(data);
}),
catchError((error) => {
console.log('Fehler beim laden des Katalaogs aufgetreten', error);
return EMPTY;
})
);
}
checkAnswer(userAnswer: string | string[]): boolean {
const currentQuestion = this.getCurrentQuestion();
//SingleChoiceQuestions
if (currentQuestion.questionType === 'single') {
return this.checkSingleChoiceAnswer(currentQuestion);
//MultipleChoiceQuestions
} else if (currentQuestion.questionType === 'multiple') {
return this.checkMultipleChoiceAnswer(currentQuestion);
//InputQuestions
} else if (currentQuestion.questionType === 'input') {
return this.checkInputAnswer(currentQuestion, userAnswer);
}
return false;
}
private checkSingleChoiceAnswer(question: Question): boolean{
const selectedChoice = this.getCurrentAnswers().selectedChoice.find(choice => choice.selected);
if (selectedChoice) {
const selectedFirstLatter = selectedChoice.text[0];
return selectedFirstLatter === question.answer;
}
return false;
}
private checkMultipleChoiceAnswer(qustion: Question): boolean{
const selectedChoices = this.getCurrentAnswers().selectedChoice.filter(choice => choice.selected);
const selectedTexts = selectedChoices.map(choice => choice.text[0]).sort().join('');
const sortedCorrectAnswer = qustion.answer.toString().split('').sort().join('');
return selectedTexts === sortedCorrectAnswer;
}
private checkInputAnswer(question: Question, userAnswer: string | string[]): boolean{
const formattedCorrectAnswers = Array.isArray(question.answer)
? question.answer.map(answer => answer.trim().toLowerCase())
: [question.answer.trim().toLowerCase()];
const normalizeUserAnswer = this.normalizeUserAnswer(userAnswer)||'';
const includes = formattedCorrectAnswers.includes(normalizeUserAnswer);
return includes;
}
//Normalizsation
normalizeUserAnswer(userAnswer: string | string[] | boolean): string | undefined {
if (typeof userAnswer === 'boolean') {
return [userAnswer.toString()].join('');
} else if (Array.isArray(userAnswer)) {
return userAnswer.map((answer: string | boolean) => (typeof answer === 'string' ? answer.trim() : answer.toString())).join('');
} else if (userAnswer === undefined) {
return undefined;
} else {
return [userAnswer.trim()].join('');
}
}
compareInputAnswers(userAnswer: string, correctAnswers: string): boolean {
const formattedUserAnswer = userAnswer.trim().replace(/\r?\n|\r/g, '');
const formattedCorrectAnswers = correctAnswers
.trim()
.replace(/\r?\n|\r/g, '');
return (
formattedUserAnswer.toLowerCase() === formattedCorrectAnswers.toLowerCase()
);
}
setSkipped(value: boolean): void{
this.skipped = value;
}
getSkipped():boolean{
return this.skipped;
}
getKatalog1(): Question[] {
return this.katalog1;
}
getKatalog2(): Question[] {
return this.katalog2;
}
}