package [Link].
quizapp
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link].material3.*
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
// 1. Data Model
data class Question(
val question: String,
val options: List<String>,
val correctAnswerIndex: Int
)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
QuizAppTheme {
QuizApp()
}
}
}
}
@Composable
fun QuizAppTheme(content: @Composable () -> Unit) {
val colors = lightColorScheme(
primary = Color(0xFF0D47A1),
secondary = Color(0xFF1976D2),
background = Color(0xFFE3F2FD),
surface = [Link]
)
MaterialTheme(colorScheme = colors, content = content)
}
@Composable
fun QuizApp() {
var userName by remember { mutableStateOf("") }
var studentId by remember { mutableStateOf("") }
var isRegistered by remember { mutableStateOf(false) }
var currentIndex by remember { mutableStateOf(0) }
var score by remember { mutableStateOf(0) }
var isFinished by remember { mutableStateOf(false) }
// Expanded Question Pool
val questions = remember {
listOf(
Question("What is the capital of Ethiopia?", listOf("Addis Ababa", "London", "Rome",
"Berlin"), 0),
Question("What is 2 + 2?", listOf("3", "4", "5", "6"), 1),
Question("Which planet is known as the Red Planet?", listOf("Earth", "Mars", "Jupiter",
"Venus"), 1),
Question("Which language is used for Android Development?", listOf("Swift", "Kotlin", "C#",
"Objective-C"), 1),
Question("What is the largest ocean on Earth?", listOf("Atlantic", "Indian", "Arctic",
"Pacific"), 3),
Question("Who painted the Mona Lisa?", listOf("Van Gogh", "Picasso", "Da Vinci", "Monet"),
2),
Question("What is the boiling point of water?", listOf("90°C", "100°C", "110°C", "120°C"),
1),
Question("Which is the smallest continent?", listOf("Africa", "Europe", "Australia",
"Antarctica"), 2),
Question("How many colors are in a rainbow?", listOf("5", "6", "7", "8"), 2),
Question("What is the square root of 64?", listOf("6", "7", "8", "9"), 2)
)
}
Surface(modifier = [Link](), color = [Link]) {
when {
!isRegistered -> {
RegistrationScreen(onStartQuiz = { name, id ->
userName = name
studentId = id
isRegistered = true
})
}
isFinished -> {
ResultScreen(userName, studentId, score, [Link]) {
currentIndex = 0
score = 0
isFinished = false
isRegistered = false
}
}
else -> {
val currentQuestion = questions[currentIndex]
key(currentIndex) {
QuestionScreen(
question = currentQuestion,
currentIndex = currentIndex,
totalQuestions = [Link],
onAnswerSelected = { index ->
if (index == [Link]) score++
},
onNext = {
if (currentIndex + 1 >= [Link]) isFinished = true
else currentIndex++
}
)
}
}
}
}
}
@Composable
fun RegistrationScreen(onStartQuiz: (String, String) -> Unit) {
var name by remember { mutableStateOf("") }
var idInput by remember { mutableStateOf("") }
val scrollState = rememberScrollState()
Column(
modifier = [Link]().padding([Link]).verticalScroll(scrollState),
verticalArrangement = [Link],
horizontalAlignment = [Link]
){
Text("Student Registration", style = [Link])
Spacer(modifier = [Link]([Link]))
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Enter Your Name") },
modifier = [Link](),
singleLine = true
)
Spacer(modifier = [Link]([Link]))
OutlinedTextField(
value = idInput,
onValueChange = { idInput = it },
label = { Text("Enter Student ID") },
modifier = [Link](),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = [Link])
)
Spacer(modifier = [Link]([Link]))
Button(
onClick = { onStartQuiz(name, idInput) },
enabled = [Link]() && [Link](),
modifier = [Link]()
){
Text("Start Quiz")
}
}
}
@Composable
fun QuestionScreen(
question: Question,
currentIndex: Int,
totalQuestions: Int,
onAnswerSelected: (Int) -> Unit,
onNext: () -> Unit
){
var selectedIndex by remember { mutableStateOf<Int?>(null) }
var isSubmitted by remember { mutableStateOf(false) }
Column(modifier = [Link]().padding([Link]), verticalArrangement =
[Link]) {
Text("Question ${currentIndex + 1}/$totalQuestions", color =
[Link])
Text([Link], style = [Link])
Spacer(modifier = [Link]([Link]))
[Link] { index, option ->
val optionColor = when {
isSubmitted && index == [Link] -> Color(0xFF4CAF50)
isSubmitted && selectedIndex == index -> Color(0xFFD32F2F)
else -> [Link]
}
Row(verticalAlignment = [Link], modifier =
[Link]().padding(vertical = [Link])) {
RadioButton(
selected = selectedIndex == index,
onClick = { if (!isSubmitted) selectedIndex = index },
enabled = !isSubmitted,
colors = [Link](
selectedColor = optionColor,
disabledSelectedColor = optionColor
)
)
Text(option, color = optionColor, modifier = [Link](start = [Link]))
}
}
Spacer(modifier = [Link]([Link]))
if (!isSubmitted) {
Button(
onClick = { isSubmitted = true; onAnswerSelected(selectedIndex!!) },
enabled = selectedIndex != null,
modifier = [Link]()
) { Text("Submit Answer") }
} else {
Button(onClick = onNext, modifier = [Link]()) {
Text(if (currentIndex + 1 == totalQuestions) "See Results" else "Next Question")
}
}
}
}
@Composable
fun ResultScreen(name: String, id: String, score: Int, totalQuestions: Int, onRestart: () -> Unit) {
Column(
modifier = [Link]().padding([Link]),
verticalArrangement = [Link],
horizontalAlignment = [Link]
){
Text("Quiz Finished!", style = [Link])
Spacer(modifier = [Link]([Link]))
Text("Student: $name", style = [Link])
Text("ID: $id", style = [Link])
Spacer(modifier = [Link]([Link]))
Text("Final Score: $score / $totalQuestions",
style = [Link],
color = if (score >= totalQuestions / 2) Color(0xFF4CAF50) else Color(0xFFD32F2F)
)
Spacer(modifier = [Link]([Link]))
Button(onClick = onRestart) {
Text("Restart App")
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[Link]
xmlns:tools="[Link]
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@android:style/[Link]"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@android:style/[Link]">
<intent-filter>
<action android:name="[Link]" />
<category android:name="[Link]" />
</intent-filter>
</activity>
</application>
</manifest>
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link].material3.*
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
data class Question(
val question: String,
val options: List<String>,
val correctAnswerIndex: Int,
val course: String
)
data class QuizResult(
val name: String,
val studentId: String,
val course: String,
val score: Int,
val total: Int
)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
QuizAppTheme {
QuizApp()
}
}
}
}
@Composable
fun QuizAppTheme(content: @Composable () -> Unit) {
val colors = lightColorScheme(
primary = Color(0xFF0D47A1),
secondary = Color(0xFF1976D2),
background = Color(0xFFE3F2FD),
surface = [Link]
)
MaterialTheme(colorScheme = colors, content = content)
}
@Composable
fun QuizApp() {
var userName by remember { mutableStateOf("") }
var studentId by remember { mutableStateOf("") }
var selectedCourse by remember { mutableStateOf("") }
var isRegistered by remember { mutableStateOf(false) }
var currentIndex by remember { mutableStateOf(0) }
var isFinished by remember { mutableStateOf(false) }
// Global Timer State (180 seconds = 3 minutes)
var totalTimeLeft by remember { mutableIntStateOf(180) }
val quizHistory = remember { mutableStateListOf<QuizResult>() }
val allQuestions = remember {
listOf(
// OOP
Question("Which concept allows a class to inherit properties from another?",
listOf("Encapsulation", "Inheritance", "Polymorphism", "Abstraction"), 1, "OOP"),
Question("In Java/Kotlin, what is used to create an instance of a class?", listOf("class",
"object", "new", "this"), 2, "OOP"),
Question("Which principle hides internal state?", listOf("Inheritance", "Interface",
"Encapsulation", "Polymorphism"), 2, "OOP"),
Question("What is a blueprint for creating objects?", listOf("Method", "Class", "Variable",
"Package"), 1, "OOP"),
Question("Two methods with same name but different parameters:", listOf("Overriding",
"Inheriting", "Overloading", "Abstaction"), 2, "OOP"),
Question("Class that cannot be instantiated:", listOf("Static", "Final", "Abstract", "Public"),
2, "OOP"),
Question("Keyword to access parent constructor:", listOf("this", "parent", "super", "base"),
2, "OOP"),
Question("Providing specific implementation of parent method:", listOf("Overloading",
"Overriding", "Inheritance", "Construction"), 1, "OOP"),
Question("Relationship represented by Inheritance:", listOf("Has-A", "Is-A", "Part-Of", "Uses-
A"), 1, "OOP"),
Question("Class having multiple forms:", listOf("Polymorphism", "Encapsulation",
"Inheritance", "Static binding"), 0, "OOP"),
// Database
Question("Command to remove all records without deleting table structure?",
listOf("DELETE", "DROP", "TRUNCATE", "REMOVE"), 2, "Database"),
Question("What does ACID stand for?", listOf("Atomicity, Consistency, Isolation, Durability",
"Access, Control, Integrity, Data", "Array, Code, Index, Disk", "None"), 0, "Database"),
Question("Uniquely identifies a record in a table:", listOf("Foreign Key", "Unique Key",
"Primary Key", "Index"), 2, "Database"),
Question("Clause used to filter results:", listOf("ORDER BY", "WHERE", "GROUP BY",
"SELECT"), 1, "Database"),
Question("Reducing data redundancy:", listOf("Normalization", "Indexing", "Caching",
"Sharding"), 0, "Database"),
Question("Command to add data:", listOf("ADD", "UPDATE", "INSERT INTO", "CREATE"), 2,
"Database"),
Question("Column linking to Primary Key in another table:", listOf("Master Key", "Foreign
Key", "Link Key", "Secondary Key"), 1, "Database"),
Question("Operator to search for pattern:", listOf("GET", "LIKE", "SEARCH", "MATCH"), 1,
"Database"),
Question("Default port for MySQL:", listOf("5432", "3306", "1433", "8080"), 1, "Database"),
Question("Command saving all changes:", listOf("SAVE", "COMMIT", "ROLLBACK",
"FINISH"), 1, "Database"),
// IP-Address
Question("Bit length of IPv4?", listOf("16 bits", "32 bits", "64 bits", "128 bits"), 1, "IP-
Address"),
Question("Private IP address range:", listOf("[Link]", "[Link]", "[Link]",
"[Link]"), 1, "IP-Address"),
Question("Bits in an IPv6 address?", listOf("32 bits", "64 bits", "128 bits", "256 bits"), 2, "IP-
Address"),
Question("Class of IP [Link]?", listOf("Class A", "Class B", "Class C", "Class D"), 0, "IP-
Address"),
Question("Subnet mask for Class C:", listOf("[Link]", "[Link]", "[Link]",
"[Link]"), 2, "IP-Address"),
Question("Purpose of DHCP:", listOf("File transfer", "Email", "Dynamic IP assignment", "Web
hosting"), 2, "IP-Address"),
Question("Loopback IP address:", listOf("[Link]", "[Link]", "[Link]",
"[Link]"), 0, "IP-Address"),
Question("Protocol resolving IP to MAC:", listOf("DNS", "ARP", "DHCP", "ICMP"), 1, "IP-
Address"),
Question("Used to mask internal network IP:", listOf("NAT", "RIP", "OSPF", "HTTP"), 0, "IP-
Address"),
Question("In /24 CIDR, how many IPs?", listOf("64", "128", "256", "512"), 2, "IP-Address")
)
}
val filteredQuestions = remember(selectedCourse) {
[Link] { [Link] == selectedCourse }
}
val selectedAnswers = remember { mutableStateMapOf<Int, Int>() }
// Timer Logic: Starts only when isRegistered is true and not finished
LaunchedEffect(isRegistered, isFinished) {
if (isRegistered && !isFinished) {
while (totalTimeLeft > 0) {
delay(1000L)
totalTimeLeft--
}
isFinished = true // Auto-finish when time is up
}
}
Surface(modifier = [Link](), color = [Link]) {
when {
!isRegistered -> {
RegistrationScreen(quizHistory) { name, id, course ->
userName = name
studentId = id
selectedCourse = course
totalTimeLeft = 180 // Reset timer for new exam
isRegistered = true
}
}
isFinished -> {
val finalScore = [Link] { selectedAnswers[it] ==
filteredQuestions[it].correctAnswerIndex }
LaunchedEffect(Unit) {
[Link](QuizResult(userName, studentId, selectedCourse, finalScore,
[Link]))
}
ResultScreen(userName, studentId, finalScore, filteredQuestions, selectedAnswers) {
currentIndex = 0
[Link]()
isFinished = false
isRegistered = false
selectedCourse = ""
}
}
else -> {
QuestionScreen(
question = filteredQuestions[currentIndex],
currentIndex = currentIndex,
totalQuestions = [Link],
savedAnswer = selectedAnswers[currentIndex],
timeLeft = totalTimeLeft, // Pass global time
onAnswerSelected = { selectedAnswers[currentIndex] = it },
onNext = {
if (currentIndex + 1 >= [Link]) isFinished = true
else currentIndex++
},
onPrevious = {
if (currentIndex > 0) currentIndex--
}
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RegistrationScreen(history: List<QuizResult>, onStartQuiz: (String, String, String) -> Unit) {
var name by remember { mutableStateOf("") }
var idInput by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
var selectedCourse by remember { mutableStateOf("") }
val courses = listOf("Database", "IP-Address", "OOP")
Column(
modifier = [Link]().padding([Link]).verticalScroll(rememberScrollState()),
horizontalAlignment = [Link]
){
Text(
text = "Dilla College Of Education",
style = [Link],
fontWeight = [Link],
color = Color(0xFF0D47A1),
textAlign = [Link],
modifier = [Link]()
)
Spacer(modifier = [Link]([Link]))
Image(
painter = painterResource(id = [Link]),
contentDescription = "Logo",
modifier = [Link]([Link]).clip(CircleShape)
)
Spacer(modifier = [Link]([Link]))
Text("Online Exam Training App", style = [Link])
Card(modifier = [Link]().padding(vertical = [Link]), shape =
RoundedCornerShape([Link])) {
Column(modifier = [Link]([Link])) {
OutlinedTextField(value = name, onValueChange = { name = it }, label = { Text("Full
Name") }, modifier = [Link]())
Spacer(modifier = [Link]([Link]))
OutlinedTextField(value = idInput, onValueChange = { idInput = it }, label = {
Text("Student ID") }, modifier = [Link](), keyboardOptions =
KeyboardOptions(keyboardType = [Link]))
Spacer(modifier = [Link]([Link]))
ExposedDropdownMenuBox(expanded = expanded, onExpandedChange = { expanded
= !expanded }) {
OutlinedTextField(
value = selectedCourse,
onValueChange = {},
readOnly = true,
label = { Text("Select Course") },
trailingIcon = { [Link](expanded =
expanded) },
modifier = [Link]().fillMaxWidth()
)
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded =
false }) {
[Link] { course ->
DropdownMenuItem(text = { Text(course) }, onClick = { selectedCourse =
course; expanded = false })
}
}
}
Spacer(modifier = [Link]([Link]))
Button(
onClick = { onStartQuiz(name, idInput, selectedCourse) },
enabled = [Link]() && [Link]() &&
[Link](),
modifier = [Link]()
){
Text("Start Exam")
}
}
}
if ([Link]()) {
Text("Recent Results History", fontWeight = [Link], modifier =
[Link]([Link]))
[Link]().forEach { result ->
Card(modifier = [Link]().padding(vertical = [Link]), colors =
[Link](containerColor = [Link])) {
Row(modifier = [Link]([Link]), verticalAlignment =
[Link]) {
Column(modifier = [Link](1f)) {
Text([Link], fontWeight = [Link])
Text("ID: ${[Link]}", fontSize = [Link])
}
Text("${[Link]}/${[Link]}", color =
[Link], fontWeight = [Link])
}
}
}
}
}
}
@Composable
fun QuestionScreen(
question: Question,
currentIndex: Int,
totalQuestions: Int,
savedAnswer: Int?,
timeLeft: Int, // Received from QuizApp
onAnswerSelected: (Int) -> Unit,
onNext: () -> Unit,
onPrevious: () -> Unit
){
// Format seconds to MM:SS
val minutes = timeLeft / 60
val seconds = timeLeft % 60
val timeFormatted = [Link]("%02d:%02d", minutes, seconds)
Column(modifier = [Link]().padding([Link])) {
Row(modifier = [Link](), horizontalArrangement =
[Link]) {
Text("${[Link]} Exam", color = [Link], fontWeight
= [Link])
Text(timeFormatted, color = if (timeLeft < 30) [Link] else [Link], fontWeight =
[Link])
}
LinearProgressIndicator(progress = { (currentIndex + 1).toFloat() / totalQuestions }, modifier
= [Link]().padding(vertical = [Link]))
Text("Question ${currentIndex + 1} of $totalQuestions", fontSize = [Link])
Spacer(modifier = [Link]([Link]))
Text([Link], style = [Link])
Spacer(modifier = [Link]([Link]))
[Link] { index, option ->
Surface(
onClick = { onAnswerSelected(index) },
color = if (savedAnswer == index) [Link](alpha =
0.15f) else [Link],
shape = RoundedCornerShape([Link]),
modifier = [Link]().padding(vertical = [Link])
){
Row(verticalAlignment = [Link], modifier =
[Link]([Link])) {
RadioButton(selected = savedAnswer == index, onClick = {
onAnswerSelected(index) })
Text(option, modifier = [Link](start = [Link]))
}
}
}
Spacer(modifier = [Link](1f))
Row(modifier = [Link](), horizontalArrangement =
[Link]([Link])) {
OutlinedButton(onClick = onPrevious, enabled = currentIndex > 0, modifier =
[Link](1f)) { Text("Back") }
Button(onClick = onNext, enabled = savedAnswer != null, modifier = [Link](1f))
{
Text(if (currentIndex + 1 == totalQuestions) "Finish" else "Next")
}
}
}
}
@Composable
fun ResultScreen(
name: String,
id: String,
score: Int,
questions: List<Question>,
userAnswers: Map<Int, Int>,
onRestart: () -> Unit
){
Column(
modifier = [Link]().padding([Link]).verticalScroll(rememberScrollState()),
horizontalAlignment = [Link]
){
Spacer(modifier = [Link]([Link]))
Text("Exam Result", style = [Link], fontWeight =
[Link])
Text("Student: $name (ID: $id)")
Text(
text = "$score / ${[Link]}",
fontSize = [Link],
fontWeight = [Link],
color = Color(0xFF0D47A1),
modifier = [Link](vertical = [Link])
)
val pass = ([Link]() / [Link]) >= 0.5
Text(
if (pass) "PASSED" else "FAILED",
color = if (pass) Color(0xFF2E7D32) else [Link],
fontWeight = [Link]
)
Spacer(modifier = [Link]([Link]))
Divider()
Text("Question Review", style = [Link], modifier =
[Link](vertical = [Link]))
[Link] { index, q ->
val selected = userAnswers[index]
val isCorrect = selected == [Link]
Card(
modifier = [Link]().padding(vertical = [Link]),
colors = [Link](
containerColor = if (isCorrect) Color(0xFFE8F5E9) else Color(0xFFFFEBEE)
)
){
Column(modifier = [Link]([Link])) {
Text("Q${index + 1}: ${[Link]}", fontWeight = [Link])
Spacer(modifier = [Link]([Link]))
Text("Your Answer: ${if (selected != null) [Link][selected] else "No Answer"}",
color = if (isCorrect) Color(0xFF2E7D32) else [Link])
if (!isCorrect) {
Text("Correct Answer: ${[Link][[Link]]}", fontWeight =
[Link])
}
}
}
}
Spacer(modifier = [Link]([Link]))
Button(onClick = onRestart, modifier = [Link]()) { Text("Back to Home") }
Spacer(modifier = [Link]([Link]))
}
}
manfest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[Link]
xmlns:tools="[Link]
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@android:style/[Link]"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@android:style/[Link]">
<intent-filter>
<action android:name="[Link]" />
<category android:name="[Link]" />
</intent-filter>
</activity>
</application>
</manifest>