diff --git a/app/build.gradle b/app/build.gradle
index 14bf5f3b7d..4927dbc350 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -51,11 +51,26 @@ dependencies {
     implementation 'com.karumi:dexter:5.0.0'
     implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
 
+    def lifecycle_version = "2.8.7"
+    // ViewModel
+    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+    // ViewModel utilities for Compose
+    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
+
+    // Lifecycles only (without ViewModel or LiveData)
+    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
+    // Lifecycle utilities for Compose
+    implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
+
+    // Saved state module for ViewModel
+    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
+
+    // Annotation processor
+    kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
     // Jetpack Compose
     def composeBom = platform('androidx.compose:compose-bom:2024.11.00')
 
     implementation "androidx.activity:activity-compose:1.9.3"
-    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4"
     implementation (composeBom)
     implementation "androidx.compose.runtime:runtime"
     implementation "androidx.compose.ui:ui"
diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.kt b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.kt
index 0e9d834784..8a074f67ae 100644
--- a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.kt
+++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.kt
@@ -25,6 +25,7 @@ import fr.free.nrw.commons.media.PageMediaInterface
 import fr.free.nrw.commons.media.WikidataMediaInterface
 import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
 import fr.free.nrw.commons.mwapi.UserInterface
+import fr.free.nrw.commons.network.APIService
 import fr.free.nrw.commons.notification.NotificationInterface
 import fr.free.nrw.commons.review.ReviewInterface
 import fr.free.nrw.commons.upload.UploadInterface
@@ -42,6 +43,8 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 import okhttp3.OkHttpClient
 import okhttp3.logging.HttpLoggingInterceptor
 import okhttp3.logging.HttpLoggingInterceptor.Level
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
 import timber.log.Timber
 import java.io.File
 import java.util.concurrent.TimeUnit
@@ -295,6 +298,32 @@ class NetworkingModule {
     fun provideLanguageWikipediaSite(): WikiSite =
         WikiSite.forDefaultLocaleLanguageCode()
 
+    @Provides
+    @Named("tool_wmflabs_base_url")
+    fun provideToolWmflabsBaseUrl() : HttpUrl =
+        "https://tools.wmflabs.org/commons-android-app/tool-commons-android-app/".toHttpUrlOrNull()!!
+
+    @Singleton
+    @Provides
+    @Named("tool_wmflabs_retrofit")
+    fun provideToolWmflabsBaseUrlRetrofit(
+        @Named("tool_wmflabs_base_url") baseUrl: HttpUrl,
+        okHttpClient: OkHttpClient
+    ) : Retrofit {
+        return Retrofit.Builder()
+            .baseUrl(baseUrl)
+            .client(okHttpClient)
+            .addConverterFactory(GsonConverterFactory.create())
+//            .addCallAdapterFactory(CoroutineCallAdapterFactory())
+            .build()
+    }
+
+    @Provides
+    @Singleton
+    fun provideAPIService(
+        @Named("tool_wmflabs_retrofit") retrofit: Retrofit
+    ): APIService = retrofit.create(APIService::class.java)
+    
     companion object {
         private const val WIKIDATA_SPARQL_QUERY_URL = "https://query.wikidata.org/sparql"
         private const val TOOLS_FORGE_URL =
diff --git a/app/src/main/java/fr/free/nrw/commons/network/APIService.kt b/app/src/main/java/fr/free/nrw/commons/network/APIService.kt
new file mode 100644
index 0000000000..ba66855fd5
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/network/APIService.kt
@@ -0,0 +1,23 @@
+package fr.free.nrw.commons.network
+
+import fr.free.nrw.commons.profile.model.AchievementResponse
+import retrofit2.Response
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+
+interface APIService {
+
+    // https://tools.wmflabs.org/commons-android-app/tool-commons-android-app/uploadsbyuser.py?user=Devanonymous
+    @GET("uploadsbyuser.py")
+    suspend fun getImageUploadCount(
+        @Query("user") username : String
+    ) : Response<Int>
+
+
+    // https://tools.wmflabs.org/commons-android-app/tool-commons-android-app//feedback.py?user=Devanonymous
+    @GET("feedback.py")
+    suspend fun getUserAchievements(
+        @Query("user") username: String
+    ) : Response<AchievementResponse>
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModel.kt b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModel.kt
new file mode 100644
index 0000000000..4d26fc2c43
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModel.kt
@@ -0,0 +1,41 @@
+package fr.free.nrw.commons.profile.achievements
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import fr.free.nrw.commons.profile.model.UserAchievements
+import fr.free.nrw.commons.repository.ProfileRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+class AchievementViewModel @Inject constructor(
+    private val repository: ProfileRepository
+) : ViewModel() {
+
+    private val _achievements = MutableStateFlow(UserAchievements(
+        LevelController.LevelInfo.LEVEL_1,
+        articlesUsingImagesCount = 0,
+        thanksReceivedCount = 0,
+        featuredImagesCount = 0,
+        qualityImagesCount = 0,
+        imagesUploadedCount = 0,
+        revertedCount = 0,
+        uniqueImagesCount = 0,
+        imagesEditedBySomeoneElseCount = 0
+        )
+    )
+    val achievements : StateFlow<UserAchievements> = _achievements
+
+    private val _loading = MutableStateFlow(true)
+    val loading : StateFlow<Boolean> = _loading
+
+    fun getUserAchievements(username: String){
+        viewModelScope.launch {
+            repository.getUserLevel(username = username).collect {
+                _loading.value = false
+                _achievements.value = it
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModelFactory.kt b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModelFactory.kt
new file mode 100644
index 0000000000..d9c936a093
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementViewModelFactory.kt
@@ -0,0 +1,23 @@
+package fr.free.nrw.commons.profile.achievements
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import javax.inject.Inject
+import javax.inject.Provider
+
+/**
+ * This class extends the ViewModelProvider.Factory and creates a ViewModelFactory class
+ * for AchievementViewModel
+ */
+class AchievementViewModelFactory @Inject constructor(
+    private val viewModelProvider: Provider<AchievementViewModel>
+): ViewModelProvider.Factory {
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(AchievementViewModel::class.java)) {
+            (@Suppress("UNCHECKED_CAST")
+            return viewModelProvider.get() as T)
+        } else {
+            throw IllegalArgumentException("Unknown class name")
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.kt b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.kt
index af07423eba..f0369799af 100644
--- a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.kt
@@ -1,15 +1,16 @@
 package fr.free.nrw.commons.profile.achievements
 
+import android.annotation.SuppressLint
 import android.net.Uri
 import android.os.Bundle
-import android.util.DisplayMetrics
+import android.view.ContextThemeWrapper
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import android.widget.Toast
-import androidx.appcompat.view.ContextThemeWrapper
-import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
 import com.google.android.material.badge.BadgeDrawable
 import com.google.android.material.badge.BadgeUtils
@@ -22,21 +23,20 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
 import fr.free.nrw.commons.kvstore.BasicKvStore
 import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
 import fr.free.nrw.commons.profile.ProfileActivity
-import fr.free.nrw.commons.profile.achievements.LevelController.LevelInfo.Companion.from
 import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
 import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
 import fr.free.nrw.commons.utils.ViewUtil.showDismissibleSnackBar
 import fr.free.nrw.commons.utils.ViewUtil.showLongToast
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
-import org.apache.commons.lang3.StringUtils
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
 import timber.log.Timber
-import java.util.Objects
 import javax.inject.Inject
 
 class AchievementsFragment : CommonsDaggerSupportFragment(){
-    private lateinit var levelInfo: LevelController.LevelInfo
 
+    @Inject
+    lateinit var viewModelFactory: AchievementViewModelFactory
+    lateinit var viewModel: AchievementViewModel
     @Inject
     lateinit var sessionManager: SessionManager
 
@@ -45,11 +45,8 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
 
     private var _binding: FragmentAchievementsBinding? = null
     private val binding get() = _binding!!
-    // To keep track of the number of wiki edits made by a user
-    private var numberOfEdits: Int = 0
 
     private var userName: String? = null
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         arguments?.let {
@@ -64,6 +61,8 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
     ): View {
         _binding = FragmentAchievementsBinding.inflate(inflater, container, false)
 
+        viewModel = ViewModelProvider(
+            this@AchievementsFragment, viewModelFactory)[AchievementViewModel::class.java]
         binding.achievementInfo.setOnClickListener { showInfoDialog() }
         binding.imagesUploadInfoIcon.setOnClickListener { showUploadInfo() }
         binding.imagesRevertedInfoIcon.setOnClickListener { showRevertedInfo() }
@@ -73,19 +72,15 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
         binding.thanksImageIcon.setOnClickListener { showThanksReceivedInfo() }
         binding.qualityImageIcon.setOnClickListener { showQualityImagesInfo() }
 
-        // DisplayMetrics used to fetch the size of the screen
-        val displayMetrics = DisplayMetrics()
-        requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
-        val height = displayMetrics.heightPixels
-        val width = displayMetrics.widthPixels
-
-        // Used for the setting the size of imageView at runtime
-        // TODO REMOVE
-        val params = binding.achievementBadgeImage.layoutParams as ConstraintLayout.LayoutParams
-        params.height = (height * BADGE_IMAGE_HEIGHT_RATIO).toInt()
-        params.width = (width * BADGE_IMAGE_WIDTH_RATIO).toInt()
-        binding.achievementBadgeImage.requestLayout()
-        binding.progressBar.visibility = View.VISIBLE
+        lifecycleScope.launch {
+            viewModel.loading.collectLatest {
+                if (it){
+                    binding.progressBar.visibility = View.VISIBLE
+                } else {
+                    binding.progressBar.visibility = View.GONE
+                }
+            }
+        }
 
         setHasOptionsMenu(true)
         if (sessionManager.userName == null || sessionManager.userName == userName) {
@@ -100,8 +95,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
             return binding.root
         }
 
-
-        setWikidataEditCount()
         setAchievements()
         return binding.root
 
@@ -145,72 +138,56 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
      * which then calls parseJson when results are fetched
      */
 
+    @SuppressLint("SetTextI18n")
     private fun setAchievements() {
-        binding.progressBar.visibility = View.VISIBLE
         if (checkAccount()) {
-            try {
-                compositeDisposable.add(
-                    okHttpJsonApiClient
-                        .getAchievements(userName ?: return)
-                        .subscribeOn(Schedulers.io())
-                        .observeOn(AndroidSchedulers.mainThread())
-                        .subscribe(
-                            { response ->
-                                if (response != null) {
-                                    setUploadCount(Achievements.from(response))
-                                } else {
-                                    Timber.d("Success")
-                                    // TODO Create a Method to Hide all the Statistics
-//                                    binding.layoutImageReverts.visibility = View.INVISIBLE
-//                                    binding.achievementBadgeImage.visibility = View.INVISIBLE
-                                    // If the number of edits made by the user are more than 150,000
-                                    // in some cases such high number of wiki edit counts cause the
-                                    // achievements calculator to fail in some cases, for more details
-                                    // refer Issue: #3295
-                                    if (numberOfEdits <= 150_000) {
-                                        showSnackBarWithRetry(false)
-                                    } else {
-                                        showSnackBarWithRetry(true)
-                                    }
-                                }
-                            },
-                            { throwable ->
-                                Timber.e(throwable, "Fetching achievements statistics failed")
-                                if (numberOfEdits <= 150_000) {
-                                    showSnackBarWithRetry(false)
-                                } else {
-                                    showSnackBarWithRetry(true)
-                                }
-                            }
+            viewModel.getUserAchievements(username = userName.toString())
+
+            lifecycleScope.launch {
+                viewModel.achievements.collect{
+
+                    binding.achievementLevel.text = getString(R.string.level,it.level.levelNumber)
+                    val store = BasicKvStore(requireContext(), userName)
+                    store.putString("userAchievementsLevel", it.level.levelNumber.toString())
+
+                    binding.achievementBadgeImage.setImageDrawable(
+                        VectorDrawableCompat.create(
+                            resources, R.drawable.badge,
+                            ContextThemeWrapper(activity, it.level.levelStyle).theme
                         )
-                )
-            } catch (e: Exception) {
-                Timber.d("Exception: ${e.message}")
-            }
-        }
-    }
+                    )
+                    binding.achievementBadgeText.text = it.level.levelNumber.toString()
 
-    /**
-     * To call the API to fetch the count of wiki data edits
-     * in the form of JavaRx Single object<JSONobject>
-    </JSONobject> */
+                    // TODO(use String Format)
+                    binding.imageUploadedTVCount.text =
+                        it.imagesUploadedCount.toString() + "/" + it.level.maxUploadCount
+                    binding.imagesUploadedProgressbar.progress =
+                        100 * it.imagesUploadedCount / it.level.maxUploadCount
 
-    private fun setWikidataEditCount() {
-        if (StringUtils.isBlank(userName)) {
-            return
+                    // Revert
+                    binding.imageRevertTVCount.text = it.revertedCount.toString() + "%"
+                    binding.imageRevertsProgressbar.progress = it.revertedCount
+                    binding.imagesRevertLimitText.text =
+                        resources.getString(R.string.achievements_revert_limit_message) + it.level.minNonRevertPercentage + "%"
+
+                    // Images Used
+                    binding.imagesUsedProgressbar.progress = (100 * it.uniqueImagesCount) / it.level.maxUniqueImages
+                    binding.imagesUsedCount.text = (it.uniqueImagesCount.toString() + "/"
+                            + it.level.maxUniqueImages)
+
+                    // Thanks Received Badge
+                    showBadgesWithCount(view = binding.thanksImageIcon, count =  it.thanksReceivedCount)
+
+                    // Featured Images Badge
+                    showBadgesWithCount(view = binding.featuredImageIcon, count =  it.featuredImagesCount)
+
+                    // Quality Images Badge
+                    showBadgesWithCount(view = binding.qualityImageIcon, count =  it.qualityImagesCount)
+
+                    showBadgesWithCount(view = binding.wikidataEditsIcon, count = it.imagesEditedBySomeoneElseCount)
+                }
+            }
         }
-        compositeDisposable.add(
-            okHttpJsonApiClient
-                .getWikidataEdits(userName)
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe({ edits: Int ->
-                    numberOfEdits = edits
-                    showBadgesWithCount(view = binding.wikidataEditsIcon, count = edits)
-                }, { e: Throwable ->
-                    Timber.e("Error:$e")
-                })
-        )
     }
 
     /**
@@ -253,49 +230,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
         binding.progressBar.visibility = View.GONE
     }
 
-    /**
-     * used to the count of images uploaded by user
-     */
-
-    private fun setUploadCount(achievements: Achievements) {
-        if (checkAccount()) {
-            compositeDisposable.add(okHttpJsonApiClient
-                .getUploadCount(Objects.requireNonNull<String>(userName))
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(
-                    { uploadCount: Int? ->
-                        setAchievementsUploadCount(
-                            achievements,
-                            uploadCount ?:0
-                        )
-                    },
-                    { t: Throwable? ->
-                        Timber.e(t, "Fetching upload count failed")
-                        onError()
-                    }
-                ))
-        }
-    }
-
-    /**
-     * used to set achievements upload count and call hideProgressbar
-     * @param uploadCount
-     */
-    private fun setAchievementsUploadCount(achievements: Achievements, uploadCount: Int) {
-        // Create a new instance of Achievements with updated imagesUploaded
-        val updatedAchievements = Achievements(
-            achievements.uniqueUsedImages,
-            achievements.articlesUsingImages,
-            achievements.thanksReceived,
-            achievements.featuredImages,
-            achievements.qualityImages,
-            uploadCount,  // Update imagesUploaded with new value
-            achievements.revertCount
-        )
-
-        hideProgressBar(updatedAchievements)
-    }
 
     /**
      * used to the uploaded images progressbar
@@ -306,9 +240,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
             setZeroAchievements()
         } else {
             binding.imagesUploadedProgressbar.visibility = View.VISIBLE
-            binding.imagesUploadedProgressbar.progress =
-                100 * uploadCount / levelInfo.maxUploadCount
-            binding.imageUploadedTVCount.text = uploadCount.toString() + "/" + levelInfo.maxUploadCount
         }
     }
 
@@ -325,7 +256,7 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
             getString(R.string.ok),
             {}
         )
-
+        binding.layout.visibility = View.INVISIBLE
 //        binding.imagesUploadedProgressbar.setVisibility(View.INVISIBLE);
 //        binding.imageRevertsProgressbar.setVisibility(View.INVISIBLE);
 //        binding.imagesUsedByWikiProgressBar.setVisibility(View.INVISIBLE);
@@ -335,52 +266,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
         binding.imagesUploadTextParam.setText(R.string.no_image_uploaded)
     }
 
-    /**
-     * used to set the non revert image percentage
-     * @param notRevertPercentage
-     */
-    private fun setImageRevertPercentage(notRevertPercentage: Int) {
-        binding.imageRevertsProgressbar.visibility = View.VISIBLE
-        binding.imageRevertsProgressbar.progress = notRevertPercentage
-        val revertPercentage = notRevertPercentage.toString()
-        binding.imageRevertTVCount.text = "$revertPercentage%"
-        binding.imagesRevertLimitText.text =
-            resources.getString(R.string.achievements_revert_limit_message) + levelInfo.minNonRevertPercentage + "%"
-    }
-
-    /**
-     * Used the inflate the fetched statistics of the images uploaded by user
-     * and assign badge and level. Also stores the achievements level of the user in BasicKvStore to display in menu
-     * @param achievements
-     */
-    private fun inflateAchievements(achievements: Achievements) {
-
-        // Thanks Received Badge
-        showBadgesWithCount(view = binding.thanksImageIcon, count =  achievements.thanksReceived)
-
-        // Featured Images Badge
-        showBadgesWithCount(view = binding.featuredImageIcon, count =  achievements.featuredImages)
-
-        // Quality Images Badge
-        showBadgesWithCount(view = binding.qualityImageIcon, count =  achievements.qualityImages)
-
-        binding.imagesUsedByWikiProgressBar.progress =
-            100 * achievements.uniqueUsedImages / levelInfo.maxUniqueImages
-        binding.imagesUsedCount.text = (achievements.uniqueUsedImages.toString() + "/"
-                + levelInfo.maxUniqueImages)
-
-        binding.achievementLevel.text = getString(R.string.level,levelInfo.levelNumber)
-        binding.achievementBadgeImage.setImageDrawable(
-            VectorDrawableCompat.create(
-                resources, R.drawable.badge,
-                ContextThemeWrapper(activity, levelInfo.levelStyle).theme
-            )
-        )
-        binding.achievementBadgeText.text = levelInfo.levelNumber.toString()
-        val store = BasicKvStore(requireContext(), userName)
-        store.putString("userAchievementsLevel", levelInfo.levelNumber.toString())
-    }
-
     /**
      * This function is used to show badge on any view (button, imageView, etc)
      * @param view The View on which the badge will be displayed eg (button, imageView, etc)
@@ -425,22 +310,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
         })
     }
 
-    /**
-     * to hide progressbar
-     */
-    private fun hideProgressBar(achievements: Achievements) {
-        if (binding.progressBar != null) {
-            levelInfo = from(
-                achievements.imagesUploaded,
-                achievements.uniqueUsedImages,
-                achievements.notRevertPercentage
-            )
-            inflateAchievements(achievements)
-            setUploadProgress(achievements.imagesUploaded)
-            setImageRevertPercentage(achievements.notRevertPercentage)
-            binding.progressBar.visibility = View.GONE
-        }
-    }
 
     fun showUploadInfo() {
         launchAlertWithHelpLink(
@@ -546,9 +415,6 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
 
 
     companion object{
-        private const val BADGE_IMAGE_WIDTH_RATIO = 0.4
-        private const val BADGE_IMAGE_HEIGHT_RATIO = 0.3
-
         /**
          * Help link URLs
          */
diff --git a/app/src/main/java/fr/free/nrw/commons/profile/model/AchievementResponse.kt b/app/src/main/java/fr/free/nrw/commons/profile/model/AchievementResponse.kt
new file mode 100644
index 0000000000..b44b7d16ca
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/profile/model/AchievementResponse.kt
@@ -0,0 +1,34 @@
+package fr.free.nrw.commons.profile.model
+
+
+import com.google.gson.annotations.SerializedName
+
+data class AchievementResponse(
+    @SerializedName("articlesUsingImages")
+    val articlesUsingImages: Int,
+    @SerializedName("database")
+    val database: String,
+    @SerializedName("deletedUploads")
+    val deletedUploads: Int,
+    @SerializedName("featuredImages")
+    val featuredImages: FeaturedImages,
+    @SerializedName("imagesEditedBySomeoneElse")
+    val imagesEditedBySomeoneElse: Int,
+    @SerializedName("labs")
+    val labs: Boolean,
+    @SerializedName("status")
+    val status: String,
+    @SerializedName("thanksReceived")
+    val thanksReceived: Int,
+    @SerializedName("uniqueUsedImages")
+    val uniqueUsedImages: Int,
+    @SerializedName("user")
+    val user: String
+)
+
+data class FeaturedImages(
+    @SerializedName("Featured_pictures_on_Wikimedia_Commons")
+    val featuredPicturesOnWikimediaCommons: Int,
+    @SerializedName("Quality_images")
+    val qualityImages: Int
+)
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/profile/model/UserAchievements.kt b/app/src/main/java/fr/free/nrw/commons/profile/model/UserAchievements.kt
new file mode 100644
index 0000000000..b13b4d3822
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/profile/model/UserAchievements.kt
@@ -0,0 +1,15 @@
+package fr.free.nrw.commons.profile.model
+
+import fr.free.nrw.commons.profile.achievements.LevelController
+
+data class UserAchievements(
+    val level: LevelController.LevelInfo,
+    val articlesUsingImagesCount: Int = 0,
+    val thanksReceivedCount: Int = 0,
+    val featuredImagesCount: Int = 0,
+    val qualityImagesCount: Int = 0,
+    val imagesUploadedCount: Int = 0,
+    val revertedCount: Int = 0,
+    val uniqueImagesCount: Int = 0,
+    val imagesEditedBySomeoneElseCount: Int = 0
+)
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/repository/ProfileRepository.kt b/app/src/main/java/fr/free/nrw/commons/repository/ProfileRepository.kt
new file mode 100644
index 0000000000..a441464fa5
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/repository/ProfileRepository.kt
@@ -0,0 +1,53 @@
+package fr.free.nrw.commons.repository
+
+import fr.free.nrw.commons.network.APIService
+import fr.free.nrw.commons.profile.achievements.LevelController
+import fr.free.nrw.commons.profile.model.UserAchievements
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import timber.log.Timber
+import javax.inject.Inject
+
+class ProfileRepository @Inject constructor(private val apiService: APIService) {
+
+    fun getUserLevel(username: String) : Flow<UserAchievements> = flow {
+        try {
+            val uploadCountResponse = apiService.getImageUploadCount(username)
+            val imagesUploaded = uploadCountResponse.body() ?:0
+
+            val achievementResponse = apiService.getUserAchievements(username)
+
+            val uniqueImages = achievementResponse.body()?.uniqueUsedImages ?: 0
+            val articlesUsingImages = achievementResponse.body()?.articlesUsingImages ?: 0
+            val thanksReceived = achievementResponse.body()?.thanksReceived ?: 0
+            val featuredImages = achievementResponse.body()?.featuredImages?.featuredPicturesOnWikimediaCommons ?:0
+            val qualityImages = achievementResponse.body()?.featuredImages?.qualityImages ?: 0
+            val deletedUploads = achievementResponse.body()?.deletedUploads ?:0
+            val revertCount = (imagesUploaded - deletedUploads) * 100 / imagesUploaded
+            val imagesEditedBySomeoneElse = achievementResponse.body()?.imagesEditedBySomeoneElse ?:0
+
+            val level = LevelController.LevelInfo.from(
+                imagesUploaded = imagesUploaded,
+                uniqueImagesUsed = uniqueImages,
+                nonRevertRate = revertCount)
+
+            emit(
+                UserAchievements(
+                    level = level,
+                    articlesUsingImagesCount = articlesUsingImages,
+                    featuredImagesCount = featuredImages,
+                    imagesUploadedCount = imagesUploaded,
+                    qualityImagesCount = qualityImages,
+                    revertedCount = revertCount,
+                    thanksReceivedCount = thanksReceived,
+                    uniqueImagesCount = uniqueImages,
+                    imagesEditedBySomeoneElseCount = imagesEditedBySomeoneElse
+                )
+            )
+
+        }
+        catch(e : Exception) {
+            Timber.e(e.printStackTrace().toString())
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_achievements.xml b/app/src/main/res/layout/fragment_achievements.xml
index 00c18b3232..b199a23de1 100644
--- a/app/src/main/res/layout/fragment_achievements.xml
+++ b/app/src/main/res/layout/fragment_achievements.xml
@@ -43,7 +43,7 @@
       android:id="@+id/achievement_badge_image"
       android:layout_width="150dp"
       android:layout_height="150dp"
-      android:layout_marginTop="16dp"
+      android:layout_marginTop="100dp"
       android:background="@drawable/badge"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
@@ -263,7 +263,7 @@
       app:layout_constraintTop_toBottomOf="@+id/images_used_tv">
 
       <ProgressBar
-        android:id="@+id/images_used_by_wiki_progress_bar"
+        android:id="@+id/images_used_progressbar"
         style="?android:attr/progressBarStyleHorizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -362,7 +362,7 @@
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintVertical_bias="0.5"
       app:layout_constraintHorizontal_bias="0.5"
-      android:visibility="gone"/>
+      />
 
   </androidx.constraintlayout.widget.ConstraintLayout>
 </ScrollView>
\ No newline at end of file
diff --git a/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt
index 4c2fbf52cf..789f4d8b28 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt
@@ -173,33 +173,6 @@ class AchievementsFragmentUnitTests {
         method.invoke(fragment, "", "")
     }
 
-    @Test
-    @Throws(Exception::class)
-    fun testHideProgressBar() {
-        Shadows.shadowOf(Looper.getMainLooper()).idle()
-        val method: Method =
-            AchievementsFragment::class.java.getDeclaredMethod(
-                "hideProgressBar",
-                Achievements::class.java,
-            )
-        method.isAccessible = true
-        method.invoke(fragment, achievements)
-    }
-
-    @Test
-    @Throws(Exception::class)
-    fun testSetAchievementsUploadCount() {
-        Shadows.shadowOf(Looper.getMainLooper()).idle()
-        val method: Method =
-            AchievementsFragment::class.java.getDeclaredMethod(
-                "setAchievementsUploadCount",
-                Achievements::class.java,
-                Int::class.java,
-            )
-        method.isAccessible = true
-        method.invoke(fragment, achievements, 0)
-    }
-
     @Test
     @Throws(Exception::class)
     fun testCheckAccount() {
@@ -211,20 +184,7 @@ class AchievementsFragmentUnitTests {
         method.isAccessible = true
         method.invoke(fragment)
     }
-
-    @Test
-    @Throws(Exception::class)
-    fun testSetUploadCount() {
-        Shadows.shadowOf(Looper.getMainLooper()).idle()
-        val method: Method =
-            AchievementsFragment::class.java.getDeclaredMethod(
-                "setUploadCount",
-                Achievements::class.java,
-            )
-        method.isAccessible = true
-        method.invoke(fragment, achievements)
-    }
-
+    
     @Test
     @Throws(Exception::class)
     fun testOnError() {
@@ -263,18 +223,6 @@ class AchievementsFragmentUnitTests {
         method.invoke(fragment, false)
     }
 
-    @Test
-    @Throws(Exception::class)
-    fun testSetWikidataEditCount() {
-        Shadows.shadowOf(Looper.getMainLooper()).idle()
-        val method: Method =
-            AchievementsFragment::class.java.getDeclaredMethod(
-                "setWikidataEditCount",
-            )
-        method.isAccessible = true
-        method.invoke(fragment)
-    }
-
     @Test
     @Throws(Exception::class)
     fun testSetAchievements() {