diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..371f2e2 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..0c0c338 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..0897082 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Screenshot/Screenshot_20240303_234447.png b/Screenshot/Screenshot_20240303_234447.png new file mode 100644 index 0000000..425ad42 Binary files /dev/null and b/Screenshot/Screenshot_20240303_234447.png differ diff --git a/Screenshot/Screenshot_20240303_234513.png b/Screenshot/Screenshot_20240303_234513.png new file mode 100644 index 0000000..fcb2b4b Binary files /dev/null and b/Screenshot/Screenshot_20240303_234513.png differ diff --git a/Screenshot/Screenshot_20240303_234539.png b/Screenshot/Screenshot_20240303_234539.png new file mode 100644 index 0000000..073a82c Binary files /dev/null and b/Screenshot/Screenshot_20240303_234539.png differ diff --git a/Screenshot/Screenshot_20240303_234933.png b/Screenshot/Screenshot_20240303_234933.png new file mode 100644 index 0000000..b90341c Binary files /dev/null and b/Screenshot/Screenshot_20240303_234933.png differ diff --git a/Screenshot/Screenshot_20240303_234949.png b/Screenshot/Screenshot_20240303_234949.png new file mode 100644 index 0000000..2a5b6f0 Binary files /dev/null and b/Screenshot/Screenshot_20240303_234949.png differ diff --git a/Screenshot/Screenshot_20240303_235001.png b/Screenshot/Screenshot_20240303_235001.png new file mode 100644 index 0000000..f6f43de Binary files /dev/null and b/Screenshot/Screenshot_20240303_235001.png differ diff --git a/Screenshot/Screenshot_20240303_235025.png b/Screenshot/Screenshot_20240303_235025.png new file mode 100644 index 0000000..8378e2f Binary files /dev/null and b/Screenshot/Screenshot_20240303_235025.png differ diff --git a/Screenshot/Screenshot_20240303_235039.png b/Screenshot/Screenshot_20240303_235039.png new file mode 100644 index 0000000..d9983b7 Binary files /dev/null and b/Screenshot/Screenshot_20240303_235039.png differ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..e9b6b2d --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + id("com.android.application") +} + +android { + namespace = "com.example.quizgame_50073457" + compileSdk = 34 + + defaultConfig { + applicationId = "com.example.quizgame_50073457" + minSdk = 29 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.11.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + implementation ("com.google.code.gson:gson:2.8.6") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/quizgame_50073457/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/quizgame_50073457/ExampleInstrumentedTest.java new file mode 100644 index 0000000..14a7300 --- /dev/null +++ b/app/src/androidTest/java/com/example/quizgame_50073457/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.quizgame_50073457; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.quizgame_50073457", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..78aba73 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/quizgame_50073457/LoginActivity.java b/app/src/main/java/com/example/quizgame_50073457/LoginActivity.java new file mode 100644 index 0000000..93c2caa --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/LoginActivity.java @@ -0,0 +1,71 @@ +package com.example.quizgame_50073457; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import androidx.appcompat.app.AppCompatActivity; +import android.text.TextUtils; +import android.util.Patterns; +import android.widget.Toast; + + +public class LoginActivity extends AppCompatActivity { + + private EditText email, password; + private Button btnLogin; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + + email = findViewById(R.id.editTextEmailLogin); + password = findViewById(R.id.editTextPasswordLogin); + btnLogin = findViewById(R.id.buttonLogin); + + + btnLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (validateInputs()){ + if (PreferencesUtil.validateUser(LoginActivity.this, email.getText().toString(), password.getText().toString())) { + // Navigate to Quiz or Rules Activity + startActivity(new Intent(LoginActivity.this, RulesActivity.class)); + //startActivity(new Intent(LoginActivity.this, QuizActivity.class)); + finish(); + } else { + // Show error + Toast.makeText(LoginActivity.this, "Invalid credentials", Toast.LENGTH_SHORT).show(); + } + } + } + }); + + } + + + private boolean validateInputs() { + // Validate that the email and password fields are not empty + if (TextUtils.isEmpty(email.getText()) || TextUtils.isEmpty(password.getText())) { + Toast.makeText(LoginActivity.this, "Please enter both email and password", Toast.LENGTH_SHORT).show(); + return false; + } + + // Validate email format + if (!Patterns.EMAIL_ADDRESS.matcher(email.getText()).matches()) { + Toast.makeText(LoginActivity.this, "Please enter a valid email address", Toast.LENGTH_SHORT).show(); + return false; + } + + return true; + } + + // Assume initialization and setContentView are done + private void navigateToRules() { + Intent intent = new Intent(LoginActivity.this, RulesActivity.class); + startActivity(intent); + finish(); + } +} diff --git a/app/src/main/java/com/example/quizgame_50073457/MainActivity.java b/app/src/main/java/com/example/quizgame_50073457/MainActivity.java new file mode 100644 index 0000000..6366c56 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/MainActivity.java @@ -0,0 +1,29 @@ +package com.example.quizgame_50073457; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import androidx.appcompat.app.AppCompatActivity; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Button btnLogin = findViewById(R.id.btnLogin); + Button btnRegister = findViewById(R.id.btnRegister); + + btnLogin.setOnClickListener(v -> { + // Navigate to LoginActivity + startActivity(new Intent(MainActivity.this, LoginActivity.class)); + }); + + btnRegister.setOnClickListener(v -> { + // Navigate to RegistrationActivity + startActivity(new Intent(MainActivity.this, RegistrationActivity.class)); + }); + } +} diff --git a/app/src/main/java/com/example/quizgame_50073457/PreferencesUtil.java b/app/src/main/java/com/example/quizgame_50073457/PreferencesUtil.java new file mode 100644 index 0000000..cf6eb17 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/PreferencesUtil.java @@ -0,0 +1,109 @@ +package com.example.quizgame_50073457; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +public class PreferencesUtil { + private static final String PREFS_NAME = "QuizAppPrefs"; + private static final String USER_EMAIL = "userEmail"; + private static final String USER_PASSWORD = "userPassword"; + private static final String USER_SCORE = "userScore"; + private static final String USER_ATTEMPTS = "userAttempts"; + private static final String SCORES_KEY = "scores"; + private static final String CURRENT_USER_KEY = "currentUser"; + + private static final String QUESTIONS_KEY = "questions"; + + public static void saveUser(Context context, String email, String password) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(USER_EMAIL, email); + editor.putString(USER_PASSWORD, password); + editor.apply(); + } + + public static boolean validateUser(Context context, String email, String password) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + String savedEmail = prefs.getString(USER_EMAIL, ""); + String savedPassword = prefs.getString(USER_PASSWORD, ""); + return savedEmail.equals(email) && savedPassword.equals(password); + } + + public static void saveScore(Context context, int score) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(USER_SCORE, score); + editor.apply(); + } + + public static int getScore(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + return prefs.getInt(USER_SCORE, 0); + } + // Method to save the JSON string of scores into SharedPreferences + public static void saveScoresJson(Context context, String jsonScores) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(SCORES_KEY, jsonScores); // SCORES_KEY is the key for storing scores JSON + editor.apply(); // or editor.commit() if you need synchronous save + } + + + public static String getScoresJson(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + String scoresJson = prefs.getString(SCORES_KEY, ""); + Log.d("QuizStatActivity", "Loaded scores JSON: " + scoresJson); + return scoresJson; + } + + + // Method to get the current username + public static String getCurrentUsername(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + // Assuming USER_EMAIL is the key where the user's email is stored. + return prefs.getString(USER_EMAIL, "Unknown User"); + } + + + public static void saveQuestionsJson(Context context, String json) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(QUESTIONS_KEY, json); + editor.apply(); + } + + public static String getQuestionsJson(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + return prefs.getString(QUESTIONS_KEY, ""); // Return an empty string if nothing is found + } + + + public static void addScore(Context context, Score newScore) { + List scores = loadScores(context); + scores.add(newScore); + saveScores(context, scores); + } + + public static List loadScores(Context context) { + String jsonScores = getScoresJson(context); + if (jsonScores.isEmpty()) return new ArrayList<>(); + return new Gson().fromJson(jsonScores, new TypeToken>() {}.getType()); + } + + public static void saveScores(Context context, List scores) { + String jsonScores = new Gson().toJson(scores); + saveScoresJson(context, jsonScores); + } +} + + + + + diff --git a/app/src/main/java/com/example/quizgame_50073457/Question.java b/app/src/main/java/com/example/quizgame_50073457/Question.java new file mode 100644 index 0000000..1cf3998 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/Question.java @@ -0,0 +1,87 @@ +package com.example.quizgame_50073457; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Question { + private String questionText; + private List options; + private String correctAnswer; // For single-choice questions + private List correctAnswers; // For multiple-choice questions + private boolean isSingleChoice; + + // Constructor for single-choice questions + public Question(String questionText, List options, String correctAnswer) { + this.questionText = questionText; + this.options = options; + this.correctAnswer = correctAnswer; + this.isSingleChoice = true; + } + + // Constructor for multiple-choice questions + public Question(String questionText, List options, List correctAnswers) { + this.questionText = questionText; + this.options = options; + this.correctAnswers = correctAnswers; + this.isSingleChoice = false; + } + + // Getters + public String getQuestionText() { + return questionText; + } + + public List getOptions() { + return options; + } + + public String getCorrectAnswer() { + return correctAnswer; + } + + public List getCorrectAnswers() { + return correctAnswers; + } + + public boolean isSingleChoice() { + return isSingleChoice; + } + + // Serialization methods + public static String questionsToJson(List questions) { + Gson gson = new Gson(); + return gson.toJson(questions); + } + + public static List jsonToQuestions(String json) { + Gson gson = new Gson(); + Type listType = new TypeToken>(){}.getType(); + return gson.fromJson(json, listType); + } + + // Example usage + public static void main(String[] args) { + List questions = new ArrayList<>(); + questions.add(new Question("What hand beats a full house in texas holdem poker?", Arrays.asList("Flush", "Three of a Kind", "Straight", "Four of a Kind"), "Four of a Kind")); + questions.add(new Question("What is probability of getting one King out of a random draw?", Arrays.asList("1/52", "4/52", "1/13", "1"), Arrays.asList( "4/52", "1/13"))); + questions.add(new Question("What do you mean by work check in poker?", Arrays.asList("Check your Phone for text", "See other peoples card", "Be in the game when bets are matched, without placing any new bet", "Bet all your chips on the hand"), "Be in the game when bets are matched, without placing any new bet")); + questions.add(new Question("What is a flush in poker?", Arrays.asList("Flush all cards in table", "consecutive cards", "cards of same suit", "cards of same number"), "cards of same suit")); + questions.add(new Question("What is a river in poker?", Arrays.asList("Hudson river", "Last card to be drawn in the community cards", "Set of cards with same suit", "Friend of Big Blind"), "Last card to be drawn in the community cards")); + + + String json = Question.questionsToJson(questions); + System.out.println(); + +// Example of converting JSON back to questions + List questionsFromJson = Question.jsonToQuestions(json); + for (Question question : questionsFromJson) { + System.out.println(question.getQuestionText()); + } + + } +} diff --git a/app/src/main/java/com/example/quizgame_50073457/QuizActivity.java b/app/src/main/java/com/example/quizgame_50073457/QuizActivity.java new file mode 100644 index 0000000..d8db263 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/QuizActivity.java @@ -0,0 +1,178 @@ +package com.example.quizgame_50073457; + +import android.app.AlertDialog; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class QuizActivity extends AppCompatActivity { + private List questions = new ArrayList<>(); + private int currentQuestionIndex = 0; + private int score = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_quiz); + + List questions = new ArrayList<>(); + questions.add(new Question("What hand beats a full house in texas holdem poker?", Arrays.asList("Flush", "Three of a Kind", "Straight", "Four of a Kind"), "Four of a Kind")); + questions.add(new Question("What is probability of getting one King out of a random draw?", Arrays.asList("1/52", "4/52", "1/13", "1"), Arrays.asList( "4/52", "1/13"))); + questions.add(new Question("What do you mean by work check in poker?", Arrays.asList("Check your Phone for text", "See other peoples card", "Be in the game when bets are matched, without placing any new bet", "Bet all your chips on the hand"), "Be in the game when bets are matched, without placing any new bet")); + questions.add(new Question("What is a flush in poker?", Arrays.asList("Flush all cards in table", "consecutive cards", "cards of same suit", "cards of same number"), "cards of same suit")); + questions.add(new Question("What is a river in poker?", Arrays.asList("Hudson river", "Last card to be drawn in the community cards", "Set of cards with same suit", "Friend of Big Blind"), "Last card to be drawn in the community cards")); + + + String jsonQuestions = Question.questionsToJson(questions); + PreferencesUtil.saveQuestionsJson(getApplicationContext(), jsonQuestions); + + loadQuestions(); + + if (!questions.isEmpty()) { + displayQuestion(currentQuestionIndex); + } else { + showError("No questions available."); + } + + Button btnSubmit = findViewById(R.id.btnSubmit); + btnSubmit.setOnClickListener(v -> submitAnswer()); + } + + private void loadQuestions() { + String jsonQuestions = PreferencesUtil.getQuestionsJson(this); + if (!jsonQuestions.isEmpty()) { + questions = Question.jsonToQuestions(jsonQuestions); + if (questions == null || questions.isEmpty()) { + showError("Failed to load questions."); + } else { + displayQuestion(currentQuestionIndex); + } + } else { + showError("No questions available."); + } + } + + private void displayQuestion(int questionIndex) { + Question question = questions.get(questionIndex); + TextView tvQuestion = findViewById(R.id.tvQuestion); + RadioGroup rgSingleChoice = findViewById(R.id.rgSingleChoice); + LinearLayout llMultipleChoice = findViewById(R.id.llMultipleChoice); + + tvQuestion.setText(question.getQuestionText()); + rgSingleChoice.removeAllViews(); + llMultipleChoice.removeAllViews(); + + if (question.isSingleChoice()) { + displaySingleChoiceQuestion(question, rgSingleChoice); + } else { + displayMultipleChoiceQuestion(question, llMultipleChoice); + } + } + + private void displaySingleChoiceQuestion(Question question, RadioGroup rgSingleChoice) { + rgSingleChoice.setVisibility(View.VISIBLE); + for (String option : question.getOptions()) { + RadioButton rb = new RadioButton(this); + rb.setText(option); + rgSingleChoice.addView(rb); + } + } + + private void displayMultipleChoiceQuestion(Question question, LinearLayout llMultipleChoice) { + llMultipleChoice.setVisibility(View.VISIBLE); + for (String option : question.getOptions()) { + CheckBox cb = new CheckBox(this); + cb.setText(option); + llMultipleChoice.addView(cb); + } + } + + private void submitAnswer() { + Question currentQuestion = questions.get(currentQuestionIndex); + + // Show confirmation dialog + new AlertDialog.Builder(this) + .setTitle("Confirm Answer") + .setMessage("Are you sure you want to submit this answer?") + .setPositiveButton("Yes", (dialog, which) -> { + if (checkAnswer(currentQuestion)) { + score++; + } + prepareNextQuestionOrFinish(); + }) + .setNegativeButton("No", (dialog, which) -> dialog.dismiss()) + .show(); + } + + private boolean checkAnswer(Question question) { + if (question.isSingleChoice()) { + return checkSingleChoiceAnswer(question); + } else { + return checkMultipleChoiceAnswer(question); + } + } + + private boolean checkSingleChoiceAnswer(Question question) { + RadioGroup rgSingleChoice = findViewById(R.id.rgSingleChoice); + int selectedId = rgSingleChoice.getCheckedRadioButtonId(); + if (selectedId != -1) { + RadioButton selectedOption = findViewById(selectedId); + return selectedOption.getText().toString().equals(question.getCorrectAnswer()); + } + return false; + } + + private boolean checkMultipleChoiceAnswer(Question question) { + LinearLayout llMultipleChoice = findViewById(R.id.llMultipleChoice); + List selectedAnswers = new ArrayList<>(); + for (int i = 0; i < llMultipleChoice.getChildCount(); i++) { + CheckBox cb = (CheckBox) llMultipleChoice.getChildAt(i); + if (cb.isChecked()) { + selectedAnswers.add(cb.getText().toString()); + } + } + return selectedAnswers.equals(question.getCorrectAnswers()); + } + + private void prepareNextQuestionOrFinish() { + currentQuestionIndex++; + if (currentQuestionIndex < questions.size()) { + displayQuestion(currentQuestionIndex); + } else { + finishQuiz(); + } + } + + private void finishQuiz() { + PreferencesUtil.saveScore(this, score); + startActivity(new Intent(this, ResultActivity.class)); + finish(); + } + + private void showError(String message) { + // Assuming you have a TextView with the ID tvError in your layout + TextView tvError = findViewById(R.id.tvError); + if (tvError != null) { + tvError.setText(message); + tvError.setVisibility(View.VISIBLE); + } else { + Toast.makeText(this, message, Toast.LENGTH_LONG).show(); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/quizgame_50073457/QuizStatActivity.java b/app/src/main/java/com/example/quizgame_50073457/QuizStatActivity.java new file mode 100644 index 0000000..c7c94f6 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/QuizStatActivity.java @@ -0,0 +1,56 @@ +package com.example.quizgame_50073457; + +import android.os.Bundle; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import androidx.appcompat.app.AppCompatActivity; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class QuizStatActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_quiz_stat); + + List scores = loadScores(); + displayTopScores(scores); + displayRecentScores(scores); + } + + private List loadScores() { + String scoresJson = PreferencesUtil.getScoresJson(this); + Type scoreListType = new TypeToken>(){}.getType(); + return new Gson().fromJson(scoresJson, scoreListType); + } + + private void displayTopScores(List scores) { + List topScores = scores.stream() + .sorted(Collections.reverseOrder(Comparator.comparing(Score::getScore))) + .limit(5) + .map(score -> String.format("%s - %d", score.getUsername(), score.getScore())) + .collect(Collectors.toList()); + + ListView topScoresListView = findViewById(R.id.topScoresListView); + topScoresListView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, topScores)); + } + + private void displayRecentScores(List scores) { + String currentUsername = PreferencesUtil.getCurrentUsername(this); + List recentScores = scores.stream() + .filter(score -> score.getUsername().equals(currentUsername)) + .sorted(Collections.reverseOrder(Comparator.comparing(Score::getTimestamp))) + .limit(5) + .map(score -> String.format("%s - %d", score.getTimestamp(), score.getScore())) + .collect(Collectors.toList()); + + ListView recentScoresListView = findViewById(R.id.recentScoresListView); + recentScoresListView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, recentScores)); + } +} diff --git a/app/src/main/java/com/example/quizgame_50073457/RegistrationActivity.java b/app/src/main/java/com/example/quizgame_50073457/RegistrationActivity.java new file mode 100644 index 0000000..2258f4a --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/RegistrationActivity.java @@ -0,0 +1,89 @@ +package com.example.quizgame_50073457; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import android.util.Patterns; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; + +public class RegistrationActivity extends AppCompatActivity { + + private EditText firstName, lastName, email, password, dob; + private Button btnRegister; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_registration); + + firstName = findViewById(R.id.editTextFirstName); + lastName = findViewById(R.id.editTextLastName); + email = findViewById(R.id.editTextEmail); + password = findViewById(R.id.editTextPassword); + dob = findViewById(R.id.editTextDob); + btnRegister = findViewById(R.id.buttonRegister); + + btnRegister.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (validateInputs()) { + Toast.makeText(RegistrationActivity.this, "Registration Successful", Toast.LENGTH_SHORT).show(); + PreferencesUtil.saveUser(RegistrationActivity.this, email.getText().toString(), password.getText().toString()); + // Return to previous screen or login screen + finish(); // Go back to the previous activity page + } + } + }); + } + + private boolean validateInputs() { + // Validate that the entered data is not empty + if (TextUtils.isEmpty(firstName.getText()) || + TextUtils.isEmpty(lastName.getText()) || + TextUtils.isEmpty(email.getText()) || + TextUtils.isEmpty(password.getText()) || + TextUtils.isEmpty(dob.getText())) { + Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show(); + return false; + } + + // Validate email format + if (!Patterns.EMAIL_ADDRESS.matcher(email.getText()).matches()) { + Toast.makeText(this, "Enter a valid email", Toast.LENGTH_SHORT).show(); + return false; + } + + // Validate first name length + if (firstName.getText().length() < 3 || firstName.getText().length() > 30) { + Toast.makeText(this, "First name must be between 3 and 30 characters", Toast.LENGTH_SHORT).show(); + return false; + } + + // Validate date format MM/DD/YYYY + if (!isValidDate(dob.getText().toString())) { + Toast.makeText(this, "Date must be in MM/DD/YYYY format", Toast.LENGTH_SHORT).show(); + return false; + } + + return true; + } + + private boolean isValidDate(String date) { + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.US); + sdf.setLenient(false); // Don't automatically convert invalid date + try { + sdf.parse(date); // If the date is valid, this line will succeed + return true; + } catch (ParseException e) { + return false; // If the date is invalid, parsing will fail + } + } +} + + diff --git a/app/src/main/java/com/example/quizgame_50073457/ResultActivity.java b/app/src/main/java/com/example/quizgame_50073457/ResultActivity.java new file mode 100644 index 0000000..5383cab --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/ResultActivity.java @@ -0,0 +1,67 @@ +package com.example.quizgame_50073457; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; + + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; + +import java.util.List; + + +public class ResultActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_result); + + + int score = getIntent().getIntExtra("score", 0); + // Assuming score is passed as an extra in the intent + + updateScoreInSharedPreferences(score); + TextView tvScore = findViewById(R.id.tvScore); + tvScore.setText("Score: " + score); + + Button btnRetakeQuiz = findViewById(R.id.btnRetakeQuiz); + btnRetakeQuiz.setOnClickListener(v -> { + startActivity(new Intent(this, QuizActivity.class)); + finish(); + }); + + Button btnExit = findViewById(R.id.btnExit); + btnExit.setOnClickListener(v -> finish()); + + Button btnViewQuizStats = findViewById(R.id.btnViewStat); + btnViewQuizStats.setOnClickListener(v -> { + startActivity(new Intent(this, QuizStatActivity.class)); + }); + } + + private void updateScoreInSharedPreferences(int score) { + // Fetch current scores + String scoresJson = PreferencesUtil.getScoresJson(this); + Gson gson = new Gson(); + Type scoreListType = new TypeToken>(){}.getType(); + List scores = gson.fromJson(scoresJson, scoreListType); + if (scores == null) scores = new ArrayList<>(); + + // Add the new score + String currentUsername = PreferencesUtil.getCurrentUsername(this); + String timestamp = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(System.currentTimeMillis())); + scores.add(new Score(currentUsername, score, timestamp)); + + + // Save updated scores + PreferencesUtil.saveScoresJson(this, gson.toJson(scores)); + } + +} diff --git a/app/src/main/java/com/example/quizgame_50073457/RulesActivity.java b/app/src/main/java/com/example/quizgame_50073457/RulesActivity.java new file mode 100644 index 0000000..2824319 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/RulesActivity.java @@ -0,0 +1,41 @@ +package com.example.quizgame_50073457; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import androidx.appcompat.app.AppCompatActivity; +public class RulesActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_rules); + // Layout contains TextView with rules + + Button takeQuiz = findViewById(R.id.takeQuiz); + takeQuiz.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(RulesActivity.this, QuizActivity.class)); + } + }); + + Button btnViewResults = findViewById(R.id.btnViewResults); + btnViewResults.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(RulesActivity.this, ResultActivity.class)); + } + }); + + Button btnViewStat = findViewById(R.id.btnViewStat); + btnViewResults.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(RulesActivity.this, QuizStatActivity.class)); + } + }); + + } +} diff --git a/app/src/main/java/com/example/quizgame_50073457/Score.java b/app/src/main/java/com/example/quizgame_50073457/Score.java new file mode 100644 index 0000000..6e3fb53 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/Score.java @@ -0,0 +1,28 @@ +package com.example.quizgame_50073457; + +public class Score { + private String username; + private int score; + private String timestamp; // ISO 8601 format, e.g., "2023-03-22T14:00:00Z" + + public Score(String username, int score, String timestamp) { + this.username = username; + this.score = score; + this.timestamp = timestamp; + } + + // Getters + public String getUsername() { + return username; + } + + public int getScore() { + return score; + } + + public String getTimestamp() { + return timestamp; + } + + // Setters, +} diff --git a/app/src/main/java/com/example/quizgame_50073457/SplashScreenActivity.java b/app/src/main/java/com/example/quizgame_50073457/SplashScreenActivity.java new file mode 100644 index 0000000..5ff6948 --- /dev/null +++ b/app/src/main/java/com/example/quizgame_50073457/SplashScreenActivity.java @@ -0,0 +1,29 @@ +package com.example.quizgame_50073457; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; + +import androidx.appcompat.app.AppCompatActivity; + +public class SplashScreenActivity extends AppCompatActivity { + + // Duration of wait + private final int SPLASH_DISPLAY_LENGTH = 2000; // 1 second + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash_screen); + + new Handler().postDelayed(new Runnable(){ + @Override + public void run() { + // Create an Intent that will start the Login/Registration Activity. + Intent mainIntent = new Intent(SplashScreenActivity.this, MainActivity.class); + SplashScreenActivity.this.startActivity(mainIntent); + SplashScreenActivity.this.finish(); + } + }, SPLASH_DISPLAY_LENGTH); + } +} diff --git a/app/src/main/res/drawable/applogo.png b/app/src/main/res/drawable/applogo.png new file mode 100644 index 0000000..09b852e Binary files /dev/null and b/app/src/main/res/drawable/applogo.png differ diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/instagram_background_gradient.xml b/app/src/main/res/drawable/instagram_background_gradient.xml new file mode 100644 index 0000000..19dd416 --- /dev/null +++ b/app/src/main/res/drawable/instagram_background_gradient.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/drawable/landing.png b/app/src/main/res/drawable/landing.png new file mode 100644 index 0000000..71f25ab Binary files /dev/null and b/app/src/main/res/drawable/landing.png differ diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..c61072e --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,47 @@ + + + + + + + +