Browse Source

Contacts Activity Compose

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
sowjanyakch 7 months ago
parent
commit
bb46b6adad
25 changed files with 1188 additions and 316 deletions
  1. 1 0
      .editorconfig
  2. 37 1
      .idea/inspectionProfiles/ktlint.xml
  3. 29 0
      app/build.gradle
  4. 3 0
      app/src/main/AndroidManifest.xml
  5. 0 220
      app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java
  6. 199 0
      app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt
  7. 0 89
      app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.java
  8. 78 0
      app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.kt
  9. 42 0
      app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt
  10. 7 1
      app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt
  11. 335 0
      app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt
  12. 16 0
      app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt
  13. 65 0
      app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt
  14. 110 0
      app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt
  15. 115 0
      app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt
  16. 16 0
      app/src/main/java/com/nextcloud/talk/contacts/ShareType.kt
  17. 2 2
      app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt
  18. 1 0
      app/src/main/java/com/nextcloud/talk/dagger/modules/BusModule.java
  19. 9 0
      app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt
  20. 10 0
      app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java
  21. 6 0
      app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt
  22. 5 0
      app/src/main/res/drawable/baseline_chat_bubble_outline_24.xml
  23. 8 1
      app/src/main/res/values/strings.xml
  24. 6 2
      build.gradle
  25. 88 0
      gradle/verification-metadata.xml

+ 1 - 0
.editorconfig

@@ -51,3 +51,4 @@ ktlint_standard_import-ordering = disabled
 ktlint_standard_wrapping = enabled
 ij_kotlin_allow_trailing_comma = false
 ij_kotlin_allow_trailing_comma_on_call_site = false
+ktlint_function_naming_ignore_when_annotated_with = Composable

+ 37 - 1
.idea/inspectionProfiles/ktlint.xml

@@ -2,6 +2,42 @@
   <profile version="1.0">
     <option name="myName" value="ktlint" />
     <inspection_tool class="KotlinUnusedImport" enabled="true" level="ERROR" enabled_by_default="true" />
+    <inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+      <option name="previewFile" value="true" />
+    </inspection_tool>
     <inspection_tool class="RedundantSemicolon" enabled="true" level="ERROR" enabled_by_default="true" />
   </profile>
-</component>
+</component>

+ 29 - 0
app/build.gradle

@@ -26,6 +26,7 @@ apply plugin: 'com.github.spotbugs'
 apply plugin: 'io.gitlab.arturbosch.detekt'
 apply plugin: "org.jlleitschuh.gradle.ktlint"
 apply plugin: 'kotlinx-serialization'
+apply plugin: 'dagger.hilt.android.plugin'
 
 android {
     compileSdk 34
@@ -45,6 +46,7 @@ android {
         flavorDimensions "default"
         renderscriptTargetApi 19
         renderscriptSupportModeEnabled true
+        javaCompileOptions.annotationProcessorOptions.arguments['dagger.hilt.disableModulesHaveInstallInCheck'] = 'true'
 
         productFlavors {
             // used for f-droid
@@ -121,6 +123,11 @@ android {
     buildFeatures {
         viewBinding true
         buildConfig = true
+        compose = true
+    }
+
+    composeOptions {
+        kotlinCompilerExtensionVersion = "1.5.13"
     }
 
     lint {
@@ -130,6 +137,9 @@ android {
         htmlReport true
     }
 }
+kapt {
+    correctErrorTypes = true
+}
 
 ext {
     androidxCameraVersion = "1.3.4"
@@ -259,6 +269,7 @@ dependencies {
     implementation "com.afollestad.material-dialogs:lifecycle:${materialDialogsVersion}"
 
     implementation 'com.google.code.gson:gson:2.11.0'
+    implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
 
     implementation "androidx.media3:media3-exoplayer:$media3_version"
     implementation "androidx.media3:media3-ui:$media3_version"
@@ -280,6 +291,19 @@ dependencies {
 
     implementation 'androidx.core:core-ktx:1.13.1'
 
+    //compose
+    implementation(platform("androidx.compose:compose-bom:2024.02.01"))
+    implementation("androidx.compose.ui:ui")
+    implementation 'androidx.compose.material3:material3'
+    implementation("androidx.compose.ui:ui-tooling-preview")
+    implementation 'androidx.activity:activity-compose:1.9.0'
+    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.1'
+    debugImplementation("androidx.compose.ui:ui-tooling")
+
+    //tests
+    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
+    debugImplementation("androidx.compose.ui:ui-test-manifest")
+
     testImplementation 'junit:junit:4.13.2'
     testImplementation 'org.mockito:mockito-core:5.12.0'
     androidTestImplementation 'org.mockito:mockito-android:5.12.0'
@@ -307,6 +331,11 @@ dependencies {
     implementation 'com.github.nextcloud.android-common:ui:0.22.0'
 
     implementation 'com.github.nextcloud-deps:android-talk-webrtc:121.6167.0'
+    implementation(platform("androidx.compose:compose-bom:2024.06.00"))
+    implementation("io.coil-kt:coil-compose:2.6.0")
+
+    implementation "com.google.dagger:hilt-android:$hilt_version"
+    kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
 }
 
 tasks.register('installGitHooks', Copy) {

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -126,6 +126,9 @@
             android:name=".account.WebViewLoginActivity"
             android:theme="@style/AppTheme" />
 
+        <activity android:name=".contacts.ContactsActivityCompose"
+            android:theme="@style/AppTheme"/>
+
         <activity
             android:name=".account.AccountVerificationActivity"
             android:theme="@style/AppTheme" />

+ 0 - 220
app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.java

@@ -1,220 +0,0 @@
-/*
- * Nextcloud Talk - Android Client
- *
- * SPDX-FileCopyrightText: 2022 Marcel Hibbe <dev@mhibbe.de>
- * SPDX-FileCopyrightText: 2021 Andy Scherzinger <infoi@andy-scherzinger.de>
- * SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-package com.nextcloud.talk.adapters.items;
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-import android.text.TextUtils;
-import android.view.View;
-
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import com.nextcloud.talk.data.user.model.User;
-import com.nextcloud.talk.databinding.RvItemContactBinding;
-import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
-import com.nextcloud.talk.models.json.participants.Participant;
-import com.nextcloud.talk.ui.theme.ViewThemeUtils;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.regex.Pattern;
-
-import androidx.core.content.res.ResourcesCompat;
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
-import eu.davidea.flexibleadapter.items.IFilterable;
-import eu.davidea.flexibleadapter.items.ISectionable;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemViewHolder> implements
-    ISectionable<ContactItem.ContactItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
-
-    private final Participant participant;
-    private final User user;
-    private GenericTextHeaderItem header;
-    private final ViewThemeUtils viewThemeUtils;
-    public boolean isOnline = true;
-
-    public ContactItem(Participant participant,
-                       User user,
-                       GenericTextHeaderItem genericTextHeaderItem,
-                       ViewThemeUtils viewThemeUtils) {
-        this.participant = participant;
-        this.user = user;
-        this.header = genericTextHeaderItem;
-        this.viewThemeUtils = viewThemeUtils;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof ContactItem inItem) {
-            return participant.getCalculatedActorType() == inItem.getModel().getCalculatedActorType() &&
-                participant.getCalculatedActorId().equals(inItem.getModel().getCalculatedActorId());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return participant.hashCode();
-    }
-
-    /**
-     * @return the model object
-     */
-    public Participant getModel() {
-        return participant;
-    }
-
-
-    @Override
-    public int getLayoutRes() {
-        return R.layout.rv_item_contact;
-    }
-
-    @Override
-    public ContactItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new ContactItemViewHolder(view, adapter);
-    }
-
-    @SuppressLint("SetTextI18n")
-    @Override
-    public void bindViewHolder(FlexibleAdapter adapter, ContactItemViewHolder holder, int position, List payloads) {
-
-        if (participant.getSelected()) {
-            viewThemeUtils.platform.colorImageView(holder.binding.checkedImageView);
-            holder.binding.checkedImageView.setVisibility(View.VISIBLE);
-        } else {
-            holder.binding.checkedImageView.setVisibility(View.GONE);
-        }
-
-        if (!isOnline) {
-            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
-                                                     holder.binding.nameText.getContext().getResources(),
-                                                     R.color.medium_emphasis_text,
-                                                     null)
-                                                );
-            holder.binding.avatarView.setAlpha(0.38f);
-        } else {
-            holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
-                                                     holder.binding.nameText.getContext().getResources(),
-                                                     R.color.high_emphasis_text,
-                                                     null)
-                                                );
-            holder.binding.avatarView.setAlpha(1.0f);
-        }
-
-        holder.binding.nameText.setText(participant.getDisplayName());
-
-        if (adapter.hasFilter()) {
-            viewThemeUtils.talk.themeAndHighlightText(holder.binding.nameText,
-                                                      participant.getDisplayName(),
-                                                      String.valueOf(adapter.getFilter(String.class)));
-        }
-
-        if (TextUtils.isEmpty(participant.getDisplayName()) &&
-            (participant.getType() == Participant.ParticipantType.GUEST ||
-                participant.getType() == Participant.ParticipantType.USER_FOLLOWING_LINK)) {
-            holder.binding.nameText.setText(NextcloudTalkApplication
-                                                .Companion
-                                                .getSharedApplication()
-                                                .getString(R.string.nc_guest));
-        }
-
-        if (
-            participant.getCalculatedActorType() == Participant.ActorType.GROUPS ||
-                participant.getCalculatedActorType() == Participant.ActorType.CIRCLES) {
-
-            setGenericAvatar(holder, R.drawable.ic_avatar_group, R.drawable.ic_circular_group);
-
-        } else if (participant.getCalculatedActorType() == Participant.ActorType.EMAILS) {
-
-            setGenericAvatar(holder, R.drawable.ic_avatar_mail, R.drawable.ic_circular_mail);
-
-        } else if (
-            participant.getCalculatedActorType() == Participant.ActorType.GUESTS ||
-                participant.getType() == Participant.ParticipantType.GUEST ||
-                participant.getType() == Participant.ParticipantType.GUEST_MODERATOR) {
-
-            String displayName;
-
-            if (!TextUtils.isEmpty(participant.getDisplayName())) {
-                displayName = participant.getDisplayName();
-            } else {
-                displayName = Objects.requireNonNull(NextcloudTalkApplication.Companion.getSharedApplication())
-                    .getResources().getString(R.string.nc_guest);
-            }
-
-            // absolute fallback to prevent NPE deference
-            if (displayName == null) {
-                displayName = "Guest";
-            }
-
-            ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, user, displayName, true, false);
-        } else if (participant.getCalculatedActorType() == Participant.ActorType.USERS) {
-            ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView,
-                                                 user,
-                                                 participant.getCalculatedActorId(),
-                                                 true,
-                                                 false);
-        }
-    }
-
-    private void setGenericAvatar(
-        ContactItemViewHolder holder,
-        int roundPlaceholderDrawable,
-        int fallbackImageResource) {
-        Object avatar;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            avatar = viewThemeUtils.talk.themePlaceholderAvatar(
-                holder.binding.avatarView,
-                roundPlaceholderDrawable
-                                                               );
-
-        } else {
-            avatar = fallbackImageResource;
-        }
-
-        ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, avatar);
-    }
-
-    @Override
-    public boolean filter(String constraint) {
-        return participant.getDisplayName() != null &&
-            (Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
-                .matcher(participant.getDisplayName().trim())
-                .find() ||
-                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
-                    .matcher(participant.getCalculatedActorId().trim())
-                    .find());
-    }
-
-    @Override
-    public GenericTextHeaderItem getHeader() {
-        return header;
-    }
-
-    @Override
-    public void setHeader(GenericTextHeaderItem header) {
-        this.header = header;
-    }
-
-    static class ContactItemViewHolder extends FlexibleViewHolder {
-
-        RvItemContactBinding binding;
-
-        /**
-         * Default constructor.
-         */
-        ContactItemViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter);
-            binding = RvItemContactBinding.bind(view);
-        }
-    }
-}

+ 199 - 0
app/src/main/java/com/nextcloud/talk/adapters/items/ContactItem.kt

@@ -0,0 +1,199 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2022 Marcel Hibbe <dev@mhibbe.de>
+ * SPDX-FileCopyrightText: 2021 Andy Scherzinger <infoi@andy-scherzinger.de>
+ * SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+package com.nextcloud.talk.adapters.items
+
+import android.os.Build
+import android.text.TextUtils
+import android.view.View
+import androidx.core.content.res.ResourcesCompat
+import androidx.recyclerview.widget.RecyclerView
+import com.nextcloud.talk.R
+import com.nextcloud.talk.adapters.items.ContactItem.ContactItemViewHolder
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.databinding.RvItemContactBinding
+import com.nextcloud.talk.extensions.loadUserAvatar
+import com.nextcloud.talk.models.json.participants.Participant
+import com.nextcloud.talk.ui.theme.ViewThemeUtils
+import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
+import eu.davidea.flexibleadapter.items.IFilterable
+import eu.davidea.flexibleadapter.items.IFlexible
+import eu.davidea.flexibleadapter.items.ISectionable
+import eu.davidea.viewholders.FlexibleViewHolder
+import java.util.Objects
+import java.util.regex.Pattern
+
+class ContactItem(
+    /**
+     * @return the model object
+     */
+    val model: Participant,
+    private val user: User,
+    private var header: GenericTextHeaderItem?,
+    private val viewThemeUtils: ViewThemeUtils
+) : AbstractFlexibleItem<ContactItemViewHolder?>(),
+    ISectionable<ContactItemViewHolder?, GenericTextHeaderItem?>,
+    IFilterable<String?> {
+    var isOnline: Boolean = true
+
+    override fun equals(o: Any?): Boolean {
+        if (o is ContactItem) {
+            return model.calculatedActorType == o.model.calculatedActorType &&
+                model.calculatedActorId == o.model.calculatedActorId
+        }
+        return false
+    }
+    override fun hashCode(): Int {
+        return model.hashCode()
+    }
+
+    override fun filter(constraint: String?): Boolean {
+        return model.displayName != null &&
+            (
+                Pattern.compile(constraint!!, Pattern.CASE_INSENSITIVE or Pattern.LITERAL)
+                    .matcher(model.displayName!!.trim { it <= ' ' })
+                    .find() ||
+                    Pattern.compile(constraint!!, Pattern.CASE_INSENSITIVE or Pattern.LITERAL)
+                        .matcher(model.calculatedActorId!!.trim { it <= ' ' })
+                        .find()
+                )
+    }
+
+    override fun getLayoutRes(): Int {
+        return R.layout.rv_item_contact
+    }
+
+    override fun createViewHolder(
+        view: View?,
+        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?
+    ): ContactItemViewHolder {
+        return ContactItemViewHolder(view, adapter)
+    }
+
+    override fun bindViewHolder(
+        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?,
+        holder: ContactItemViewHolder?,
+        position: Int,
+        payloads: List<Any>?
+    ) {
+        if (model.selected) {
+            holder?.binding?.checkedImageView?.let { viewThemeUtils.platform.colorImageView(it) }
+            holder?.binding?.checkedImageView?.visibility = View.VISIBLE
+        } else {
+            holder?.binding?.checkedImageView?.visibility = View.GONE
+        }
+
+        if (!isOnline) {
+            holder?.binding?.nameText?.setTextColor(
+                ResourcesCompat.getColor(
+                    holder.binding.nameText.context.resources,
+                    R.color.medium_emphasis_text,
+                    null
+                )
+            )
+            holder?.binding?.avatarView?.alpha = 0.38f
+        } else {
+            holder?.binding?.nameText?.setTextColor(
+                ResourcesCompat.getColor(
+                    holder.binding.nameText.context.resources,
+                    R.color.high_emphasis_text,
+                    null
+                )
+            )
+            holder?.binding?.avatarView?.alpha = 1.0f
+        }
+
+        holder?.binding?.nameText?.text = model.displayName
+
+        if (adapter != null) {
+            if (adapter.hasFilter()) {
+                holder?.binding?.let {
+                    viewThemeUtils.talk.themeAndHighlightText(
+                        it.nameText,
+                        model.displayName,
+                        adapter.getFilter(String::class.java).toString()
+                    )
+                }
+            }
+        }
+
+        if (TextUtils.isEmpty(model.displayName) &&
+            (
+                model.type == Participant.ParticipantType.GUEST ||
+                    model.type == Participant.ParticipantType.USER_FOLLOWING_LINK
+                )
+        ) {
+            holder?.binding?.nameText?.text = sharedApplication!!.getString(R.string.nc_guest)
+        }
+
+        if (model.calculatedActorType == Participant.ActorType.GROUPS ||
+            model.calculatedActorType == Participant.ActorType.CIRCLES
+        ) {
+            setGenericAvatar(holder!!, R.drawable.ic_avatar_group, R.drawable.ic_circular_group)
+        } else if (model.calculatedActorType == Participant.ActorType.EMAILS) {
+            setGenericAvatar(holder!!, R.drawable.ic_avatar_mail, R.drawable.ic_circular_mail)
+        } else if (model.calculatedActorType == Participant.ActorType.GUESTS ||
+            model.type == Participant.ParticipantType.GUEST || model.type == Participant.ParticipantType.GUEST_MODERATOR
+        ) {
+            var displayName: String?
+
+            displayName = if (!TextUtils.isEmpty(model.displayName)) {
+                model.displayName
+            } else {
+                Objects.requireNonNull(sharedApplication)!!.resources!!.getString(R.string.nc_guest)
+            }
+
+            // absolute fallback to prevent NPE deference
+            if (displayName == null) {
+                displayName = "Guest"
+            }
+
+            holder?.binding?.avatarView?.loadUserAvatar(user, displayName, true, false)
+        } else if (model.calculatedActorType == Participant.ActorType.USERS) {
+            holder?.binding?.avatarView
+                ?.loadUserAvatar(
+                    user,
+                    model.calculatedActorId!!,
+                    true,
+                    false
+                )
+        }
+    }
+
+    private fun setGenericAvatar(
+        holder: ContactItemViewHolder,
+        roundPlaceholderDrawable: Int,
+        fallbackImageResource: Int
+    ) {
+        val avatar = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            viewThemeUtils.talk.themePlaceholderAvatar(
+                holder.binding.avatarView,
+                roundPlaceholderDrawable
+            )
+        } else {
+            fallbackImageResource
+        }
+
+        holder.binding.avatarView.loadUserAvatar(avatar)
+    }
+
+    override fun getHeader(): GenericTextHeaderItem? {
+        return header
+    }
+
+    override fun setHeader(p0: GenericTextHeaderItem?) {
+        this.header = header
+    }
+
+    class ContactItemViewHolder(view: View?, adapter: FlexibleAdapter<*>?) : FlexibleViewHolder(view, adapter) {
+        var binding: RvItemContactBinding =
+            RvItemContactBinding.bind(view!!)
+    }
+}

+ 0 - 89
app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.java

@@ -1,89 +0,0 @@
-/*
- * Nextcloud Talk - Android Client
- *
- * SPDX-FileCopyrightText: 2022 Andy Scherzinger <infoi@andy-scherzinger.de>
- * SPDX-FileCopyrightText: 2017-2018 Mario Danic <mario@lovelyhq.com>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-package com.nextcloud.talk.adapters.items;
-
-import android.util.Log;
-import android.view.View;
-
-import com.nextcloud.talk.R;
-import com.nextcloud.talk.databinding.RvItemTitleHeaderBinding;
-import com.nextcloud.talk.ui.theme.ViewThemeUtils;
-
-import java.util.List;
-import java.util.Objects;
-
-import eu.davidea.flexibleadapter.FlexibleAdapter;
-import eu.davidea.flexibleadapter.items.AbstractHeaderItem;
-import eu.davidea.flexibleadapter.items.IFlexible;
-import eu.davidea.viewholders.FlexibleViewHolder;
-
-public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
-    private static final String TAG = "GenericTextHeaderItem";
-
-    private final String title;
-    private final ViewThemeUtils viewThemeUtils;
-
-    public GenericTextHeaderItem(String title, ViewThemeUtils viewThemeUtils) {
-        super();
-        setHidden(false);
-        setSelectable(false);
-        this.title = title;
-        this.viewThemeUtils = viewThemeUtils;
-    }
-
-    public String getModel() {
-        return title;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof GenericTextHeaderItem) {
-            GenericTextHeaderItem inItem = (GenericTextHeaderItem) o;
-            return title.equals(inItem.getModel());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(title);
-    }
-
-    @Override
-    public int getLayoutRes() {
-        return R.layout.rv_item_title_header;
-    }
-
-    @Override
-    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, HeaderViewHolder holder, int position, List<Object> payloads) {
-        if (payloads.size() > 0) {
-            Log.d(TAG, "We have payloads, so ignoring!");
-        } else {
-            holder.binding.titleTextView.setText(title);
-            viewThemeUtils.platform.colorPrimaryTextViewElement(holder.binding.titleTextView);
-        }
-    }
-
-    @Override
-    public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
-        return new HeaderViewHolder(view, adapter);
-    }
-
-    static class HeaderViewHolder extends FlexibleViewHolder {
-
-        RvItemTitleHeaderBinding binding;
-
-        /**
-         * Default constructor.
-         */
-        HeaderViewHolder(View view, FlexibleAdapter adapter) {
-            super(view, adapter, true);
-            binding = RvItemTitleHeaderBinding.bind(view);
-        }
-    }
-}

+ 78 - 0
app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.kt

@@ -0,0 +1,78 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2022 Andy Scherzinger <infoi@andy-scherzinger.de>
+ * SPDX-FileCopyrightText: 2017-2018 Mario Danic <mario@lovelyhq.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+package com.nextcloud.talk.adapters.items
+
+import android.util.Log
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import com.nextcloud.talk.R
+import com.nextcloud.talk.databinding.RvItemTitleHeaderBinding
+import com.nextcloud.talk.ui.theme.ViewThemeUtils
+import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.items.AbstractHeaderItem
+import eu.davidea.flexibleadapter.items.IFlexible
+import eu.davidea.viewholders.FlexibleViewHolder
+import java.util.Objects
+
+open class GenericTextHeaderItem(title: String, viewThemeUtils: ViewThemeUtils) :
+    AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder>() {
+    val model: String
+    private val viewThemeUtils: ViewThemeUtils
+
+    init {
+        isHidden = false
+        isSelectable = false
+        this.model = title
+        this.viewThemeUtils = viewThemeUtils
+    }
+
+    override fun equals(o: Any?): Boolean {
+        if (o is GenericTextHeaderItem) {
+            return model == o.model
+        }
+        return false
+    }
+
+    override fun hashCode(): Int {
+        return Objects.hash(model)
+    }
+
+    override fun getLayoutRes(): Int {
+        return R.layout.rv_item_title_header
+    }
+
+    override fun createViewHolder(
+        view: View?,
+        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?
+    ): HeaderViewHolder {
+        return HeaderViewHolder(view, adapter)
+    }
+
+    override fun bindViewHolder(
+        adapter: FlexibleAdapter<IFlexible<*>?>?,
+        holder: HeaderViewHolder,
+        position: Int,
+        payloads: List<Any>
+    ) {
+        if (payloads.size > 0) {
+            Log.d(TAG, "We have payloads, so ignoring!")
+        } else {
+            holder.binding.titleTextView.text = model
+            viewThemeUtils.platform.colorPrimaryTextViewElement(holder.binding.titleTextView)
+        }
+    }
+
+    class HeaderViewHolder(view: View?, adapter: FlexibleAdapter<*>?) : FlexibleViewHolder(view, adapter, true) {
+        var binding: RvItemTitleHeaderBinding =
+            RvItemTitleHeaderBinding.bind(view!!)
+    }
+
+    companion object {
+        private const val TAG = "GenericTextHeaderItem"
+    }
+}

+ 42 - 0
app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

@@ -0,0 +1,42 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.api
+
+import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
+import com.nextcloud.talk.models.json.conversations.RoomOverall
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.POST
+import retrofit2.http.Query
+import retrofit2.http.QueryMap
+import retrofit2.http.Url
+
+interface NcApiCoroutines {
+    @GET
+    @JvmSuppressWildcards
+    suspend fun getContactsWithSearchParam(
+        @Header("Authorization") authorization: String?,
+        @Url url: String?,
+        @Query("shareTypes[]") listOfShareTypes: List<String>?,
+        @QueryMap options: Map<String, Any>?
+    ): AutocompleteOverall
+
+    /*
+        QueryMap items are as follows:
+            - "roomType" : ""
+            - "invite" : ""
+
+        Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room
+     */
+    @POST
+    suspend fun createRoom(
+        @Header("Authorization") authorization: String?,
+        @Url url: String?,
+        @QueryMap options: Map<String, String>?
+    ): RoomOverall
+}

+ 7 - 1
app/src/main/java/com/nextcloud/talk/contacts/ContactsActivity.kt

@@ -125,8 +125,10 @@ class ContactsActivity :
 
         existingParticipants = ArrayList()
         if (intent.hasExtra(BundleKeys.KEY_NEW_CONVERSATION)) {
+            // adding a new conversation, setting a flag.
             isNewConversationView = true
         } else if (intent.hasExtra(BundleKeys.KEY_ADD_PARTICIPANTS)) {
+            // adding the participants in the conversation also opens this activity, setting a flag for it.
             isAddingParticipantsView = true
             conversationToken = intent.getStringExtra(BundleKeys.KEY_TOKEN)
             if (intent.hasExtra(BundleKeys.KEY_EXISTING_PARTICIPANTS)) {
@@ -258,6 +260,7 @@ class ContactsActivity :
 
     private fun selectionDone() {
         if (isAddingParticipantsView) {
+            // add participants in the view
             addParticipantsToConversation()
         } else {
             // if there is only 1 participant, directly add him while creating room (which can only add 'one')
@@ -477,9 +480,11 @@ class ContactsActivity :
                 }
 
                 override fun onNext(responseBody: ResponseBody) {
+                    // getting contacts
                     val newUserItemList = processAutocompleteUserList(responseBody)
 
                     userHeaderItems = HashMap()
+                    // getting the contact list from the endpoints.
                     contactItems!!.addAll(newUserItemList)
 
                     sortUserItems(newUserItemList)
@@ -539,7 +544,7 @@ class ContactsActivity :
                 }
                 val newContactItem = ContactItem(
                     participant,
-                    currentUser,
+                    currentUser!!,
                     userHeaderItems[headerTitle],
                     viewThemeUtils
                 )
@@ -551,6 +556,7 @@ class ContactsActivity :
         return newUserItemList
     }
 
+    // this function displays the title of the contacts activity
     private fun getHeaderTitle(participant: Participant): String {
         return when {
             participant.calculatedActorType == Participant.ActorType.GROUPS -> {

+ 335 - 0
app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt

@@ -0,0 +1,335 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Search
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.lifecycle.ViewModelProvider
+import autodagger.AutoInjector
+import coil.compose.AsyncImage
+import coil.request.ImageRequest
+import coil.transform.CircleCropTransformation
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.chat.ChatActivity
+import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
+import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
+import com.nextcloud.talk.utils.bundle.BundleKeys
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class ContactsActivityCompose : ComponentActivity() {
+
+    @Inject
+    lateinit var viewModelFactory: ViewModelProvider.Factory
+    private lateinit var contactsViewModel: ContactsViewModel
+
+    @SuppressLint("UnrememberedMutableState")
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
+        contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java]
+
+        setContent {
+            MaterialTheme {
+                val context = LocalContext.current
+                Scaffold(
+                    topBar = {
+                        AppBar(
+                            title = stringResource(R.string.nc_app_product_name),
+                            context = context,
+                            contactsViewModel = contactsViewModel
+                        )
+                    },
+                    content = {
+                        val uiState = contactsViewModel.contactsViewState.collectAsState()
+                        Column(Modifier.padding(it)) {
+                            ConversationCreationOptions(context = context)
+                            ContactsList(
+                                contactsUiState = uiState.value,
+                                contactsViewModel = contactsViewModel,
+                                context = context
+                            )
+                        }
+                    }
+                )
+            }
+        }
+    }
+}
+
+@Composable
+fun ContactsList(contactsUiState: ContactsUiState, contactsViewModel: ContactsViewModel, context: Context) {
+    when (contactsUiState) {
+        is ContactsUiState.None -> {
+        }
+        is ContactsUiState.Loading -> {
+            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+                CircularProgressIndicator()
+            }
+        }
+        is ContactsUiState.Success -> {
+            val contacts = contactsUiState.contacts
+            Log.d(CompanionClass.TAG, "Contacts:$contacts")
+            if (contacts != null) {
+                ContactsItem(contacts, contactsViewModel, context)
+            }
+        }
+        is ContactsUiState.Error -> {
+            val errorMessage = contactsUiState.message
+            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+                Text(text = "Error: $errorMessage", color = Color.Red)
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun ContactsItem(contacts: List<AutocompleteUser>, contactsViewModel: ContactsViewModel, context: Context) {
+    val groupedContacts: Map<String, List<AutocompleteUser>> = contacts.groupBy { contact ->
+        (
+            if (contact.source == "users") {
+                contact.label?.first()?.uppercase()
+            } else {
+                contact.source?.replaceFirstChar { actorType ->
+                    actorType.uppercase()
+                }
+            }
+            ).toString()
+    }
+    LazyColumn(
+        modifier = Modifier
+            .padding(8.dp)
+            .fillMaxWidth(),
+        contentPadding = PaddingValues(all = 10.dp),
+        verticalArrangement = Arrangement.spacedBy(10.dp)
+    ) {
+        groupedContacts.forEach { (initial, contactsForInitial) ->
+            stickyHeader {
+                Column {
+                    Surface(Modifier.fillParentMaxWidth()) {
+                        Header(initial)
+                    }
+                    HorizontalDivider(thickness = 0.1.dp, color = Color.Black)
+                }
+            }
+            items(contactsForInitial) { contact ->
+                ContactItemRow(contact = contact, contactsViewModel = contactsViewModel, context = context)
+            }
+        }
+    }
+}
+
+@Composable
+fun Header(header: String) {
+    Text(
+        text = header,
+        modifier = Modifier
+            .fillMaxSize()
+            .background(Color.Transparent)
+            .padding(start = 60.dp),
+        color = Color.Blue,
+        fontWeight = FontWeight.Bold
+    )
+}
+
+@Composable
+fun ContactItemRow(contact: AutocompleteUser, contactsViewModel: ContactsViewModel, context: Context) {
+    val roomUiState by contactsViewModel.roomViewState.collectAsState()
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .clickable {
+                contactsViewModel.createRoom(
+                    CompanionClass.ROOM_TYPE_ONE_ONE,
+                    contact.source!!,
+                    contact.id!!,
+                    null
+                )
+            },
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        val imageUri = contact.id?.let { contactsViewModel.getImageUri(it, true) }
+        val imageRequest = ImageRequest.Builder(context)
+            .data(imageUri)
+            .transformations(CircleCropTransformation())
+            .error(R.drawable.account_circle_96dp)
+            .placeholder(R.drawable.account_circle_96dp)
+            .build()
+
+        AsyncImage(
+            model = imageRequest,
+            contentDescription = stringResource(R.string.user_avatar),
+            modifier = Modifier.size(width = 45.dp, height = 45.dp)
+        )
+        Text(modifier = Modifier.padding(16.dp), text = contact.label!!)
+    }
+    when (roomUiState) {
+        is RoomUiState.Success -> {
+            val conversation = (roomUiState as RoomUiState.Success).conversation
+            val bundle = Bundle()
+            bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation?.token)
+            bundle.putString(BundleKeys.KEY_ROOM_ID, conversation?.roomId)
+            val chatIntent = Intent(context, ChatActivity::class.java)
+            chatIntent.putExtras(bundle)
+            chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            context.startActivity(chatIntent)
+        }
+        is RoomUiState.Error -> {
+            val errorMessage = (roomUiState as RoomUiState.Error).message
+            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+                Text(text = "Error: $errorMessage", color = Color.Red)
+            }
+        }
+        is RoomUiState.None -> {}
+    }
+}
+
+@SuppressLint("UnrememberedMutableState")
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel) {
+    val searchQuery by contactsViewModel.searchQuery.collectAsState()
+    val searchState = contactsViewModel.searchState.collectAsState()
+    TopAppBar(
+        title = { Text(text = title) },
+        navigationIcon = {
+            IconButton(onClick = {
+                (context as? Activity)?.finish()
+            }) {
+                Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button))
+            }
+        },
+        actions = {
+            IconButton(onClick = {
+                contactsViewModel.updateSearchState(true)
+            }) {
+                Icon(Icons.Filled.Search, contentDescription = stringResource(R.string.search_icon))
+            }
+        }
+    )
+    if (searchState.value) {
+        DisplaySearch(
+            text = searchQuery,
+            onTextChange = { searchQuery ->
+                contactsViewModel.updateSearchQuery(query = searchQuery)
+                contactsViewModel.getContactsFromSearchParams()
+            },
+            contactsViewModel = contactsViewModel
+        )
+    }
+}
+
+@Composable
+fun ConversationCreationOptions(context: Context) {
+    Column {
+        Row(
+            modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp),
+            verticalAlignment = Alignment.CenterVertically
+        ) {
+            Image(
+                modifier = Modifier
+                    .width(40.dp)
+                    .height(40.dp)
+                    .padding(8.dp),
+                painter = painterResource(R.drawable.baseline_chat_bubble_outline_24),
+                contentDescription = stringResource(R.string.new_conversation_creation_icon)
+            )
+            Text(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .wrapContentHeight(),
+                text = stringResource(R.string.nc_create_new_conversation),
+                maxLines = 1,
+                fontSize = 16.sp
+            )
+        }
+        Row(
+            modifier = Modifier
+                .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp)
+                .clickable {
+                    val intent = Intent(context, ListOpenConversationsActivity::class.java)
+                    context.startActivity(intent)
+                },
+            verticalAlignment = Alignment.CenterVertically
+        ) {
+            Image(
+                modifier = Modifier
+                    .width(40.dp)
+                    .height(40.dp)
+                    .padding(8.dp),
+                painter = painterResource(R.drawable.baseline_format_list_bulleted_24),
+                contentDescription = stringResource(R.string.join_open_conversations_icon)
+            )
+            Text(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .wrapContentHeight(),
+                text = stringResource(R.string.nc_join_open_conversations),
+                fontSize = 16.sp
+            )
+        }
+    }
+}
+
+class CompanionClass {
+    companion object {
+        internal val TAG = ContactsActivityCompose::class.simpleName
+        internal const val ROOM_TYPE_ONE_ONE = "1"
+    }
+}

+ 16 - 0
app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt

@@ -0,0 +1,16 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
+import com.nextcloud.talk.models.json.conversations.RoomOverall
+
+interface ContactsRepository {
+    suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall
+    suspend fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?): RoomOverall
+}

+ 65 - 0
app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt

@@ -0,0 +1,65 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+import com.nextcloud.talk.api.NcApiCoroutines
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.models.RetrofitBucket
+import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
+import com.nextcloud.talk.models.json.conversations.RoomOverall
+import com.nextcloud.talk.users.UserManager
+import com.nextcloud.talk.utils.ApiUtils
+
+class ContactsRepositoryImpl(
+    private val ncApiCoroutines: NcApiCoroutines,
+    private val userManager: UserManager
+) : ContactsRepository {
+    private val _currentUser = userManager.currentUser.blockingGet()
+    val currentUser: User = _currentUser
+    val credentials = ApiUtils.getCredentials(_currentUser.username, _currentUser.token)
+    val apiVersion = ApiUtils.getConversationApiVersion(_currentUser, intArrayOf(ApiUtils.API_V4, 1))
+
+    override suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall {
+        val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForContactsSearchFor14(
+            currentUser.baseUrl!!,
+            searchQuery
+        )
+        val modifiedQueryMap: HashMap<String, Any> = HashMap(retrofitBucket.queryMap)
+        modifiedQueryMap["limit"] = 50
+        modifiedQueryMap["shareTypes[]"] = shareTypes
+        val response = ncApiCoroutines.getContactsWithSearchParam(
+            credentials,
+            retrofitBucket.url,
+            shareTypes,
+            modifiedQueryMap
+        )
+        return response
+    }
+
+    override suspend fun createRoom(
+        roomType: String,
+        sourceType: String,
+        userId: String,
+        conversationName: String?
+    ): RoomOverall {
+        val retrofitBucket: RetrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
+            apiVersion,
+            _currentUser.baseUrl,
+            roomType,
+            sourceType,
+            userId,
+            conversationName
+        )
+        val response = ncApiCoroutines.createRoom(
+            credentials,
+            retrofitBucket.url,
+            retrofitBucket.queryMap
+        )
+        return response
+    }
+}

+ 110 - 0
app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt

@@ -0,0 +1,110 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.nextcloud.talk.data.user.model.User
+import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
+import com.nextcloud.talk.models.json.conversations.Conversation
+import com.nextcloud.talk.users.UserManager
+import com.nextcloud.talk.utils.ApiUtils
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+class ContactsViewModel @Inject constructor(
+    private val repository: ContactsRepository,
+    private val userManager: UserManager
+) : ViewModel() {
+
+    private val _contactsViewState = MutableStateFlow<ContactsUiState>(ContactsUiState.None)
+    val contactsViewState: StateFlow<ContactsUiState> = _contactsViewState
+    private val _roomViewState = MutableStateFlow<RoomUiState>(RoomUiState.None)
+    val roomViewState: StateFlow<RoomUiState> = _roomViewState
+    private val _currentUser = userManager.currentUser.blockingGet()
+    val currentUser: User = _currentUser
+    private val _searchQuery = MutableStateFlow("")
+    val searchQuery: StateFlow<String> = _searchQuery
+    private val shareTypes: MutableList<String> = mutableListOf(ShareType.User.shareType)
+    val shareTypeList: List<String> = shareTypes
+    private val _searchState = MutableStateFlow(false)
+    val searchState: StateFlow<Boolean> = _searchState
+
+    init {
+        getContactsFromSearchParams()
+    }
+
+    fun updateSearchQuery(query: String) {
+        _searchQuery.value = query
+    }
+
+    fun updateSearchState(searchState: Boolean) {
+        _searchState.value = searchState
+    }
+
+    fun updateShareTypes(value: String) {
+        shareTypes.add(value)
+    }
+
+    fun getContactsFromSearchParams() {
+        _contactsViewState.value = ContactsUiState.Loading
+        viewModelScope.launch {
+            try {
+                val contacts = repository.getContacts(
+                    searchQuery.value,
+                    shareTypeList
+                )
+                val contactsList: List<AutocompleteUser>? = contacts.ocs!!.data
+                _contactsViewState.value = ContactsUiState.Success(contactsList)
+            } catch (exception: Exception) {
+                _contactsViewState.value = ContactsUiState.Error(exception.message ?: "")
+            }
+        }
+    }
+
+    fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) {
+        viewModelScope.launch {
+            try {
+                val room = repository.createRoom(
+                    roomType,
+                    sourceType,
+                    userId,
+                    conversationName
+                )
+
+                val conversation: Conversation? = room.ocs?.data
+                _roomViewState.value = RoomUiState.Success(conversation)
+            } catch (exception: Exception) {
+                _roomViewState.value = RoomUiState.Error(exception.message ?: "")
+            }
+        }
+    }
+
+    fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
+        return ApiUtils.getUrlForAvatar(
+            _currentUser.baseUrl,
+            avatarId,
+            requestBigSize
+        )
+    }
+}
+
+sealed class ContactsUiState {
+    data object None : ContactsUiState()
+    data object Loading : ContactsUiState()
+    data class Success(val contacts: List<AutocompleteUser>?) : ContactsUiState()
+    data class Error(val message: String) : ContactsUiState()
+}
+
+sealed class RoomUiState {
+    data object None : RoomUiState()
+    data class Success(val conversation: Conversation?) : RoomUiState()
+    data class Error(val message: String) : RoomUiState()
+}

+ 115 - 0
app/src/main/java/com/nextcloud/talk/contacts/SearchComponent.kt

@@ -0,0 +1,115 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.nextcloud.talk.R
+
+@Composable
+fun DisplaySearch(text: String, onTextChange: (String) -> Unit, contactsViewModel: ContactsViewModel) {
+    Surface(
+        modifier = Modifier
+            .fillMaxWidth()
+            .height(60.dp)
+            .background(Color.White)
+    ) {
+        val keyboardController = LocalSoftwareKeyboardController.current
+        TextField(
+            modifier = Modifier
+                .fillMaxWidth(),
+            value = text,
+            onValueChange = { onTextChange(it) },
+            placeholder = {
+                Text(
+                    text = stringResource(R.string.nc_search),
+                    color = Color.DarkGray
+                )
+            },
+
+            textStyle = TextStyle(
+                color = Color.Black,
+                fontSize = 16.sp
+            ),
+            singleLine = true,
+            leadingIcon = {
+                IconButton(
+                    onClick = {
+                        onTextChange("")
+                        contactsViewModel.updateSearchState(false)
+                    }
+                ) {
+                    Icon(
+                        imageVector = Icons.AutoMirrored.Default.ArrowBack,
+                        contentDescription = stringResource(R.string.back_button),
+                        tint = Color.Black
+                    )
+                }
+            },
+
+            trailingIcon = {
+                if (text.isNotEmpty()) {
+                    IconButton(
+                        onClick = {
+                            onTextChange("")
+                        }
+                    ) {
+                        Icon(
+                            imageVector = Icons.Default.Close,
+                            contentDescription = stringResource(R.string.close_icon),
+                            tint = Color.Black
+                        )
+                    }
+                }
+            },
+
+            keyboardOptions = KeyboardOptions(
+                imeAction = ImeAction.Search
+            ),
+
+            keyboardActions = KeyboardActions(
+                onSearch = {
+                    if (text.trim().isNotEmpty()) {
+                        keyboardController?.hide()
+                    } else {
+                        return@KeyboardActions
+                    }
+                }
+            ),
+            maxLines = 1,
+            colors = TextFieldDefaults.colors(
+                focusedContainerColor = Color.White,
+                unfocusedContainerColor = Color.White,
+                disabledContainerColor = Color.White,
+                focusedTextColor = Color.Black,
+                cursorColor = Color.Black
+            )
+        )
+    }
+}

+ 16 - 0
app/src/main/java/com/nextcloud/talk/contacts/ShareType.kt

@@ -0,0 +1,16 @@
+/*
+ * Nextcloud Talk - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package com.nextcloud.talk.contacts
+
+enum class ShareType(val shareType: String) {
+    User("0"),
+    Group("1"),
+    Email(""),
+    Circle(""),
+    Federated("")
+}

+ 2 - 2
app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt

@@ -78,7 +78,7 @@ import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
 import com.nextcloud.talk.chat.ChatActivity
-import com.nextcloud.talk.contacts.ContactsActivity
+import com.nextcloud.talk.contacts.ContactsActivityCompose
 import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.databinding.ActivityConversationsBinding
@@ -1072,7 +1072,7 @@ class ConversationsListActivity :
             conversation.type === Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
 
     private fun showNewConversationsScreen() {
-        val intent = Intent(context, ContactsActivity::class.java)
+        val intent = Intent(context, ContactsActivityCompose::class.java)
         intent.putExtra(KEY_NEW_CONVERSATION, true)
         startActivity(intent)
     }

+ 1 - 0
app/src/main/java/com/nextcloud/talk/dagger/modules/BusModule.java

@@ -8,6 +8,7 @@ package com.nextcloud.talk.dagger.modules;
 
 import dagger.Module;
 import dagger.Provides;
+
 import org.greenrobot.eventbus.EventBus;
 
 import javax.inject.Singleton;

+ 9 - 0
app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt

@@ -10,8 +10,11 @@
 package com.nextcloud.talk.dagger.modules
 
 import com.nextcloud.talk.api.NcApi
+import com.nextcloud.talk.api.NcApiCoroutines
 import com.nextcloud.talk.chat.data.ChatRepository
 import com.nextcloud.talk.chat.data.network.NetworkChatRepositoryImpl
+import com.nextcloud.talk.contacts.ContactsRepository
+import com.nextcloud.talk.contacts.ContactsRepositoryImpl
 import com.nextcloud.talk.conversation.repository.ConversationRepository
 import com.nextcloud.talk.conversation.repository.ConversationRepositoryImpl
 import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepository
@@ -45,6 +48,7 @@ import com.nextcloud.talk.shareditems.repositories.SharedItemsRepository
 import com.nextcloud.talk.shareditems.repositories.SharedItemsRepositoryImpl
 import com.nextcloud.talk.translate.repositories.TranslateRepository
 import com.nextcloud.talk.translate.repositories.TranslateRepositoryImpl
+import com.nextcloud.talk.users.UserManager
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
 import dagger.Module
@@ -150,4 +154,9 @@ class RepositoryModule {
     fun provideInvitationsRepository(ncApi: NcApi): InvitationsRepository {
         return InvitationsRepositoryImpl(ncApi)
     }
+
+    @Provides
+    fun provideContactsRepository(ncApiCoroutines: NcApiCoroutines, userManager: UserManager): ContactsRepository {
+        return ContactsRepositoryImpl(ncApiCoroutines, userManager)
+    }
 }

+ 10 - 0
app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java

@@ -14,6 +14,7 @@ import com.github.aurae.retrofit2.LoganSquareConverterFactory;
 import com.nextcloud.talk.BuildConfig;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
+import com.nextcloud.talk.api.NcApiCoroutines;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.users.UserManager;
 import com.nextcloud.talk.utils.ApiUtils;
@@ -35,6 +36,7 @@ import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.util.concurrent.TimeUnit;
 
+import javax.inject.Named;
 import javax.inject.Singleton;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.X509KeyManager;
@@ -58,6 +60,7 @@ import okhttp3.internal.tls.OkHostnameVerifier;
 import okhttp3.logging.HttpLoggingInterceptor;
 import retrofit2.Retrofit;
 import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
 
 @Module(includes = DatabaseModule.class)
 public class RestModule {
@@ -75,6 +78,13 @@ public class RestModule {
         return retrofit.create(NcApi.class);
     }
 
+    @Singleton
+    @Provides
+    NcApiCoroutines provideNcApiCoroutines(Retrofit retrofit) {
+        return retrofit.create(NcApiCoroutines.class);
+    }
+
+
     @Singleton
     @Provides
     Proxy provideProxy(AppPreferences appPreferences) {

+ 6 - 0
app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt

@@ -10,6 +10,7 @@ package com.nextcloud.talk.dagger.modules
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import com.nextcloud.talk.chat.viewmodels.ChatViewModel
+import com.nextcloud.talk.contacts.ContactsViewModel
 import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel
 import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel
 import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel
@@ -150,4 +151,9 @@ abstract class ViewModelModule {
     @IntoMap
     @ViewModelKey(InvitationsViewModel::class)
     abstract fun invitationsViewModel(viewModel: InvitationsViewModel): ViewModel
+
+    @Binds
+    @IntoMap
+    @ViewModelKey(ContactsViewModel::class)
+    abstract fun contactsViewModel(viewModel: ContactsViewModel): ViewModel
 }

+ 5 - 0
app/src/main/res/drawable/baseline_chat_bubble_outline_24.xml

@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+      
+    <path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,16L6,16l-2,2L4,4h16v12z"/>
+    
+</vector>

+ 8 - 1
app/src/main/res/values/strings.xml

@@ -240,6 +240,8 @@ How to translate with transifex:
     <string name="nc_mark_as_unread">Mark as unread</string>
     <string name="nc_add_to_favorites">Add to favorites</string>
     <string name="nc_remove_from_favorites">Remove from favorites</string>
+    <string name="nc_create_new_conversation">Create a new conversation</string>
+    <string name="nc_join_open_conversations">Join open conversations</string>
 
     <string name="added_to_favorites">Added conversation %1$s to favorites</string>
     <string name="removed_from_favorites">Removed conversation %1$s from favorites</string>
@@ -259,7 +261,10 @@ How to translate with transifex:
     <string name="nc_select_participants">Select participants</string>
     <string name="nc_add_participants">Add participants</string>
     <string name="nc_contacts_done">Done</string>
-
+    <string name="user_avatar">User avatar</string>
+    <string name="back_button">Back button</string>
+    <string name="new_conversation_creation_icon">New Conversation Creation Icon</string>
+    <string name="join_open_conversations_icon">Join Open Conversations Icon</string>
     <!-- Permissions -->
     <string name="nc_permissions_rationale_dialog_title">Please allow permissions</string>
     <string name="nc_permissions_denied">Some permissions were denied.</string>
@@ -379,6 +384,7 @@ How to translate with transifex:
     <string name="openConversations">Open conversations</string>
     <string name="error_loading_chats">There was a problem loading your chats</string>
     <string name="close">Close</string>
+    <string name="close_icon">Close Icon</string>
     <string name="nc_refresh">Refresh</string>
     <string name="nc_check_your_internet">Please check your internet connection</string>
 
@@ -681,6 +687,7 @@ How to translate with transifex:
     <string name="message_search_hint">Search …</string>
     <string name="message_search_begin_typing">Start typing to search …</string>
     <string name="message_search_begin_empty">No search results</string>
+    <string name="search_icon">Search Icon</string>
 
     <!-- Polls -->
     <string name="message_poll_tap_to_open">Tap to open poll</string>

+ 6 - 2
build.gradle

@@ -10,9 +10,12 @@
 buildscript {
 
     ext {
-        kotlinVersion = '2.0.0'
+      kotlinVersion = '1.9.23'
+      hilt_version = '2.44'
+      kotlinVersion = '2.0.0'
     }
 
+
     repositories {
         google()
         gradlePluginPortal()
@@ -25,7 +28,8 @@ buildscript {
         classpath "org.jetbrains.kotlin:kotlin-serialization:${kotlinVersion}"
         classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.19'
         classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6"
-        classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.1"
+        classpath "org.jlleitschuh.gradle:ktlint-gradle:12.1.0"
+        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files

+ 88 - 0
gradle/verification-metadata.xml

@@ -8,6 +8,9 @@
          <trust group="com.github.nextcloud-deps" name="android-talk-webrtc" version="110.5481.0" reason="ships OS specific artifacts (win/linux) - temp global trust"/>
          <trust file=".*-sources[.]jar" regex="true"/>
 		 <trust file="tensorflow-lite-metadata-0.1.0-rc2.pom" reason="differing hash on every CI run - temp global trust"/>
+          <trust group="com.google.dagger" />
+          <trust group="org.javassist" name="javassist" version="3.26.0-GA" reason="java assist"/>
+          <trust group="androidx.fragment"/>
       </trusted-artifacts>
       <ignored-keys>
          <ignored-key id="23778689FBFBE047" reason="Key couldn't be downloaded from any key server"/>
@@ -137,6 +140,7 @@
             <trusting group="androidx.sqlite"/>
             <trusting group="androidx.webkit"/>
             <trusting group="androidx.work"/>
+             <trusting group="androidx.compose.foundation"/>
          </trusted-key>
          <trusted-key id="84789D24DF77A32433CE1F079EB80E92EB2135B1">
             <trusting group="org.apache" name="apache"/>
@@ -219,6 +223,7 @@
          <trusted-key id="E4AC7874F3479A0F1F8ECF9960BB45F36B649F22" group="fr.dudie" name="nominatim-api" version="3.4"/>
          <trusted-key id="E77417AC194160A3FABD04969A259C7EE636C5ED" group="^com[.]google($|([.].*))" regex="true"/>
          <trusted-key id="E7DC75FC24FB3C8DFE8086AD3D5839A2262CBBFB" group="org.jetbrains.kotlinx"/>
+          <trusted-key id="64B9B09F164AA0BF88742EB61188B69F6D6259CA" group="com.google.accompanist"/>
          <trusted-key id="E82D2EAF2E83830CE1F7F6BE571A5291E827E1C7" group="net.java" name="jvnet-parent" version="3"/>
          <trusted-key id="E85AED155021AF8A6C6B7A4A7C7D8456294423BA" group="org.objenesis"/>
          <trusted-key id="EAA526B91DD83BA3E1B9636FA730529CA355A63E" group="org.ccil.cowan.tagsoup" name="tagsoup" version="1.2.1"/>
@@ -305,6 +310,50 @@
             <sha256 value="9516c2ae44284ea0bd3d0eade0ee638879b708cbe31e3af92ba96c300604ebc3" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
+       <component group="androidx.exifinterface" name="exifinterface" version="1.3.6">
+           <artifact name="exifinterface-1.3.6.aar">
+               <sha256 value="1804105e9e05fdd8f760413bad5de498c381aa329f4f9d94c851bc891ac654c6" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+           <artifact name="exifinterface-1.3.6.module">
+               <sha256 value="5e9fd84ca3fd3b7706f6856fa4383107de8676bf7c42b7d4b8108949414d6201" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.core" name="core" version="1.1.0">
+           <artifact name="core-1.1.0.pom">
+               <sha256 value="dae46132cdcd46b798425f7cb78fd65890869b6d26101ccdcd43461a4f51754c" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.core" name="core" version="1.3.2">
+           <artifact name="core-1.3.2.pom">
+               <sha256 value="afb5ea494dd083ed404cd51f580d218e37362f8ae326e893bee521290ed34920" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.test.ext" name="junit" version="1.1.5">
+           <artifact name="junit-1.1.5.aar">
+               <sha256 value="4307c0e60f5d701db9c59bcd9115af705113c36a9132fa3dbad58db1294e9bfd" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+           <artifact name="junit-1.1.5.pom">
+               <sha256 value="4cff0df04cae25831e821ef2f9129245783460e98d0fd67d8f6824065a134c4e" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.core" name="core-ktx" version="1.8.0">
+           <artifact name="core-ktx-1.8.0.module">
+               <sha256 value="a91bc3e02f209f643dd8275345a9e3003ce20d64fc0760eccf479c1709842f72" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.annotation" name="annotation-experimental" version="1.3.0">
+           <artifact name="annotation-experimental-1.3.0.aar">
+               <sha256 value="abfd29c8556e5bd0325a9f769ab9e9d154ff4a5515c476cdd5a2a8285b1b19dc" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+           <artifact name="annotation-experimental-1.3.0.module">
+               <sha256 value="5eebeaff01d042e06dcf292abf8964ad391e4b0159f0090f16253d6045d38da0" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.annotation" name="annotation-experimental" version="1.1.0-rc01">
+           <artifact name="annotation-experimental-1.1.0-rc01.module">
+               <sha256 value="d45ac493e84d968aabb2bea2b7744031a98cf5074447c0f3b862d600fc44b55c" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
       <component group="androidx.annotation" name="annotation" version="1.5.0">
          <artifact name="annotation-1.5.0.jar">
             <sha256 value="261fb7c0210858500bab66d34354972a75166ab4182add283780b05513d6ec4a" origin="Generated by Gradle" reason="Artifact is not signed"/>
@@ -321,6 +370,14 @@
             <sha256 value="fbc64f5c44a7added8b6eab517cf7d70555e25153bf5d44a6ed9b0e5312f7de9" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
+       <component group="androidx.exifinterface" name="exifinterface" version="1.3.2">
+           <artifact name="exifinterface-1.3.2.aar">
+               <sha256 value="8770c180103e0b8c04a07eb4c59153af639b09eca25deae9bdcdaf869d1e5b6b" origin="Generated by Gradle"/>
+           </artifact>
+           <artifact name="exifinterface-1.3.2.module">
+               <sha256 value="10ba5b5cbea7f5c8758be4fdaec60a3545e891a1130d830a442b88cf5336a885" origin="Generated by Gradle"/>
+           </artifact>
+       </component>
       <component group="androidx.annotation" name="annotation-experimental" version="1.0.0">
          <artifact name="annotation-experimental-1.0.0.pom">
             <sha256 value="6b73ff6608f4b1d6cbab620b65708a382d0b39901cf4e6b0d16f84a1b04d7732" origin="Generated by Gradle" reason="Artifact is not signed"/>
@@ -342,6 +399,37 @@
             <sha256 value="9b6974a7dfe26d3c209dd63e16f8ee2461b57a091789160ca1eb492bb1bf3f84" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
+       <component group="androidx.activity" name="activity-compose" version="1.7.0">
+           <artifact name="activity-compose-1.7.0.aar">
+               <sha256 value="caa72885d1ce7979c1d6c59a8b255c6097b770780d4d4da95d56979a348646cd" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+           <artifact name="activity-compose-1.7.0.module">
+               <sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
+       <component group="androidx.compose.runtime" name="runtime" version="1.0.1">
+           <artifact name="runtime-1.0.1.module">
+               <sha256 value="2543a8c7edc16bde91f140286b4fd3773d7204a283a4ec99f6e5e286aa92c0c3" origin="Generated by Gradle"/>
+           </artifact>
+       </component>
+       <component group="androidx.compose.runtime" name="runtime-saveable" version="1.0.1">
+           <artifact name="runtime-saveable-1.0.1.module">
+               <sha256 value="c0d6f142542d8d74f65481ef6526d2be265f01f812a112948fcde87a458f4fb6" origin="Generated by Gradle"/>
+           </artifact>
+       </component>
+       <component group="androidx.compose.ui" name="ui" version="1.0.1">
+           <artifact name="ui-1.0.1.aar">
+               <sha256 value="1943daa4a3412861b9a2bdc1a7c8c2ff05d9b8191c1d3e56ebb223d2eb4a8526" origin="Generated by Gradle"/>
+           </artifact>
+           <artifact name="ui-1.0.1.module">
+               <sha256 value="57031a6ac9b60e5b56792ebf5cde6e16812ff566ed9190cbd188b00b46c13779" origin="Generated by Gradle"/>
+           </artifact>
+       </component>
+       <component group="androidx.compose" name="compose-bom" version="2024.06.00">
+           <artifact name="compose-bom-2024.06.00.pom">
+               <sha256 value="1b391a969ff81c0bb43b3711e92d977e8bfa72457a11d8a37910a7051bdc3045" origin="Generated by Gradle" reason="Artifact is not signed"/>
+           </artifact>
+       </component>
       <component group="androidx.appcompat" name="appcompat" version="1.1.0">
          <artifact name="appcompat-1.1.0.pom">
             <sha256 value="340d617121f8ef8e02a6680c8f357aa3e542276d0c8a1cdcb6fd98984b2cb7b9" origin="Generated by Gradle" reason="Artifact is not signed"/>