Fix infinite loading circular progress bar after nominating for deletion

**Description (required)**

Fixes #5531

What changes did you make and why?
Parneet fixed the issue in his PR #5610 by making changes in the `MediaDetailFragment.java` file. However, that file was migrated to `Kotlin` and caused merge conflicts. So, I pull from his branch, copy the changes to the migrated file and refactor the related code for better code quality.

**Tests performed (required)**

Tested prodDebug on Samsung A14 with API level 34.

**Screenshots (for UI changes only)**

https://github.com/user-attachments/assets/2be3519a-9076-45f6-8602-3a97a446bf79

[Bug]: Circular Progress bar keeps on moving even though nomination for deletion is successful
### Summary

When the user clicks on 'Nominate for Deletion,' the circular progress bar keeps moving even though the nomination for deletion is successful. This doesn't provide any visible status and makes the user think that the process is ongoing. Only a notification is received, which can be piled up among other notifications.

### Steps to reproduce

1. Open the App
2. Click on any contribution
3. Click on Nominate for Deletion

### Expected behaviour

OnSuccess : Circular Progress bar should stop and Text should change to nominated for deletion

### Actual behaviour

OnSuccess : Circular Progress bar keeps on moving

### Device name

Samsung S21

### Android version

Android 14

### Commons app version

4.2.1-debug-HEAD~d4b473656

### Device logs

_No response_

### Screen-shots

https://github.com/commons-app/apps-android-commons/assets/114223204/f215652b-00a3-4256-8c34-c90eeadf31c0

### Would you like to work on the issue?

Yes

please assign #5531 @nicolas-raoul
Can I work on this @kanahia1 ?
Sure @neeldoshii, You can take it !

./gradlew :app:testBetaDebugUnitTest --tests "fr.free.nrw.commons.delete.ReasonBuilderTest"

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 9c53155a77..2e391a24fd 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -347,6 +347,7 @@ dependencies {
     // Kotlin + coroutines
     implementation(libs.androidx.work.runtime.ktx)
     implementation(libs.androidx.work.runtime)
+    implementation(libs.kotlinx.coroutines.rx2)
     testImplementation(libs.androidx.work.testing)

     //Glide
diff --git a/app/src/main/java/fr/free/nrw/commons/delete/DeleteHelper.kt b/app/src/main/java/fr/free/nrw/commons/delete/DeleteHelper.kt
index 09959d0ef5..3f9ae47ac1 100644
--- a/app/src/main/java/fr/free/nrw/commons/delete/DeleteHelper.kt
+++ b/app/src/main/java/fr/free/nrw/commons/delete/DeleteHelper.kt
@@ -53,7 +53,6 @@ class DeleteHelper @Inject constructor(
         media: Media?,
         reason: String?
     ): Single<Boolean>? {
-
         if(context == null && media == null) {
             return null
         }
@@ -86,7 +85,6 @@ class DeleteHelper @Inject constructor(
      * @return
      */
     private fun delete(media: Media, reason: String): Observable<Boolean> {
-        Timber.d("thread is delete %s", Thread.currentThread().name)
         val summary = "Nominating ${media.filename} for deletion."
         val calendar = Calendar.getInstance()
         val fileDeleteString = """
diff --git a/app/src/main/java/fr/free/nrw/commons/delete/ReasonBuilder.kt b/app/src/main/java/fr/free/nrw/commons/delete/ReasonBuilder.kt
index 09018c249b..c4cd73b8a6 100644
--- a/app/src/main/java/fr/free/nrw/commons/delete/ReasonBuilder.kt
+++ b/app/src/main/java/fr/free/nrw/commons/delete/ReasonBuilder.kt
@@ -2,21 +2,19 @@ package fr.free.nrw.commons.delete

 import android.annotation.SuppressLint
 import android.content.Context
-
-import fr.free.nrw.commons.utils.DateUtil
-import java.util.Locale
-
-import javax.inject.Inject
-import javax.inject.Singleton
-
 import fr.free.nrw.commons.Media
 import fr.free.nrw.commons.R
-import fr.free.nrw.commons.profile.achievements.FeedbackResponse
 import fr.free.nrw.commons.auth.SessionManager
 import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
+import fr.free.nrw.commons.utils.DateUtil
 import fr.free.nrw.commons.utils.ViewUtilWrapper
 import io.reactivex.Single
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.rx2.rxSingle
 import timber.log.Timber
+import java.util.Locale
+import javax.inject.Inject
+import javax.inject.Singleton

 /**
  * This class handles the reason for deleting a Media object
@@ -29,6 +27,8 @@ class ReasonBuilder @Inject constructor(
     private val viewUtilWrapper: ViewUtilWrapper
 ) {

+    private val defaultFileUsagePageSize = 10
+
     /**
      * To process the reason and append the media's upload date and uploaded_by_me string
      * @param media
@@ -39,7 +39,7 @@ class ReasonBuilder @Inject constructor(
         if (media == null || reason == null) {
             return Single.just("Not known")
         }
-        return fetchArticleNumber(media, reason)
+        return getAndAppendFileUsage(media, reason)
     }

     /**
@@ -54,27 +54,36 @@ class ReasonBuilder @Inject constructor(
         }
     }

-    private fun fetchArticleNumber(media: Media, reason: String): Single<String> {
-        return if (checkAccount()) {
-            okHttpJsonApiClient
-                .getAchievements(sessionManager.userName)
-                .map { feedbackResponse -> appendArticlesUsed(feedbackResponse, media, reason) }
-        } else {
-            Single.just("")
+    private fun getAndAppendFileUsage(media: Media, reason: String): Single<String> {
+        return rxSingle(context = Dispatchers.IO) {
+            if (!checkAccount()) return@rxSingle ""
+
+            try {
+                val globalFileUsage = okHttpJsonApiClient.getGlobalFileUsages(
+                    fileName = media.filename,
+                    pageSize = defaultFileUsagePageSize
+                )
+                val globalUsages = globalFileUsage?.query?.pages?.sumOf { it.fileUsage.size } ?: 0
+
+                appendArticlesUsed(globalUsages, media, reason)
+            } catch (e: Exception) {
+                Timber.e(e, "Error fetching file usage")
+                throw e
+            }
         }
     }

     /**
-     * Takes the uploaded_by_me string, the upload date, name of articles using images
+     * Takes the uploaded_by_me string, the upload date, no. of articles using images
      * and appends it to the received reason
-     * @param feedBack object
+     * @param fileUsages No. of files/articles using this image
      * @param media whose upload data is to be fetched
-     * @param reason
+     * @param reason string to be appended
      */
     @SuppressLint("StringFormatInvalid")
-    private fun appendArticlesUsed(feedBack: FeedbackResponse, media: Media, reason: String): String {
+    private fun appendArticlesUsed(fileUsages: Int, media: Media, reason: String): String {
         val reason1Template = context.getString(R.string.uploaded_by_myself)
-        return reason + String.format(Locale.getDefault(), reason1Template, prettyUploadedDate(media), feedBack.articlesUsingImages)
+        return reason + String.format(Locale.getDefault(), reason1Template, prettyUploadedDate(media), fileUsages)
             .also { Timber.i("New Reason %s", it) }
     }

diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt
index 8a4d530c47..f371b733f7 100644
--- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt
@@ -74,7 +74,6 @@ import fr.free.nrw.commons.BuildConfig
 import fr.free.nrw.commons.CameraPosition
 import fr.free.nrw.commons.CommonsApplication
 import fr.free.nrw.commons.CommonsApplication.Companion.instance
-import fr.free.nrw.commons.locationpicker.LocationPicker
 import fr.free.nrw.commons.Media
 import fr.free.nrw.commons.MediaDataExtractor
 import fr.free.nrw.commons.R
@@ -102,6 +101,7 @@ import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity
 import fr.free.nrw.commons.kvstore.JsonKvStore
 import fr.free.nrw.commons.language.AppLanguageLookUpTable
 import fr.free.nrw.commons.location.LocationServiceManager
+import fr.free.nrw.commons.locationpicker.LocationPicker
 import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
 import fr.free.nrw.commons.profile.ProfileActivity
 import fr.free.nrw.commons.review.ReviewHelper
@@ -116,6 +116,7 @@ import fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources
 import fr.free.nrw.commons.utils.PermissionUtils.PERMISSIONS_STORAGE
 import fr.free.nrw.commons.utils.PermissionUtils.checkPermissionsAndPerformAction
 import fr.free.nrw.commons.utils.PermissionUtils.hasPermission
+import fr.free.nrw.commons.utils.ViewUtil
 import fr.free.nrw.commons.utils.ViewUtil.showShortToast
 import fr.free.nrw.commons.utils.ViewUtilWrapper
 import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.Revision
@@ -125,6 +126,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.schedulers.Schedulers
 import org.apache.commons.lang3.StringUtils
 import timber.log.Timber
+import java.lang.String.format
 import java.util.Date
 import java.util.Locale
 import java.util.Objects
@@ -1646,7 +1648,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
                 getString(R.string.cancel),
                 {
                     val reason: String = input.text.toString()
-                    onDeleteClickeddialogtext(reason)
+                    onDeleteClickedDialogText(reason)
                 },
                 {},
                 input
@@ -1700,26 +1702,48 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
         resultSingle
             .subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread())
-            .subscribe { _ ->
-                if (applicationKvStore.getBoolean(
-                        String.format(
-                            NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl
-                        ), false
-                    )
-                ) {
-                    applicationKvStore.remove(
-                        String.format(
-                            NOMINATING_FOR_DELETION_MEDIA,
-                            media!!.imageUrl
-                        )
-                    )
-                    callback!!.nominatingForDeletion(index)
-                }
-            }
+            .subscribe(this::handleDeletionResult, this::handleDeletionError);
+    }
+
+    /**
+     * Disables Progress Bar and Update delete button text.
+     */
+    private fun disableProgressBar() {
+        activity?.run {
+            runOnUiThread(Runnable {
+                binding.progressBarDeletion.visibility = View.GONE
+            })
+        } ?: return // Prevent NullPointerException when fragment is not attached to activity
+    }
+
+    private fun handleDeletionResult(success: Boolean) {
+        if (success) {
+            binding.nominateDeletion.text = getString(R.string.nominated_for_deletion_btn)
+            ViewUtil.showLongSnackbar(requireView(), getString(R.string.nominated_for_deletion))
+            disableProgressBar()
+            checkAndClearDeletionFlag()
+        } else {
+            disableProgressBar()
+        }
+    }
+
+    private fun handleDeletionError(throwable: Throwable) {
+        throwable.printStackTrace()
+        disableProgressBar()
+        checkAndClearDeletionFlag()
+    }
+
+    private fun checkAndClearDeletionFlag() {
+        if (applicationKvStore
+            .getBoolean(format(NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl), false)
+        ) {
+            applicationKvStore.remove(format(NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl))
+            callback!!.nominatingForDeletion(index)
+        }
     }

     @SuppressLint("CheckResult")
-    private fun onDeleteClickeddialogtext(reason: String) {
+    private fun onDeleteClickedDialogText(reason: String) {
         applicationKvStore.putBoolean(
             String.format(
                 NOMINATING_FOR_DELETION_MEDIA,
@@ -1736,22 +1760,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
         resultSingletext
             .subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread())
-            .subscribe { _ ->
-                if (applicationKvStore.getBoolean(
-                        String.format(
-                            NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl
-                        ), false
-                    )
-                ) {
-                    applicationKvStore.remove(
-                        String.format(
-                            NOMINATING_FOR_DELETION_MEDIA,
-                            media!!.imageUrl
-                        )
-                    )
-                    callback!!.nominatingForDeletion(index)
-                }
-            }
+            .subscribe(this::handleDeletionResult, this::handleDeletionError);
     }

     private fun onSeeMoreClicked() {
diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.kt b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.kt
index 4fa7979d2f..a2f92c2e67 100644
--- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.kt
+++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.kt
@@ -281,6 +281,7 @@ class OkHttpJsonApiClient @Inject constructor(
                         FeedbackResponse::class.java
                     )
                 } catch (e: Exception) {
+                    e.printStackTrace()
                     return@fromCallable FeedbackResponse(0, 0, 0, FeaturedImages(0, 0), 0, "")
                 }
             }
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 68dba88bec..c9a2d16c86 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -431,7 +431,7 @@
   <string name="deletion_reason_no_longer_want_public">I changed my mind, I don\'t want it to be publicly visible anymore</string>
   <string name="deletion_reason_not_interesting">Sorry this picture is not interesting for an encyclopedia</string>

-  <string name="uploaded_by_myself">Uploaded by myself on %1$s, used in %2$d article(s).</string>
+  <string name="uploaded_by_myself">Uploaded by myself on %1$s, used in %2$d article(s) at least.</string>

   <string name="no_uploads">Welcome to Commons!\n
 Upload your first media by tapping on the add button.</string>
@@ -876,4 +876,5 @@ Upload your first media by tapping on the add button.</string>
   <string name="show_in_nearby">Show in Nearby</string>
   <string name="image_tag_line_created_and_uploaded_by">Created and uploaded by: %1$s</string>
   <string name="image_tag_line_created_by_and_uploaded_by">Created by %1$s and uploaded by %2$s</string>
+  <string name="nominated_for_deletion_btn">Nominated for Deletion</string>
 </resources>
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f38357b045..df4b7bb43a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -16,6 +16,7 @@ constraintlayout = "1.1.3"
 coordinates2country = "1.8"
 dexcount = "4.0.0"
 githubTripletPlay = "2.7.2"
+kotlinxCoroutinesRx2 = "1.8.0"
 osmdroidAndroid = "6.1.17"
 testCore = "1.4.0"
 coreKtx = "1.9.0"
@@ -127,6 +128,7 @@ dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref =
 facebook-fresco = { module = "com.facebook.fresco:fresco", version.ref = "frescoVersion" }
 glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" }
 glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
+kotlinx-coroutines-rx2 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", version.ref = "kotlinxCoroutinesRx2" }
 photoview = { module = "com.github.chrisbanes:PhotoView", version.ref = "photoviewVersion" }

 # RxJava and Reactive Programming

diff --git a/app/src/test/kotlin/fr/free/nrw/commons/delete/ReasonBuilderTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/delete/ReasonBuilderTest.kt
index e89a02dece..bd67475ee3 100644
--- a/app/src/test/kotlin/fr/free/nrw/commons/delete/ReasonBuilderTest.kt
+++ b/app/src/test/kotlin/fr/free/nrw/commons/delete/ReasonBuilderTest.kt
@@ -5,13 +5,14 @@ import android.content.res.Resources
 import fr.free.nrw.commons.Media
 import fr.free.nrw.commons.R
 import fr.free.nrw.commons.auth.SessionManager
+import fr.free.nrw.commons.fileusages.GlobalFileUsagesResponse
 import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
-import fr.free.nrw.commons.profile.achievements.FeedbackResponse
 import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse
 import fr.free.nrw.commons.profile.leaderboard.UpdateAvatarResponse
 import fr.free.nrw.commons.utils.ViewUtilWrapper
 import io.reactivex.Observable
 import io.reactivex.Single
+import kotlinx.coroutines.test.runTest
 import media
 import org.junit.Before
 import org.junit.Test
@@ -58,16 +59,16 @@ class ReasonBuilderTest {
         PowerMockito.`when`(context?.getString(R.string.user_not_logged_in))
             .thenReturn("Log-in expired. Please log in again.")

-        reasonBuilder!!.getReason(mock(Media::class.java), "test")
+        reasonBuilder!!.getReason(mock(Media::class.java), "test").test().await()
         verify(sessionManager, times(1))!!.forceLogin(any(Context::class.java))
     }

     @Test
-    fun getReason() {
+    fun getReason()  = runTest {
         `when`(sessionManager?.userName).thenReturn("Testuser")
         `when`(sessionManager?.doesAccountExist()).thenReturn(true)
-        `when`(okHttpJsonApiClient!!.getAchievements(anyString()))
-            .thenReturn(Single.just(mock(FeedbackResponse::class.java)))
+        `when`(okHttpJsonApiClient!!.getGlobalFileUsages(anyString(), anyInt()))
+            .thenReturn(mock(GlobalFileUsagesResponse::class.java))
         `when`(okHttpJsonApiClient!!.getLeaderboard(anyString(), anyString(), anyString(), anyString(), anyString()))
             .thenReturn(Observable.just(mock(LeaderboardResponse::class.java)))
         `when`(okHttpJsonApiClient!!.setAvatar(anyString(), anyString()))
@@ -75,8 +76,8 @@ class ReasonBuilderTest {

         val media = media(filename = "test_file", dateUploaded = Date())

-        reasonBuilder!!.getReason(media, "test")
+        reasonBuilder!!.getReason(media, "test").test().await()
         verify(sessionManager, times(0))!!.forceLogin(any(Context::class.java))
-        verify(okHttpJsonApiClient, times(1))!!.getAchievements(anyString())
+        verify(okHttpJsonApiClient, times(1))!!.getGlobalFileUsages(anyString(), anyInt())
     }
 }


Remove Welcome screen from the FTUE

<!-- Please read [CONTRIBUTING.md](https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->

## Type of change

- [ ] Feature
- [ ] Bugfix
- [ ] Technical
- [x] Other : UI flow changes

## Content

- Remove `WelcomeScreen` from the FTUE flow.

## Motivation and context

Closes #2584.

## Screenshots / GIFs

A few screenshots should have been removed.

## Tests

<!-- Explain how you tested your development -->

- Log into the app.

The welcome screen, which should appear as the first step in the FTUE flow, should be gone. You should see the notification permission screen instead in API >= 33 or the analytics one in API < 33.

## Tested devices

- [ ] Physical
- [x] Emulator
- OS version(s): 12, 13.

## Checklist

<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->

- [ ] Changes have been tested on an Android device or Android emulator with API 23
- [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [x] Pull request is based on the develop branch
- [x] Pull request includes a new file under ./changelog.d. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#changelog
- [x] Pull request includes screenshots or videos if containing UI changes
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
- [x] You've made a self review of your PR

[Task] FTUE - Remove the welcome screen

[Task] FTUE - Remove the welcome screen
Please see and discuss the details in the meta issue.

./gradlew :features:ftue:impl:testDebugUnitTest --tests "io.element.android.features.ftue.impl.DefaultFtueStateTests"

diff --git a/changelog.d/2584.misc b/changelog.d/2584.misc
new file mode 100644
index 00000000000..de85b9d90fa
--- /dev/null
+++ b/changelog.d/2584.misc
@@ -0,0 +1,1 @@
+Remove Welcome screen from the FTUE.
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
index 983e0c8db2e..652b6dddd40 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt
@@ -36,7 +36,6 @@ import io.element.android.features.ftue.api.FtueEntryPoint
 import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode
 import io.element.android.features.ftue.impl.state.DefaultFtueState
 import io.element.android.features.ftue.impl.state.FtueStep
-import io.element.android.features.ftue.impl.welcome.WelcomeNode
 import io.element.android.features.lockscreen.api.LockScreenEntryPoint
 import io.element.android.libraries.architecture.BackstackView
 import io.element.android.libraries.architecture.BaseFlowNode
@@ -73,9 +72,6 @@ class FtueFlowNode @AssistedInject constructor(
         @Parcelize
         data object Placeholder : NavTarget

-        @Parcelize
-        data object WelcomeScreen : NavTarget
-
         @Parcelize
         data object NotificationsOptIn : NavTarget

@@ -110,15 +106,6 @@ class FtueFlowNode @AssistedInject constructor(
             NavTarget.Placeholder -> {
                 createNode<PlaceholderNode>(buildContext)
             }
-            NavTarget.WelcomeScreen -> {
-                val callback = object : WelcomeNode.Callback {
-                    override fun onContinueClicked() {
-                        ftueState.setWelcomeScreenShown()
-                        lifecycleScope.launch { moveToNextStep() }
-                    }
-                }
-                createNode<WelcomeNode>(buildContext, listOf(callback))
-            }
             NavTarget.NotificationsOptIn -> {
                 val callback = object : NotificationsOptInNode.Callback {
                     override fun onNotificationsOptInFinished() {
@@ -146,9 +133,6 @@ class FtueFlowNode @AssistedInject constructor(

     private fun moveToNextStep() {
         when (ftueState.getNextStep()) {
-            FtueStep.WelcomeScreen -> {
-                backstack.newRoot(NavTarget.WelcomeScreen)
-            }
             FtueStep.NotificationsOptIn -> {
                 backstack.newRoot(NavTarget.NotificationsOptIn)
             }
diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
index ce7a769187f..f1a1c84545e 100644
--- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
+++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt
@@ -21,7 +21,6 @@ import android.os.Build
 import androidx.annotation.VisibleForTesting
 import com.squareup.anvil.annotations.ContributesBinding
 import io.element.android.features.ftue.api.state.FtueState
-import io.element.android.features.ftue.impl.welcome.state.WelcomeScreenState
 import io.element.android.features.lockscreen.api.LockScreenService
 import io.element.android.libraries.di.SessionScope
 import io.element.android.libraries.permissions.api.PermissionStateProvider
@@ -40,14 +39,12 @@ class DefaultFtueState @Inject constructor(
     private val sdkVersionProvider: BuildVersionSdkIntProvider,
     coroutineScope: CoroutineScope,
     private val analyticsService: AnalyticsService,
-    private val welcomeScreenState: WelcomeScreenState,
     private val permissionStateProvider: PermissionStateProvider,
     private val lockScreenService: LockScreenService,
 ) : FtueState {
     override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete())

     override suspend fun reset() {
-        welcomeScreenState.reset()
         analyticsService.reset()
         if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
             permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
@@ -62,12 +59,7 @@ class DefaultFtueState @Inject constructor(

     fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
         when (currentStep) {
-            null -> if (shouldDisplayWelcomeScreen()) {
-                FtueStep.WelcomeScreen
-            } else {
-                getNextStep(FtueStep.WelcomeScreen)
-            }
-            FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) {
+            null -> if (shouldAskNotificationPermissions()) {
                 FtueStep.NotificationsOptIn
             } else {
                 getNextStep(FtueStep.NotificationsOptIn)
@@ -87,7 +79,6 @@ class DefaultFtueState @Inject constructor(

     private fun isAnyStepIncomplete(): Boolean {
         return listOf(
-            { shouldDisplayWelcomeScreen() },
             { shouldAskNotificationPermissions() },
             { needsAnalyticsOptIn() },
             { shouldDisplayLockscreenSetup() },
@@ -99,10 +90,6 @@ class DefaultFtueState @Inject constructor(
         return runBlocking { analyticsService.didAskUserConsent().first().not() }
     }

-    private fun shouldDisplayWelcomeScreen(): Boolean {
-        return welcomeScreenState.isWelcomeScreenNeeded()
-    }
-
     private fun shouldAskNotificationPermissions(): Boolean {
         return if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
             val permission = Manifest.permission.POST_NOTIFICATIONS
@@ -120,11 +107,6 @@ class DefaultFtueState @Inject constructor(
         }
     }

-    fun setWelcomeScreenShown() {
-        welcomeScreenState.setWelcomeScreenShown()
-        updateState()
-    }
-
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     internal fun updateState() {
         shouldDisplayFlow.value = isAnyStepIncomplete()
@@ -132,7 +114,6 @@ class DefaultFtueState @Inject constructor(
 }

 sealed interface FtueStep {
-    data object WelcomeScreen : FtueStep
     data object NotificationsOptIn : FtueStep
     data object AnalyticsOptIn : FtueStep
     data object LockscreenSetup : FtueStep

diff --git a/.maestro/tests/account/login.yaml b/.maestro/tests/account/login.yaml
index 397cc61f5c8..dcb5cd32234 100644
--- a/.maestro/tests/account/login.yaml
+++ b/.maestro/tests/account/login.yaml
@@ -23,8 +23,6 @@ appId: ${MAESTRO_APP_ID}
 - inputText: ${MAESTRO_PASSWORD}
 - pressKey: Enter
 - tapOn: "Continue"
-- runFlow: ../assertions/assertWelcomeScreenDisplayed.yaml
-- tapOn: "Continue"
 - runFlow: ../assertions/assertAnalyticsDisplayed.yaml
 - tapOn: "Not now"
 - runFlow: ../assertions/assertHomeDisplayed.yaml
diff --git a/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml b/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml
deleted file mode 100644
index 340d21ff2e0..00000000000
--- a/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-appId: ${MAESTRO_APP_ID}
----
-- extendedWaitUntil:
-    visible:
-      id: "welcome_screen-title"
-    timeout: 10000
diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
index 834aaa5c1f4..1f0b8178509 100644
--- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
+++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt
@@ -20,7 +20,6 @@ import android.os.Build
 import com.google.common.truth.Truth.assertThat
 import io.element.android.features.ftue.impl.state.DefaultFtueState
 import io.element.android.features.ftue.impl.state.FtueStep
-import io.element.android.features.ftue.impl.welcome.state.FakeWelcomeState
 import io.element.android.features.lockscreen.api.LockScreenService
 import io.element.android.features.lockscreen.test.FakeLockScreenService
 import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
@@ -47,7 +46,6 @@ class DefaultFtueStateTests {

     @Test
     fun `given all checks being true, should display flow is false`() = runTest {
-        val welcomeState = FakeWelcomeState()
         val analyticsService = FakeAnalyticsService()
         val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true)
         val lockScreenService = FakeLockScreenService()
@@ -55,13 +53,11 @@ class DefaultFtueStateTests {

         val state = createState(
             coroutineScope = coroutineScope,
-            welcomeState = welcomeState,
             analyticsService = analyticsService,
             permissionStateProvider = permissionStateProvider,
             lockScreenService = lockScreenService,
         )

-        welcomeState.setWelcomeScreenShown()
         analyticsService.setDidAskUserConsent()
         permissionStateProvider.setPermissionGranted()
         lockScreenService.setIsPinSetup(true)
@@ -75,7 +71,6 @@ class DefaultFtueStateTests {

     @Test
     fun `traverse flow`() = runTest {
-        val welcomeState = FakeWelcomeState()
         val analyticsService = FakeAnalyticsService()
         val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
         val lockScreenService = FakeLockScreenService()
@@ -83,26 +78,21 @@ class DefaultFtueStateTests {

         val state = createState(
             coroutineScope = coroutineScope,
-            welcomeState = welcomeState,
             analyticsService = analyticsService,
             permissionStateProvider = permissionStateProvider,
             lockScreenService = lockScreenService,
         )
         val steps = mutableListOf<FtueStep?>()

-        // First step, welcome screen
-        steps.add(state.getNextStep(steps.lastOrNull()))
-        welcomeState.setWelcomeScreenShown()
-
-        // Second step, notifications opt in
+        // Notifications opt in
         steps.add(state.getNextStep(steps.lastOrNull()))
         permissionStateProvider.setPermissionGranted()

-        // Third step, entering PIN code
+        // Entering PIN code
         steps.add(state.getNextStep(steps.lastOrNull()))
         lockScreenService.setIsPinSetup(true)

-        // Fourth step, analytics opt in
+        // Analytics opt in
         steps.add(state.getNextStep(steps.lastOrNull()))
         analyticsService.setDidAskUserConsent()

@@ -110,7 +100,6 @@ class DefaultFtueStateTests {
         steps.add(state.getNextStep(steps.lastOrNull()))

         assertThat(steps).containsExactly(
-            FtueStep.WelcomeScreen,
             FtueStep.NotificationsOptIn,
             FtueStep.LockscreenSetup,
             FtueStep.AnalyticsOptIn,
@@ -135,15 +124,14 @@ class DefaultFtueStateTests {
             lockScreenService = lockScreenService,
         )

-        // Skip first 3 steps
-        state.setWelcomeScreenShown()
+        // Skip first 2 steps
         permissionStateProvider.setPermissionGranted()
         lockScreenService.setIsPinSetup(true)

         assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)

         analyticsService.setDidAskUserConsent()
-        assertThat(state.getNextStep(FtueStep.WelcomeScreen)).isNull()
+        assertThat(state.getNextStep(null)).isNull()

         // Cleanup
         coroutineScope.cancel()
@@ -162,14 +150,12 @@ class DefaultFtueStateTests {
             lockScreenService = lockScreenService,
         )

-        assertThat(state.getNextStep()).isEqualTo(FtueStep.WelcomeScreen)
-        state.setWelcomeScreenShown()
         lockScreenService.setIsPinSetup(true)

         assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)

         analyticsService.setDidAskUserConsent()
-        assertThat(state.getNextStep(FtueStep.WelcomeScreen)).isNull()
+        assertThat(state.getNextStep(null)).isNull()

         // Cleanup
         coroutineScope.cancel()
@@ -177,7 +163,6 @@ class DefaultFtueStateTests {

     private fun createState(
         coroutineScope: CoroutineScope,
-        welcomeState: FakeWelcomeState = FakeWelcomeState(),
         analyticsService: AnalyticsService = FakeAnalyticsService(),
         permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
         lockScreenService: LockScreenService = FakeLockScreenService(),
@@ -187,7 +172,6 @@ class DefaultFtueStateTests {
         sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion),
         coroutineScope = coroutineScope,
         analyticsService = analyticsService,
-        welcomeScreenState = welcomeState,
         permissionStateProvider = permissionStateProvider,
         lockScreenService = lockScreenService,
     )