Skip to content

Commit 3ed1d99

Browse files
Extend quiz with reminders and results
1 parent 4dcb334 commit 3ed1d99

File tree

10 files changed

+188
-1
lines changed

10 files changed

+188
-1
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@
327327
android:label="@string/quiz_title"
328328
android:parentActivityName=".ui.screens.quiz.QuizActivity" />
329329

330+
<receiver
331+
android:name=".notifications.receivers.QuizReminderReceiver"
332+
android:exported="false" />
333+
330334
<service
331335
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
332336
android:enabled="false"

app/src/main/assets/quiz_questions.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,20 @@
88
"question": "Which file declares your app's activities?",
99
"options": ["build.gradle", "AndroidManifest.xml", "strings.xml", "MainActivity.java"],
1010
"answer": 1
11+
},
12+
{
13+
"question": "Where do you store string resources?",
14+
"options": ["AndroidManifest.xml", "build.gradle", "strings.xml", "colors.xml"],
15+
"answer": 2
16+
},
17+
{
18+
"question": "Which layout allows positioning views relative to others?",
19+
"options": ["LinearLayout", "ConstraintLayout", "FrameLayout", "TableLayout"],
20+
"answer": 1
21+
},
22+
{
23+
"question": "What component shows a scrollable list of items?",
24+
"options": ["RecyclerView", "TextView", "ImageView", "Button"],
25+
"answer": 0
1126
}
1227
]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.d4rk.androidtutorials.java.notifications.managers;
2+
3+
import android.app.AlarmManager;
4+
import android.app.PendingIntent;
5+
import android.content.Context;
6+
import android.content.Intent;
7+
8+
import com.d4rk.androidtutorials.java.notifications.receivers.QuizReminderReceiver;
9+
10+
import java.util.concurrent.TimeUnit;
11+
12+
/**
13+
* Utility for scheduling daily quiz reminder notifications.
14+
*/
15+
public class QuizReminderManager {
16+
17+
private final AlarmManager alarmManager;
18+
private final PendingIntent reminderIntent;
19+
20+
public QuizReminderManager(Context context) {
21+
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
22+
reminderIntent = PendingIntent.getBroadcast(
23+
context,
24+
1,
25+
new Intent(context, QuizReminderReceiver.class),
26+
PendingIntent.FLAG_IMMUTABLE
27+
);
28+
}
29+
30+
/** Schedule a repeating daily reminder. */
31+
public void scheduleDailyReminder() {
32+
long trigger = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
33+
alarmManager.setRepeating(
34+
AlarmManager.RTC_WAKEUP,
35+
trigger,
36+
TimeUnit.DAYS.toMillis(1),
37+
reminderIntent
38+
);
39+
}
40+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.d4rk.androidtutorials.java.notifications.receivers;
2+
3+
import android.content.BroadcastReceiver;
4+
import android.content.Context;
5+
import android.content.Intent;
6+
7+
import androidx.work.OneTimeWorkRequest;
8+
import androidx.work.WorkManager;
9+
10+
import com.d4rk.androidtutorials.java.notifications.workers.QuizReminderWorker;
11+
12+
/**
13+
* BroadcastReceiver that enqueues a {@link QuizReminderWorker}.
14+
*/
15+
public class QuizReminderReceiver extends BroadcastReceiver {
16+
@Override
17+
public void onReceive(Context context, Intent intent) {
18+
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(
19+
QuizReminderWorker.class)
20+
.build();
21+
WorkManager.getInstance(context).enqueue(request);
22+
}
23+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.d4rk.androidtutorials.java.notifications.workers;
2+
3+
import android.app.NotificationChannel;
4+
import android.app.NotificationManager;
5+
import android.app.PendingIntent;
6+
import android.content.Context;
7+
import android.content.Intent;
8+
import android.os.Build;
9+
10+
import androidx.annotation.NonNull;
11+
import androidx.annotation.RequiresApi;
12+
import androidx.core.app.NotificationCompat;
13+
import androidx.work.Worker;
14+
import androidx.work.WorkerParameters;
15+
16+
import com.d4rk.androidtutorials.java.R;
17+
import com.d4rk.androidtutorials.java.ui.screens.quiz.QuizActivity;
18+
19+
/**
20+
* Worker that displays the daily quiz reminder notification.
21+
*/
22+
public class QuizReminderWorker extends Worker {
23+
24+
public QuizReminderWorker(@NonNull Context context, @NonNull WorkerParameters params) {
25+
super(context, params);
26+
}
27+
28+
@RequiresApi(api = Build.VERSION_CODES.O)
29+
@NonNull
30+
@Override
31+
public Result doWork() {
32+
NotificationManager manager = (NotificationManager) getApplicationContext()
33+
.getSystemService(Context.NOTIFICATION_SERVICE);
34+
String channelId = "quiz_reminder_channel";
35+
NotificationChannel channel = new NotificationChannel(
36+
channelId,
37+
getApplicationContext().getString(R.string.quiz_reminder_title),
38+
NotificationManager.IMPORTANCE_HIGH
39+
);
40+
manager.createNotificationChannel(channel);
41+
42+
Intent intent = new Intent(getApplicationContext(), QuizActivity.class);
43+
PendingIntent pendingIntent = PendingIntent.getActivity(
44+
getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
45+
46+
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), channelId)
47+
.setSmallIcon(R.drawable.ic_check_circle)
48+
.setContentTitle(getApplicationContext().getString(R.string.quiz_reminder_title))
49+
.setContentText(getApplicationContext().getString(R.string.quiz_reminder_body))
50+
.setAutoCancel(true)
51+
.setContentIntent(pendingIntent);
52+
53+
manager.notify(1001, builder.build());
54+
return Result.success();
55+
}
56+
}

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainActivity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.d4rk.androidtutorials.java.databinding.ActivityMainBinding;
3232
import com.d4rk.androidtutorials.java.notifications.managers.AppUpdateNotificationsManager;
3333
import com.d4rk.androidtutorials.java.notifications.managers.AppUsageNotificationsManager;
34+
import com.d4rk.androidtutorials.java.notifications.managers.QuizReminderManager;
3435
import com.d4rk.androidtutorials.java.ui.components.navigation.BottomSheetMenuFragment;
3536
import com.d4rk.androidtutorials.java.ui.screens.startup.StartupActivity;
3637
import com.d4rk.androidtutorials.java.ui.screens.startup.StartupViewModel;
@@ -258,6 +259,8 @@ protected void onResume() {
258259
}
259260
AppUsageNotificationsManager appUsageNotificationsManager = new AppUsageNotificationsManager(this);
260261
appUsageNotificationsManager.scheduleAppUsageCheck();
262+
QuizReminderManager quizReminderManager = new QuizReminderManager(this);
263+
quizReminderManager.scheduleDailyReminder();
261264
appUpdateNotificationsManager.checkAndSendUpdateNotification();
262265
checkForImmediateUpdate();
263266
}

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/QuizActivity.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
import com.d4rk.androidtutorials.java.databinding.ActivityQuizBinding;
1414
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
1515
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
16+
import android.view.LayoutInflater;
17+
import android.view.View;
18+
import android.widget.TextView;
19+
import com.airbnb.lottie.LottieAnimationView;
1620

1721
/**
1822
* Activity that displays a simple multiple-choice quiz.
@@ -37,6 +41,14 @@ protected void onCreate(Bundle savedInstanceState) {
3741
}
3842

3943
viewModel = new ViewModelProvider(this).get(QuizViewModel.class);
44+
if (viewModel.getTotalQuestions() == 0) {
45+
new MaterialAlertDialogBuilder(this)
46+
.setMessage(R.string.quiz_no_more_questions)
47+
.setPositiveButton(android.R.string.ok, (d, w) -> finish())
48+
.setCancelable(false)
49+
.show();
50+
return;
51+
}
4052
showQuestion(viewModel.getCurrentQuestion());
4153

4254
binding.buttonNext.setOnClickListener(v -> onNextClicked());
@@ -79,8 +91,13 @@ private void showQuestion(QuizQuestion question) {
7991
private void showResult() {
8092
int score = viewModel.getScore().getValue();
8193
int total = viewModel.getTotalQuestions();
94+
View view = LayoutInflater.from(this).inflate(R.layout.dialog_quiz_result, null, false);
95+
TextView textResult = view.findViewById(R.id.text_result);
96+
textResult.setText(getString(R.string.quiz_finished, score, total));
97+
LottieAnimationView animationView = view.findViewById(R.id.animation_success);
98+
animationView.playAnimation();
8299
new MaterialAlertDialogBuilder(this)
83-
.setMessage(getString(R.string.quiz_finished, score, total))
100+
.setView(view)
84101
.setPositiveButton(android.R.string.ok, (d, w) -> finish())
85102
.setCancelable(false)
86103
.show();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:orientation="vertical"
7+
android:padding="16dp">
8+
9+
<com.airbnb.lottie.LottieAnimationView
10+
android:id="@+id/animation_success"
11+
android:layout_width="96dp"
12+
android:layout_height="96dp"
13+
android:layout_gravity="center_horizontal"
14+
app:lottie_autoPlay="true"
15+
app:lottie_loop="false"
16+
app:lottie_rawRes="@raw/anim_quiz_success" />
17+
18+
<TextView
19+
android:id="@+id/text_result"
20+
android:layout_width="wrap_content"
21+
android:layout_height="wrap_content"
22+
android:layout_gravity="center_horizontal"
23+
android:layout_marginTop="8dp"
24+
android:textAppearance="@style/TextAppearance.Material3.BodyMedium" />
25+
</LinearLayout>

app/src/main/res/raw/anim_quiz_success.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,5 +438,8 @@
438438
<string name="quiz_title">Quiz</string>
439439
<string name="next_question">Next Question</string>
440440
<string name="quiz_finished">Quiz complete! Your score: %1$d/%2$d</string>
441+
<string name="quiz_no_more_questions">No more questions, check further updates for more.</string>
442+
<string name="quiz_reminder_title">Daily Quiz Reminder</string>
443+
<string name="quiz_reminder_body">Come back for today&#39;s quiz!</string>
441444
<string name="other_apps_title">More apps by the developer</string>
442445
</resources>

0 commit comments

Comments
 (0)