mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-30 22:34:02 +01:00 
			
		
		
		
	Migrated quiz module from Java to Kotlin (#5952)
* Rename .java to .kt * Migrated quiz module to Kotlin * unit test failing fixed * unit test failing fixed
This commit is contained in:
		
							parent
							
								
									bafae821e2
								
							
						
					
					
						commit
						00cfd83521
					
				
					 10 changed files with 658 additions and 628 deletions
				
			
		|  | @ -1,146 +0,0 @@ | |||
| package fr.free.nrw.commons.quiz; | ||||
| 
 | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| 
 | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; | ||||
| 
 | ||||
| import com.facebook.drawee.drawable.ProgressBarDrawable; | ||||
| import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; | ||||
| 
 | ||||
| import fr.free.nrw.commons.databinding.ActivityQuizBinding; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import fr.free.nrw.commons.R; | ||||
| 
 | ||||
| public class QuizActivity extends AppCompatActivity { | ||||
| 
 | ||||
|     private ActivityQuizBinding binding; | ||||
|     private final QuizController quizController = new QuizController(); | ||||
|     private ArrayList<QuizQuestion> quiz = new ArrayList<>(); | ||||
|     private int questionIndex = 0; | ||||
|     private int score; | ||||
|     /** | ||||
|      * isPositiveAnswerChecked : represents yes click event | ||||
|      */ | ||||
|     private boolean isPositiveAnswerChecked; | ||||
|     /** | ||||
|      * isNegativeAnswerChecked : represents no click event | ||||
|      */ | ||||
|     private boolean isNegativeAnswerChecked; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         binding = ActivityQuizBinding.inflate(getLayoutInflater()); | ||||
|         setContentView(binding.getRoot()); | ||||
| 
 | ||||
|         quizController.initialize(this); | ||||
|         setSupportActionBar(binding.toolbar.toolbar); | ||||
|         binding.nextButton.setOnClickListener(view -> notKnowAnswer()); | ||||
|         displayQuestion(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to move to next question and check whether answer is selected or not | ||||
|      */ | ||||
|     public void setNextQuestion(){ | ||||
|         if ( questionIndex <= quiz.size() && (isPositiveAnswerChecked || isNegativeAnswerChecked)) { | ||||
|             evaluateScore(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void notKnowAnswer(){ | ||||
|         customAlert("Information", quiz.get(questionIndex).getAnswerMessage()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to give warning before ending quiz | ||||
|      */ | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         new AlertDialog.Builder(this) | ||||
|             .setTitle(getResources().getString(R.string.warning)) | ||||
|             .setMessage(getResources().getString(R.string.quiz_back_button)) | ||||
|             .setPositiveButton(R.string.continue_message, (dialog, which) -> { | ||||
|                 final Intent intent = new Intent(this, QuizResultActivity.class); | ||||
|                 dialog.dismiss(); | ||||
|                 intent.putExtra("QuizResult", score); | ||||
|                 startActivity(intent); | ||||
|             }) | ||||
|             .setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.dismiss()) | ||||
|             .create() | ||||
|             .show(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to display the question | ||||
|      */ | ||||
|     public void displayQuestion() { | ||||
|         quiz = quizController.getQuiz(); | ||||
|         binding.question.questionText.setText(quiz.get(questionIndex).getQuestion()); | ||||
|         binding.questionTitle.setText( | ||||
|             getResources().getString(R.string.question) + | ||||
|                 quiz.get(questionIndex).getQuestionNumber() | ||||
|         ); | ||||
|         binding.question.questionImage.setHierarchy(GenericDraweeHierarchyBuilder | ||||
|                 .newInstance(getResources()) | ||||
|                 .setFailureImage(VectorDrawableCompat.create(getResources(), | ||||
|                         R.drawable.ic_error_outline_black_24dp, getTheme())) | ||||
|                 .setProgressBarImage(new ProgressBarDrawable()) | ||||
|                 .build()); | ||||
| 
 | ||||
|         binding.question.questionImage.setImageURI(quiz.get(questionIndex).getUrl()); | ||||
|         isPositiveAnswerChecked = false; | ||||
|         isNegativeAnswerChecked = false; | ||||
|         binding.answer.quizPositiveAnswer.setOnClickListener(view -> { | ||||
|             isPositiveAnswerChecked = true; | ||||
|             setNextQuestion(); | ||||
|         }); | ||||
|         binding.answer.quizNegativeAnswer.setOnClickListener(view -> { | ||||
|             isNegativeAnswerChecked = true; | ||||
|             setNextQuestion(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to evaluate score and check whether answer is correct or wrong | ||||
|      */ | ||||
|     public void evaluateScore() { | ||||
|         if ((quiz.get(questionIndex).isAnswer() && isPositiveAnswerChecked) || | ||||
|                 (!quiz.get(questionIndex).isAnswer() && isNegativeAnswerChecked) ){ | ||||
|             customAlert(getResources().getString(R.string.correct), | ||||
|                 quiz.get(questionIndex).getAnswerMessage()); | ||||
|             score++; | ||||
|         } else { | ||||
|             customAlert(getResources().getString(R.string.wrong), | ||||
|                 quiz.get(questionIndex).getAnswerMessage()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to display explanation after each answer, update questionIndex and move to next question | ||||
|      * @param title the alert title | ||||
|      * @param Message the alert message | ||||
|      */ | ||||
|     public void customAlert(final String title, final String Message) { | ||||
|         new AlertDialog.Builder(this) | ||||
|             .setTitle(title) | ||||
|             .setMessage(Message) | ||||
|             .setPositiveButton(R.string.continue_message, (dialog, which) -> { | ||||
|                 questionIndex++; | ||||
|                 if (questionIndex == quiz.size()) { | ||||
|                     final Intent intent = new Intent(this, QuizResultActivity.class); | ||||
|                     dialog.dismiss(); | ||||
|                     intent.putExtra("QuizResult", score); | ||||
|                     startActivity(intent); | ||||
|                 } else { | ||||
|                     displayQuestion(); | ||||
|                 } | ||||
|             }) | ||||
|             .create() | ||||
|             .show(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										154
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizActivity.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,154 @@ | |||
| package fr.free.nrw.commons.quiz | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Intent | ||||
| import android.os.Bundle | ||||
| 
 | ||||
| import androidx.appcompat.app.AlertDialog | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat | ||||
| 
 | ||||
| import com.facebook.drawee.drawable.ProgressBarDrawable | ||||
| import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder | ||||
| 
 | ||||
| import fr.free.nrw.commons.databinding.ActivityQuizBinding | ||||
| import java.util.ArrayList | ||||
| 
 | ||||
| import fr.free.nrw.commons.R | ||||
| 
 | ||||
| 
 | ||||
| class QuizActivity : AppCompatActivity() { | ||||
| 
 | ||||
|     private lateinit var binding: ActivityQuizBinding | ||||
|     private val quizController = QuizController() | ||||
|     private var quiz = ArrayList<QuizQuestion>() | ||||
|     private var questionIndex = 0 | ||||
|     private var score = 0 | ||||
| 
 | ||||
|     /** | ||||
|      * isPositiveAnswerChecked : represents yes click event | ||||
|      */ | ||||
|     private var isPositiveAnswerChecked = false | ||||
| 
 | ||||
|     /** | ||||
|      * isNegativeAnswerChecked : represents no click event | ||||
|      */ | ||||
|     private var isNegativeAnswerChecked = false | ||||
| 
 | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|         binding = ActivityQuizBinding.inflate(layoutInflater) | ||||
|         setContentView(binding.root) | ||||
| 
 | ||||
|         quizController.initialize(this) | ||||
|         setSupportActionBar(binding.toolbar.toolbar) | ||||
|         binding.nextButton.setOnClickListener { notKnowAnswer() } | ||||
|         displayQuestion() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To move to next question and check whether answer is selected or not | ||||
|      */ | ||||
|     fun setNextQuestion() { | ||||
|         if (questionIndex <= quiz.size && (isPositiveAnswerChecked || isNegativeAnswerChecked)) { | ||||
|             evaluateScore() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun notKnowAnswer() { | ||||
|         customAlert("Information", quiz[questionIndex].answerMessage) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To give warning before ending quiz | ||||
|      */ | ||||
|     override fun onBackPressed() { | ||||
|         AlertDialog.Builder(this) | ||||
|             .setTitle(getString(R.string.warning)) | ||||
|             .setMessage(getString(R.string.quiz_back_button)) | ||||
|             .setPositiveButton(R.string.continue_message) { dialog, _ -> | ||||
|                 val intent = Intent(this, QuizResultActivity::class.java) | ||||
|                 dialog.dismiss() | ||||
|                 intent.putExtra("QuizResult", score) | ||||
|                 startActivity(intent) | ||||
|             } | ||||
|             .setNegativeButton("Cancel") { dialogInterface, _ -> dialogInterface.dismiss() } | ||||
|             .create() | ||||
|             .show() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To display the question | ||||
|      */ | ||||
|     @SuppressLint("SetTextI18n") | ||||
|     private fun displayQuestion() { | ||||
|         quiz = quizController.getQuiz() | ||||
|         binding.question.questionText.text = quiz[questionIndex].question | ||||
|         binding.questionTitle.text = getString(R.string.question) + quiz[questionIndex].questionNumber | ||||
| 
 | ||||
|         binding.question.questionImage.hierarchy = GenericDraweeHierarchyBuilder | ||||
|             .newInstance(resources) | ||||
|             .setFailureImage(VectorDrawableCompat.create(resources, R.drawable.ic_error_outline_black_24dp, theme)) | ||||
|             .setProgressBarImage(ProgressBarDrawable()) | ||||
|             .build() | ||||
| 
 | ||||
|         binding.question.questionImage.setImageURI(quiz[questionIndex].getUrl()) | ||||
|         isPositiveAnswerChecked = false | ||||
|         isNegativeAnswerChecked = false | ||||
| 
 | ||||
|         binding.answer.quizPositiveAnswer.setOnClickListener { | ||||
|             isPositiveAnswerChecked = true | ||||
|             setNextQuestion() | ||||
|         } | ||||
|         binding.answer.quizNegativeAnswer.setOnClickListener { | ||||
|             isNegativeAnswerChecked = true | ||||
|             setNextQuestion() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To evaluate score and check whether answer is correct or wrong | ||||
|      */ | ||||
|     fun evaluateScore() { | ||||
|         if ( | ||||
|             (quiz[questionIndex].isAnswer && isPositiveAnswerChecked) | ||||
|                 || | ||||
|             (!quiz[questionIndex].isAnswer && isNegativeAnswerChecked) | ||||
|             ) { | ||||
|             customAlert( | ||||
|                 getString(R.string.correct), | ||||
|                 quiz[questionIndex].answerMessage | ||||
|             ) | ||||
|             score++ | ||||
|         } else { | ||||
|             customAlert( | ||||
|                 getString(R.string.wrong), | ||||
|                 quiz[questionIndex].answerMessage | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To display explanation after each answer, update questionIndex and move to next question | ||||
|      * @param title The alert title | ||||
|      * @param message The alert message | ||||
|      */ | ||||
|     fun customAlert(title: String, message: String) { | ||||
|         AlertDialog.Builder(this) | ||||
|             .setTitle(title) | ||||
|             .setMessage(message) | ||||
|             .setPositiveButton(R.string.continue_message) { dialog, _ -> | ||||
|                 questionIndex++ | ||||
|                 if (questionIndex == quiz.size) { | ||||
|                     val intent = Intent(this, QuizResultActivity::class.java) | ||||
|                     dialog.dismiss() | ||||
|                     intent.putExtra("QuizResult", score) | ||||
|                     startActivity(intent) | ||||
|                 } else { | ||||
|                     displayQuestion() | ||||
|                 } | ||||
|             } | ||||
|             .create() | ||||
|             .show() | ||||
|     } | ||||
| } | ||||
|  | @ -1,167 +0,0 @@ | |||
| package fr.free.nrw.commons.quiz; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| import javax.inject.Named; | ||||
| import javax.inject.Singleton; | ||||
| 
 | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.WelcomeActivity; | ||||
| import fr.free.nrw.commons.auth.SessionManager; | ||||
| import fr.free.nrw.commons.kvstore.JsonKvStore; | ||||
| import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient; | ||||
| import fr.free.nrw.commons.utils.DialogUtil; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  * fetches the number of images uploaded and number of images reverted. | ||||
|  * Then it calculates the percentage of the images reverted | ||||
|  * if the percentage of images reverted after last quiz exceeds 50% and number of images uploaded is | ||||
|  * greater than 50, then quiz is popped up | ||||
|  */ | ||||
| @Singleton | ||||
| public class QuizChecker { | ||||
| 
 | ||||
|     private int revertCount ; | ||||
|     private int totalUploadCount ; | ||||
|     private boolean isRevertCountFetched; | ||||
|     private boolean isUploadCountFetched; | ||||
| 
 | ||||
|     private CompositeDisposable compositeDisposable = new CompositeDisposable(); | ||||
| 
 | ||||
|     private final SessionManager sessionManager; | ||||
|     private final OkHttpJsonApiClient okHttpJsonApiClient; | ||||
|     private final JsonKvStore revertKvStore; | ||||
| 
 | ||||
|     private static final int UPLOAD_COUNT_THRESHOLD = 5; | ||||
|     private static final String REVERT_PERCENTAGE_FOR_MESSAGE = "50%"; | ||||
|     private final String REVERT_SHARED_PREFERENCE = "revertCount"; | ||||
|     private final String UPLOAD_SHARED_PREFERENCE = "uploadCount"; | ||||
| 
 | ||||
|     /** | ||||
|      * constructor to set the parameters for quiz | ||||
|      * @param sessionManager | ||||
|      * @param okHttpJsonApiClient | ||||
|      */ | ||||
|     @Inject | ||||
|     public QuizChecker(SessionManager sessionManager, | ||||
|                        OkHttpJsonApiClient okHttpJsonApiClient, | ||||
|                        @Named("default_preferences") JsonKvStore revertKvStore) { | ||||
|         this.sessionManager = sessionManager; | ||||
|         this.okHttpJsonApiClient = okHttpJsonApiClient; | ||||
|         this.revertKvStore = revertKvStore; | ||||
|     } | ||||
| 
 | ||||
|     public void initQuizCheck(Activity activity) { | ||||
|         calculateRevertParameterAndShowQuiz(activity); | ||||
|     } | ||||
| 
 | ||||
|     public void cleanup() { | ||||
|         compositeDisposable.clear(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to fet the total number of images uploaded | ||||
|      */ | ||||
|     private void setUploadCount() { | ||||
|         compositeDisposable.add(okHttpJsonApiClient | ||||
|                 .getUploadCount(sessionManager.getUserName()) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(this::setTotalUploadCount, | ||||
|                             t -> Timber.e(t, "Fetching upload count failed") | ||||
|                     )); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * set the sub Title of Contibutions Activity and | ||||
|      * call function to check for quiz | ||||
|      * @param uploadCount user's upload count | ||||
|      */ | ||||
|     private void setTotalUploadCount(int uploadCount) { | ||||
|         totalUploadCount = uploadCount - revertKvStore.getInt(UPLOAD_SHARED_PREFERENCE, 0); | ||||
|         if ( totalUploadCount < 0){ | ||||
|             totalUploadCount = 0; | ||||
|             revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0); | ||||
|         } | ||||
|         isUploadCountFetched = true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To call the API to get reverts count in form of JSONObject | ||||
|      */ | ||||
|     private void setRevertCount() { | ||||
|         compositeDisposable.add(okHttpJsonApiClient | ||||
|                 .getAchievements(sessionManager.getUserName()) | ||||
|                     .subscribeOn(Schedulers.io()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .subscribe( | ||||
|                             response -> { | ||||
|                                 if (response != null) { | ||||
|                                     setRevertParameter(response.getDeletedUploads()); | ||||
|                                 } | ||||
|                             }, throwable -> Timber.e(throwable, "Fetching feedback failed")) | ||||
|             ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to calculate the number of images reverted after previous quiz | ||||
|      * @param revertCountFetched count of deleted uploads | ||||
|      */ | ||||
|     private void setRevertParameter(int revertCountFetched) { | ||||
|         revertCount = revertCountFetched - revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0); | ||||
|         if (revertCount < 0){ | ||||
|             revertCount = 0; | ||||
|             revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0); | ||||
|         } | ||||
|         isRevertCountFetched = true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to check whether the criterion to call quiz is satisfied | ||||
|      */ | ||||
|     private void calculateRevertParameterAndShowQuiz(Activity activity) { | ||||
|         setUploadCount(); | ||||
|         setRevertCount(); | ||||
|         if ( revertCount < 0 || totalUploadCount < 0){ | ||||
|             revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0); | ||||
|             revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0); | ||||
|             return; | ||||
|         } | ||||
|         if (isRevertCountFetched && isUploadCountFetched && | ||||
|                 totalUploadCount >= UPLOAD_COUNT_THRESHOLD && | ||||
|                 (revertCount * 100) / totalUploadCount >= 50) { | ||||
|             callQuiz(activity); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Alert which prompts to quiz | ||||
|      */ | ||||
|     @SuppressLint("StringFormatInvalid") | ||||
|     private void callQuiz(Activity activity) { | ||||
|         DialogUtil.showAlertDialog(activity, | ||||
|                 activity.getString(R.string.quiz), | ||||
|                 activity.getString(R.string.quiz_alert_message, REVERT_PERCENTAGE_FOR_MESSAGE), | ||||
|                 activity.getString(R.string.about_translate_proceed), | ||||
|                 activity.getString(android.R.string.cancel), | ||||
|                 () -> startQuizActivity(activity), | ||||
|                 null); | ||||
|     } | ||||
| 
 | ||||
|     private void startQuizActivity(Activity activity) { | ||||
|         int newRevetSharedPrefs = revertCount + revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0); | ||||
|         revertKvStore.putInt(REVERT_SHARED_PREFERENCE, newRevetSharedPrefs); | ||||
|         int newUploadCount = totalUploadCount + revertKvStore.getInt(UPLOAD_SHARED_PREFERENCE, 0); | ||||
|         revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, newUploadCount); | ||||
|         Intent i = new Intent(activity, WelcomeActivity.class); | ||||
|         i.putExtra("isQuiz", true); | ||||
|         activity.startActivity(i); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										175
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,175 @@ | |||
| package fr.free.nrw.commons.quiz | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import android.app.Activity | ||||
| import android.content.Intent | ||||
| 
 | ||||
| import javax.inject.Inject | ||||
| import javax.inject.Named | ||||
| import javax.inject.Singleton | ||||
| 
 | ||||
| import fr.free.nrw.commons.R | ||||
| import fr.free.nrw.commons.WelcomeActivity | ||||
| import fr.free.nrw.commons.auth.SessionManager | ||||
| import fr.free.nrw.commons.kvstore.JsonKvStore | ||||
| import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient | ||||
| import fr.free.nrw.commons.utils.DialogUtil | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.disposables.CompositeDisposable | ||||
| import io.reactivex.schedulers.Schedulers | ||||
| import timber.log.Timber | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Fetches the number of images uploaded and number of images reverted. | ||||
|  * Then it calculates the percentage of the images reverted. | ||||
|  * If the percentage of images reverted after the last quiz exceeds 50% and number of images uploaded is | ||||
|  * greater than 50, then the quiz is popped up. | ||||
|  */ | ||||
| @Singleton | ||||
| class QuizChecker @Inject constructor( | ||||
|     private val sessionManager: SessionManager, | ||||
|     private val okHttpJsonApiClient: OkHttpJsonApiClient, | ||||
|     @Named("default_preferences") private val revertKvStore: JsonKvStore | ||||
| ) { | ||||
| 
 | ||||
|     private var revertCount = 0 | ||||
|     private var totalUploadCount = 0 | ||||
|     private var isRevertCountFetched = false | ||||
|     private var isUploadCountFetched = false | ||||
| 
 | ||||
|     private val compositeDisposable = CompositeDisposable() | ||||
| 
 | ||||
|     private val UPLOAD_COUNT_THRESHOLD = 5 | ||||
|     private val REVERT_PERCENTAGE_FOR_MESSAGE = "50%" | ||||
|     private val REVERT_SHARED_PREFERENCE = "revertCount" | ||||
|     private val UPLOAD_SHARED_PREFERENCE = "uploadCount" | ||||
| 
 | ||||
|     /** | ||||
|      * Initializes quiz check by calculating revert parameters and showing quiz if necessary | ||||
|      */ | ||||
|     fun initQuizCheck(activity: Activity) { | ||||
|         calculateRevertParameterAndShowQuiz(activity) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Clears disposables to avoid memory leaks | ||||
|      */ | ||||
|     fun cleanup() { | ||||
|         compositeDisposable.clear() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Fetches the total number of images uploaded | ||||
|      */ | ||||
|     private fun setUploadCount() { | ||||
|         compositeDisposable.add( | ||||
|             okHttpJsonApiClient.getUploadCount(sessionManager.userName) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe( | ||||
|                     { uploadCount -> setTotalUploadCount(uploadCount) }, | ||||
|                     { t -> Timber.e(t, "Fetching upload count failed") } | ||||
|                 ) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sets the total upload count after subtracting stored preference | ||||
|      * @param uploadCount User's upload count | ||||
|      */ | ||||
|     private fun setTotalUploadCount(uploadCount: Int) { | ||||
|         totalUploadCount = uploadCount - revertKvStore.getInt( | ||||
|             UPLOAD_SHARED_PREFERENCE, | ||||
|             0 | ||||
|         ) | ||||
|         if (totalUploadCount < 0) { | ||||
|             totalUploadCount = 0 | ||||
|             revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0) | ||||
|         } | ||||
|         isUploadCountFetched = true | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Fetches the revert count using the API | ||||
|      */ | ||||
|     private fun setRevertCount() { | ||||
|         compositeDisposable.add( | ||||
|             okHttpJsonApiClient.getAchievements(sessionManager.userName) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe( | ||||
|                     { response -> | ||||
|                         response?.let { setRevertParameter(it.deletedUploads) } | ||||
|                     }, | ||||
|                     { throwable -> Timber.e(throwable, "Fetching feedback failed") } | ||||
|                 ) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calculates the number of images reverted after the previous quiz | ||||
|      * @param revertCountFetched Count of deleted uploads | ||||
|      */ | ||||
|     private fun setRevertParameter(revertCountFetched: Int) { | ||||
|         revertCount = revertCountFetched - revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0) | ||||
|         if (revertCount < 0) { | ||||
|             revertCount = 0 | ||||
|             revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0) | ||||
|         } | ||||
|         isRevertCountFetched = true | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks whether the criteria for calling the quiz are satisfied | ||||
|      */ | ||||
|     private fun calculateRevertParameterAndShowQuiz(activity: Activity) { | ||||
|         setUploadCount() | ||||
|         setRevertCount() | ||||
| 
 | ||||
|         if (revertCount < 0 || totalUploadCount < 0) { | ||||
|             revertKvStore.putInt(REVERT_SHARED_PREFERENCE, 0) | ||||
|             revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, 0) | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         if (isRevertCountFetched && isUploadCountFetched && | ||||
|             totalUploadCount >= UPLOAD_COUNT_THRESHOLD && | ||||
|             (revertCount * 100) / totalUploadCount >= 50 | ||||
|         ) { | ||||
|             callQuiz(activity) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Displays an alert prompting the user to take the quiz | ||||
|      */ | ||||
|     @SuppressLint("StringFormatInvalid") | ||||
|     private fun callQuiz(activity: Activity) { | ||||
|         DialogUtil.showAlertDialog( | ||||
|             activity, | ||||
|             activity.getString(R.string.quiz), | ||||
|             activity.getString(R.string.quiz_alert_message, REVERT_PERCENTAGE_FOR_MESSAGE), | ||||
|             activity.getString(R.string.about_translate_proceed), | ||||
|             activity.getString(android.R.string.cancel), | ||||
|             { startQuizActivity(activity) }, | ||||
|             null | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Starts the quiz activity and updates preferences for revert and upload counts | ||||
|      */ | ||||
|     private fun startQuizActivity(activity: Activity) { | ||||
|         val newRevertSharedPrefs = revertCount + revertKvStore.getInt(REVERT_SHARED_PREFERENCE, 0) | ||||
|         revertKvStore.putInt(REVERT_SHARED_PREFERENCE, newRevertSharedPrefs) | ||||
| 
 | ||||
|         val newUploadCount = totalUploadCount + revertKvStore.getInt(UPLOAD_SHARED_PREFERENCE, 0) | ||||
|         revertKvStore.putInt(UPLOAD_SHARED_PREFERENCE, newUploadCount) | ||||
| 
 | ||||
|         val intent = Intent(activity, WelcomeActivity::class.java).apply { | ||||
|             putExtra("isQuiz", true) | ||||
|         } | ||||
|         activity.startActivity(intent) | ||||
|     } | ||||
| } | ||||
|  | @ -1,63 +0,0 @@ | |||
| package fr.free.nrw.commons.quiz; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import fr.free.nrw.commons.R; | ||||
| 
 | ||||
| /** | ||||
|  * controls the quiz in the Activity | ||||
|  */ | ||||
| public class QuizController { | ||||
| 
 | ||||
|     ArrayList<QuizQuestion> quiz = new ArrayList<>(); | ||||
| 
 | ||||
|     private final String URL_FOR_SELFIE = "https://i.imgur.com/0fMYcpM.jpg"; | ||||
|     private final String URL_FOR_TAJ_MAHAL = "https://upload.wikimedia.org/wikipedia/commons/1/15/Taj_Mahal-03.jpg"; | ||||
|     private final String URL_FOR_BLURRY_IMAGE = "https://i.imgur.com/Kepb5jR.jpg"; | ||||
|     private final String URL_FOR_SCREENSHOT = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Social_media_app_mockup_screenshot.svg/500px-Social_media_app_mockup_screenshot.svg.png"; | ||||
|     private final String URL_FOR_EVENT = "https://upload.wikimedia.org/wikipedia/commons/5/51/HouseBuildingInNorthernVietnam.jpg"; | ||||
| 
 | ||||
|     public void initialize(Context context){ | ||||
|         QuizQuestion q1 = new QuizQuestion(1, | ||||
|                 context.getString(R.string.quiz_question_string), | ||||
|                 URL_FOR_SELFIE, | ||||
|                 false, | ||||
|                 context.getString(R.string.selfie_answer)); | ||||
|         quiz.add(q1); | ||||
| 
 | ||||
|         QuizQuestion q2 = new QuizQuestion(2, | ||||
|                 context.getString(R.string.quiz_question_string), | ||||
|                 URL_FOR_TAJ_MAHAL, | ||||
|                 true, | ||||
|                 context.getString(R.string.taj_mahal_answer)); | ||||
|         quiz.add(q2); | ||||
| 
 | ||||
|         QuizQuestion q3 = new QuizQuestion(3, | ||||
|                 context.getString(R.string.quiz_question_string), | ||||
|                 URL_FOR_BLURRY_IMAGE, | ||||
|                 false, | ||||
|                 context.getString(R.string.blurry_image_answer)); | ||||
|         quiz.add(q3); | ||||
| 
 | ||||
|         QuizQuestion q4 = new QuizQuestion(4, | ||||
|                 context.getString(R.string.quiz_screenshot_question), | ||||
|                 URL_FOR_SCREENSHOT, | ||||
|                 false, | ||||
|                 context.getString(R.string.screenshot_answer)); | ||||
|         quiz.add(q4); | ||||
| 
 | ||||
|         QuizQuestion q5 = new QuizQuestion(5, | ||||
|                 context.getString(R.string.quiz_question_string), | ||||
|                 URL_FOR_EVENT, | ||||
|                 true, | ||||
|                 context.getString(R.string.construction_event_answer)); | ||||
|         quiz.add(q5); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public ArrayList<QuizQuestion> getQuiz() { | ||||
|         return quiz; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizController.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizController.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| package fr.free.nrw.commons.quiz | ||||
| 
 | ||||
| import android.content.Context | ||||
| 
 | ||||
| import java.util.ArrayList | ||||
| 
 | ||||
| import fr.free.nrw.commons.R | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Controls the quiz in the Activity | ||||
|  */ | ||||
| class QuizController { | ||||
| 
 | ||||
|     private val quiz: ArrayList<QuizQuestion> = ArrayList() | ||||
| 
 | ||||
|     private val URL_FOR_SELFIE = "https://i.imgur.com/0fMYcpM.jpg" | ||||
|     private val URL_FOR_TAJ_MAHAL = "https://upload.wikimedia.org/wikipedia/commons/1/15/Taj_Mahal-03.jpg" | ||||
|     private val URL_FOR_BLURRY_IMAGE = "https://i.imgur.com/Kepb5jR.jpg" | ||||
|     private val URL_FOR_SCREENSHOT = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Social_media_app_mockup_screenshot.svg/500px-Social_media_app_mockup_screenshot.svg.png" | ||||
|     private val URL_FOR_EVENT = "https://upload.wikimedia.org/wikipedia/commons/5/51/HouseBuildingInNorthernVietnam.jpg" | ||||
| 
 | ||||
|     fun initialize(context: Context) { | ||||
|         val q1 = QuizQuestion( | ||||
|             1, | ||||
|             context.getString(R.string.quiz_question_string), | ||||
|             URL_FOR_SELFIE, | ||||
|             false, | ||||
|             context.getString(R.string.selfie_answer) | ||||
|         ) | ||||
|         quiz.add(q1) | ||||
| 
 | ||||
|         val q2 = QuizQuestion( | ||||
|             2, | ||||
|             context.getString(R.string.quiz_question_string), | ||||
|             URL_FOR_TAJ_MAHAL, | ||||
|             true, | ||||
|             context.getString(R.string.taj_mahal_answer) | ||||
|         ) | ||||
|         quiz.add(q2) | ||||
| 
 | ||||
|         val q3 = QuizQuestion( | ||||
|             3, | ||||
|             context.getString(R.string.quiz_question_string), | ||||
|             URL_FOR_BLURRY_IMAGE, | ||||
|             false, | ||||
|             context.getString(R.string.blurry_image_answer) | ||||
|         ) | ||||
|         quiz.add(q3) | ||||
| 
 | ||||
|         val q4 = QuizQuestion( | ||||
|             4, | ||||
|             context.getString(R.string.quiz_screenshot_question), | ||||
|             URL_FOR_SCREENSHOT, | ||||
|             false, | ||||
|             context.getString(R.string.screenshot_answer) | ||||
|         ) | ||||
|         quiz.add(q4) | ||||
| 
 | ||||
|         val q5 = QuizQuestion( | ||||
|             5, | ||||
|             context.getString(R.string.quiz_question_string), | ||||
|             URL_FOR_EVENT, | ||||
|             true, | ||||
|             context.getString(R.string.construction_event_answer) | ||||
|         ) | ||||
|         quiz.add(q5) | ||||
|     } | ||||
| 
 | ||||
|     fun getQuiz(): ArrayList<QuizQuestion> { | ||||
|         return quiz | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1,188 +0,0 @@ | |||
| package fr.free.nrw.commons.quiz; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.graphics.Bitmap; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| 
 | ||||
| import fr.free.nrw.commons.databinding.ActivityQuizResultBinding; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| 
 | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.contributions.MainActivity; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  *  Displays the final score of quiz and congratulates the user | ||||
|  */ | ||||
| public class QuizResultActivity extends AppCompatActivity { | ||||
| 
 | ||||
|     private ActivityQuizResultBinding binding; | ||||
|     private final int NUMBER_OF_QUESTIONS = 5; | ||||
|     private final int MULTIPLIER_TO_GET_PERCENTAGE = 20; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         binding = ActivityQuizResultBinding.inflate(getLayoutInflater()); | ||||
|         setContentView(binding.getRoot()); | ||||
| 
 | ||||
|         setSupportActionBar(binding.toolbar.toolbar); | ||||
| 
 | ||||
|         binding.quizResultNext.setOnClickListener(view -> launchContributionActivity()); | ||||
| 
 | ||||
|         if ( getIntent() != null) { | ||||
|             Bundle extras = getIntent().getExtras(); | ||||
|             int score = extras.getInt("QuizResult"); | ||||
|             setScore(score); | ||||
|         }else{ | ||||
|             startActivityWithFlags( | ||||
|                     this, MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, | ||||
|                     Intent.FLAG_ACTIVITY_SINGLE_TOP); | ||||
|             super.onBackPressed(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         binding = null; | ||||
|         super.onDestroy(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to calculate and display percentage and score | ||||
|      * @param score | ||||
|      */ | ||||
|     public void setScore(int score) { | ||||
|         final int scorePercent = score * MULTIPLIER_TO_GET_PERCENTAGE; | ||||
|         binding.resultProgressBar.setProgress(scorePercent); | ||||
|         binding.tvResultProgress.setText(score +" / " + NUMBER_OF_QUESTIONS); | ||||
|         final String message = getResources().getString(R.string.congratulatory_message_quiz,scorePercent + "%"); | ||||
|         binding.congratulatoryMessage.setText(message); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to go to Contibutions Activity | ||||
|      */ | ||||
|     public void launchContributionActivity(){ | ||||
|         startActivityWithFlags( | ||||
|                 this, MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, | ||||
|                 Intent.FLAG_ACTIVITY_SINGLE_TOP); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
|         startActivityWithFlags( | ||||
|                 this, MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, | ||||
|                 Intent.FLAG_ACTIVITY_SINGLE_TOP); | ||||
|         super.onBackPressed(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Function to call intent to an activity | ||||
|      * @param context | ||||
|      * @param cls | ||||
|      * @param flags | ||||
|      * @param <T> | ||||
|      */ | ||||
|     public static <T> void startActivityWithFlags(Context context, Class<T> cls, int... flags) { | ||||
|         Intent intent = new Intent(context, cls); | ||||
|         for (int flag: flags) { | ||||
|             intent.addFlags(flag); | ||||
|         } | ||||
|         context.startActivity(intent); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to inflate menu | ||||
|      * @param menu | ||||
|      * @return | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         // Inflate the menu; this adds items to the action bar if it is present. | ||||
|         getMenuInflater().inflate(R.menu.menu_about, menu); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * if share option selected then take screenshot and launch alert | ||||
|      * @param item | ||||
|      * @return | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int id = item.getItemId(); | ||||
|         if (id == R.id.share_app_icon) { | ||||
|             View rootView = getWindow().getDecorView().findViewById(android.R.id.content); | ||||
|             Bitmap screenShot = getScreenShot(rootView); | ||||
|             showAlert(screenShot); | ||||
|         } | ||||
| 
 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * to store the screenshot of image in bitmap variable temporarily | ||||
|      * @param view | ||||
|      * @return | ||||
|      */ | ||||
|     public static Bitmap getScreenShot(View view) { | ||||
|         View screenView = view.getRootView(); | ||||
|         screenView.setDrawingCacheEnabled(true); | ||||
|         Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache()); | ||||
|         screenView.setDrawingCacheEnabled(false); | ||||
|         return bitmap; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * share the screenshot through social media | ||||
|      * @param bitmap | ||||
|      */ | ||||
|     void shareScreen(Bitmap bitmap) { | ||||
|         try { | ||||
|             File file = new File(this.getExternalCacheDir(),"screen.png"); | ||||
|             FileOutputStream fOut = new FileOutputStream(file); | ||||
|             bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); | ||||
|             fOut.flush(); | ||||
|             fOut.close(); | ||||
|             file.setReadable(true, false); | ||||
|             final Intent intent = new Intent(android.content.Intent.ACTION_SEND); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); | ||||
|             intent.setType("image/png"); | ||||
|             startActivity(Intent.createChooser(intent, getString(R.string.share_image_via))); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * It display the alertDialog with Image of screenshot | ||||
|      * @param screenshot | ||||
|      */ | ||||
|     public void showAlert(Bitmap screenshot) { | ||||
|         AlertDialog.Builder alertadd = new AlertDialog.Builder(QuizResultActivity.this); | ||||
|         LayoutInflater factory = LayoutInflater.from(QuizResultActivity.this); | ||||
|         final View view = factory.inflate(R.layout.image_alert_layout, null); | ||||
|         ImageView screenShotImage = view.findViewById(R.id.alert_image); | ||||
|         screenShotImage.setImageBitmap(screenshot); | ||||
|         TextView shareMessage = view.findViewById(R.id.alert_text); | ||||
|         shareMessage.setText(R.string.quiz_result_share_message); | ||||
|         alertadd.setView(view); | ||||
|         alertadd.setPositiveButton(R.string.about_translate_proceed, (dialog, which) -> shareScreen(screenshot)); | ||||
|         alertadd.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel()); | ||||
|         alertadd.show(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										192
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								app/src/main/java/fr/free/nrw/commons/quiz/QuizResultActivity.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,192 @@ | |||
| package fr.free.nrw.commons.quiz | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.graphics.Bitmap | ||||
| import android.net.Uri | ||||
| import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.Menu | ||||
| import android.view.MenuItem | ||||
| import android.view.View | ||||
| import android.widget.ImageView | ||||
| import android.widget.TextView | ||||
| 
 | ||||
| import androidx.appcompat.app.AlertDialog | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| 
 | ||||
| import fr.free.nrw.commons.databinding.ActivityQuizResultBinding | ||||
| import java.io.File | ||||
| import java.io.FileOutputStream | ||||
| 
 | ||||
| import fr.free.nrw.commons.R | ||||
| import fr.free.nrw.commons.contributions.MainActivity | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Displays the final score of quiz and congratulates the user | ||||
|  */ | ||||
| class QuizResultActivity : AppCompatActivity() { | ||||
| 
 | ||||
|     private var binding: ActivityQuizResultBinding? = null | ||||
|     private val NUMBER_OF_QUESTIONS = 5 | ||||
|     private val MULTIPLIER_TO_GET_PERCENTAGE = 20 | ||||
| 
 | ||||
|     public override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|         binding = ActivityQuizResultBinding.inflate(layoutInflater) | ||||
|         setContentView(binding?.root) | ||||
| 
 | ||||
|         setSupportActionBar(binding?.toolbar?.toolbar) | ||||
| 
 | ||||
|         binding?.quizResultNext?.setOnClickListener { | ||||
|             launchContributionActivity() | ||||
|         } | ||||
| 
 | ||||
|         intent?.extras?.let { extras -> | ||||
|             val score = extras.getInt("QuizResult", 0) | ||||
|             setScore(score) | ||||
|         } ?: run { | ||||
|             startActivityWithFlags( | ||||
|                 this, MainActivity::class.java, | ||||
|                 Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP | ||||
|             ) | ||||
|             super.onBackPressed() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun onDestroy() { | ||||
|         binding = null | ||||
|         super.onDestroy() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To calculate and display percentage and score | ||||
|      * @param score | ||||
|      */ | ||||
|     @SuppressLint("StringFormatInvalid", "SetTextI18n") | ||||
|     fun setScore(score: Int) { | ||||
|         val scorePercent = score * MULTIPLIER_TO_GET_PERCENTAGE | ||||
|         binding?.resultProgressBar?.progress = scorePercent | ||||
|         binding?.tvResultProgress?.text = "$score / $NUMBER_OF_QUESTIONS" | ||||
|         val message = resources.getString(R.string.congratulatory_message_quiz, "$scorePercent%") | ||||
|         binding?.congratulatoryMessage?.text = message | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To go to Contributions Activity | ||||
|      */ | ||||
|     fun launchContributionActivity() { | ||||
|         startActivityWithFlags( | ||||
|             this, MainActivity::class.java, | ||||
|             Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun onBackPressed() { | ||||
|         startActivityWithFlags( | ||||
|             this, MainActivity::class.java, | ||||
|             Intent.FLAG_ACTIVITY_CLEAR_TOP, Intent.FLAG_ACTIVITY_SINGLE_TOP | ||||
|         ) | ||||
|         super.onBackPressed() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Function to call intent to an activity | ||||
|      * @param context | ||||
|      * @param cls | ||||
|      * @param flags | ||||
|      */ | ||||
|     companion object { | ||||
|         fun <T> startActivityWithFlags(context: Context, cls: Class<T>, vararg flags: Int) { | ||||
|             val intent = Intent(context, cls) | ||||
|             flags.forEach { flag -> intent.addFlags(flag) } | ||||
|             context.startActivity(intent) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To inflate menu | ||||
|      * @param menu | ||||
|      * @return | ||||
|      */ | ||||
|     override fun onCreateOptionsMenu(menu: Menu?): Boolean { | ||||
|         // Inflate the menu; this adds items to the action bar if it is present. | ||||
|         menuInflater.inflate(R.menu.menu_about, menu) | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * If share option selected then take screenshot and launch alert | ||||
|      * @param item | ||||
|      * @return | ||||
|      */ | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         if (item.itemId == R.id.share_app_icon) { | ||||
|             val rootView = window.decorView.findViewById<View>(android.R.id.content) | ||||
|             val screenShot = getScreenShot(rootView) | ||||
|             showAlert(screenShot) | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To store the screenshot of image in bitmap variable temporarily | ||||
|      * @param view | ||||
|      * @return | ||||
|      */ | ||||
|     fun getScreenShot(view: View): Bitmap { | ||||
|         val screenView = view.rootView | ||||
|         screenView.isDrawingCacheEnabled = true | ||||
|         val bitmap = Bitmap.createBitmap(screenView.drawingCache) | ||||
|         screenView.isDrawingCacheEnabled = false | ||||
|         return bitmap | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Share the screenshot through social media | ||||
|      * @param bitmap | ||||
|      */ | ||||
|     @SuppressLint("SetWorldReadable") | ||||
|     fun shareScreen(bitmap: Bitmap) { | ||||
|         try { | ||||
|             val file = File(this.externalCacheDir, "screen.png") | ||||
|             FileOutputStream(file).use { fOut -> | ||||
|                 bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut) | ||||
|                 fOut.flush() | ||||
|             } | ||||
|             file.setReadable(true, false) | ||||
|             val intent = Intent(Intent.ACTION_SEND).apply { | ||||
|                 flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||||
|                 putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)) | ||||
|                 type = "image/png" | ||||
|             } | ||||
|             startActivity(Intent.createChooser(intent, getString(R.string.share_image_via))) | ||||
|         } catch (e: Exception) { | ||||
|             e.printStackTrace() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * It displays the AlertDialog with Image of screenshot | ||||
|      * @param screenshot | ||||
|      */ | ||||
|     fun showAlert(screenshot: Bitmap) { | ||||
|         val alertadd = AlertDialog.Builder(this) | ||||
|         val factory = LayoutInflater.from(this) | ||||
|         val view = factory.inflate(R.layout.image_alert_layout, null) | ||||
|         val screenShotImage = view.findViewById<ImageView>(R.id.alert_image) | ||||
|         screenShotImage.setImageBitmap(screenshot) | ||||
|         val shareMessage = view.findViewById<TextView>(R.id.alert_text) | ||||
|         shareMessage.setText(R.string.quiz_result_share_message) | ||||
|         alertadd.setView(view) | ||||
|         alertadd.setPositiveButton(R.string.about_translate_proceed) { dialog, _ -> | ||||
|             shareScreen(screenshot) | ||||
|         } | ||||
|         alertadd.setNegativeButton(android.R.string.cancel) { dialog, _ -> | ||||
|             dialog.cancel() | ||||
|         } | ||||
|         alertadd.show() | ||||
|     } | ||||
| } | ||||
|  | @ -1,64 +0,0 @@ | |||
| package fr.free.nrw.commons.quiz; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.view.View; | ||||
| import android.widget.CompoundButton; | ||||
| import android.widget.RadioButton; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * Used to group to or more radio buttons to ensure | ||||
|  * that at a particular time only one of them is selected | ||||
|  */ | ||||
| public class RadioGroupHelper { | ||||
| 
 | ||||
|     public List<CompoundButton> radioButtons = new ArrayList<>(); | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param radios | ||||
|      */ | ||||
|     public RadioGroupHelper(RadioButton... radios) { | ||||
|         super(); | ||||
|         for (RadioButton rb : radios) { | ||||
|             add(rb); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param activity | ||||
|      * @param radiosIDs | ||||
|      */ | ||||
|     public RadioGroupHelper(Activity activity, int... radiosIDs) { | ||||
|         this(activity.findViewById(android.R.id.content),radiosIDs); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param rootView | ||||
|      * @param radiosIDs | ||||
|      */ | ||||
|     public RadioGroupHelper(View rootView, int... radiosIDs) { | ||||
|         super(); | ||||
|         for (int radioButtonID : radiosIDs) { | ||||
|             add(rootView.findViewById(radioButtonID)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void add(CompoundButton button){ | ||||
|         this.radioButtons.add(button); | ||||
|         button.setOnClickListener(onClickListener); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * listener to ensure only one of the radio button is selected | ||||
|      */ | ||||
|     View.OnClickListener onClickListener = v -> { | ||||
|         for (CompoundButton rb : radioButtons) { | ||||
|             if (rb != v) rb.setChecked(false); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | @ -0,0 +1,61 @@ | |||
| package fr.free.nrw.commons.quiz | ||||
| 
 | ||||
| import android.app.Activity | ||||
| import android.view.View | ||||
| import android.widget.CompoundButton | ||||
| import android.widget.RadioButton | ||||
| 
 | ||||
| import java.util.ArrayList | ||||
| 
 | ||||
| /** | ||||
|  * Used to group to or more radio buttons to ensure | ||||
|  * that at a particular time only one of them is selected | ||||
|  */ | ||||
| class RadioGroupHelper { | ||||
| 
 | ||||
|     val radioButtons: MutableList<CompoundButton> = ArrayList() | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param radios | ||||
|      */ | ||||
|     constructor(vararg radios: RadioButton) { | ||||
|         for (rb in radios) { | ||||
|             add(rb) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param activity | ||||
|      * @param radiosIDs | ||||
|      */ | ||||
|     constructor(activity: Activity, vararg radiosIDs: Int) : this( | ||||
|         *radiosIDs.map { id -> activity.findViewById<RadioButton>(id) }.toTypedArray() | ||||
|     ) | ||||
| 
 | ||||
|     /** | ||||
|      * Constructor to group radio buttons | ||||
|      * @param rootView | ||||
|      * @param radiosIDs | ||||
|      */ | ||||
|     constructor(rootView: View, vararg radiosIDs: Int) { | ||||
|         for (radioButtonID in radiosIDs) { | ||||
|             add(rootView.findViewById(radioButtonID)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun add(button: CompoundButton) { | ||||
|         radioButtons.add(button) | ||||
|         button.setOnClickListener(onClickListener) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * listener to ensure only one of the radio button is selected | ||||
|      */ | ||||
|     private val onClickListener = View.OnClickListener { v -> | ||||
|         for (rb in radioButtons) { | ||||
|             if (rb != v) rb.isChecked = false | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Saifuddin Adenwala
						Saifuddin Adenwala