Add overview for shared items of a conversation

Via the conversation info or the menu entry in the conversation menu a
overview of shared items can be opened.

Signed-off-by: Tim Krüger <t@timkrueger.me>
This commit is contained in:
Tim Krüger 2022-04-05 17:05:27 +02:00
parent 73b772dfa1
commit a1b7e1260c
No known key found for this signature in database
GPG Key ID: FECE3A7222C52A4E
19 changed files with 529 additions and 10 deletions

View File

@ -332,6 +332,10 @@ dependencies {
gplayImplementation 'com.google.android.gms:play-services-base:18.0.1' gplayImplementation 'com.google.android.gms:play-services-base:18.0.1'
gplayImplementation "com.google.firebase:firebase-messaging:23.0.0" gplayImplementation "com.google.firebase:firebase-messaging:23.0.0"
// TODO: Define variable for version
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
// implementation 'androidx.activity:activity-ktx:1.4.0'
} }
task installGitHooks(type: Copy, group: "development") { task installGitHooks(type: Copy, group: "development") {

View File

@ -96,6 +96,11 @@
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="10" /> android:value="10" />
<activity
android:name=".activities.SharedItemsActivity"
android:exported="false"
android:theme="@style/AppTheme"/>
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
android:label="@string/nc_app_name" android:label="@string/nc_app_name"

View File

@ -0,0 +1,44 @@
package com.nextcloud.talk.activities
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.nextcloud.talk.adapters.SharedItemsAdapter
import com.nextcloud.talk.databinding.ActivitySharedItemsBinding
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.viewmodels.SharedItemsViewModel
class SharedItemsActivity : AppCompatActivity() {
companion object {
private val TAG = SharedItemsActivity::class.simpleName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!
val userEntity = intent.getParcelableExtra<UserEntity>(BundleKeys.KEY_USER_ENTITY)!!
binding = ActivitySharedItemsBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(
this,
SharedItemsViewModel.Factory(userEntity, roomToken)
).get(SharedItemsViewModel::class.java)
viewModel.media.observe(this) {
Log.d(TAG, "Items received: $it")
val adapter = SharedItemsAdapter()
adapter.items = it.items
adapter.authHeader = it.authHeader
binding.imageRecycler.adapter = adapter
}
}
private lateinit var binding: ActivitySharedItemsBinding
private lateinit var viewModel: SharedItemsViewModel
}

View File

@ -0,0 +1,51 @@
package com.nextcloud.talk.adapters
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.interfaces.DraweeController
import com.facebook.imagepipeline.common.RotationOptions
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.nextcloud.talk.databinding.AttachmentItemBinding
import com.nextcloud.talk.repositories.SharedItem
class SharedItemsAdapter : RecyclerView.Adapter<SharedItemsAdapter.ViewHolder>() {
class ViewHolder(val binding: AttachmentItemBinding, itemView: View) : RecyclerView.ViewHolder(itemView)
var authHeader: Map<String, String> = emptyMap()
var items: List<SharedItem> = emptyList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = AttachmentItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding, binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = items[position]
if (currentItem.previewAvailable) {
val imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(currentItem.previewLink))
.setProgressiveRenderingEnabled(true)
.setRotationOptions(RotationOptions.autoRotate())
.disableDiskCache()
.setHeaders(authHeader)
.build()
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.binding.image.controller)
.setAutoPlayAnimations(true)
.setImageRequest(imageRequest)
.build()
holder.binding.image.controller = draweeController
}
}
override fun getItemCount(): Int {
return items.size
}
}

View File

@ -27,6 +27,7 @@ package com.nextcloud.talk.api;
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall; import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
import com.nextcloud.talk.models.json.chat.ChatOverall; import com.nextcloud.talk.models.json.chat.ChatOverall;
import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage; import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage;
import com.nextcloud.talk.models.json.chat.ChatShareOverall;
import com.nextcloud.talk.models.json.conversations.RoomOverall; import com.nextcloud.talk.models.json.conversations.RoomOverall;
import com.nextcloud.talk.models.json.conversations.RoomsOverall; import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.generic.GenericOverall; import com.nextcloud.talk.models.json.generic.GenericOverall;
@ -338,6 +339,12 @@ public interface NcApi {
@Field("actorDisplayName") String actorDisplayName, @Field("actorDisplayName") String actorDisplayName,
@Field("replyTo") Integer replyTo); @Field("replyTo") Integer replyTo);
@GET
Observable<Response<ChatShareOverall>> getSharedItems(@Header("Authorization") String authorization, @Url String url,
@Query("objectType") String objectType,
@Nullable @Query("lastKnownMessageId") Integer lastKnownMessageId,
@Nullable @Query("limit") Integer limit);
@GET @GET
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization, Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
@Url String url, @Query("search") String query, @Url String url, @Query("search") String query,

View File

@ -46,6 +46,7 @@ import android.os.Build
import android.os.Build.VERSION_CODES.O import android.os.Build.VERSION_CODES.O
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Parcelable
import android.os.SystemClock import android.os.SystemClock
import android.os.VibrationEffect import android.os.VibrationEffect
import android.os.Vibrator import android.os.Vibrator
@ -99,6 +100,7 @@ import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.activities.SharedItemsActivity
import com.nextcloud.talk.activities.TakePhotoActivity import com.nextcloud.talk.activities.TakePhotoActivity
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder import com.nextcloud.talk.adapters.messages.IncomingPreviewMessageViewHolder
@ -188,9 +190,7 @@ import java.io.File
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Date import java.util.Date
import java.util.HashMap
import java.util.Objects import java.util.Objects
import java.util.concurrent.ExecutionException import java.util.concurrent.ExecutionException
import javax.inject.Inject import javax.inject.Inject
@ -253,6 +253,7 @@ class ChatController(args: Bundle) :
var conversationInfoMenuItem: MenuItem? = null var conversationInfoMenuItem: MenuItem? = null
var conversationVoiceCallMenuItem: MenuItem? = null var conversationVoiceCallMenuItem: MenuItem? = null
var conversationVideoMenuItem: MenuItem? = null var conversationVideoMenuItem: MenuItem? = null
var conversationSharedItemsItem: MenuItem? = null
var magicWebSocketInstance: MagicWebSocketInstance? = null var magicWebSocketInstance: MagicWebSocketInstance? = null
@ -1464,7 +1465,7 @@ class ChatController(args: Bundle) :
val bundle = Bundle() val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType)) bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap<BrowserController.BrowserType>(browserType))
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap<UserEntity>(conversationUser)) bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap<UserEntity>(conversationUser))
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) bundle.putString(KEY_ROOM_TOKEN, roomToken)
router.pushController( router.pushController(
RouterTransaction.with(BrowserForSharingController(bundle)) RouterTransaction.with(BrowserForSharingController(bundle))
.pushChangeHandler(VerticalChangeHandler()) .pushChangeHandler(VerticalChangeHandler())
@ -1476,7 +1477,7 @@ class ChatController(args: Bundle) :
Log.d(TAG, "showShareLocationScreen") Log.d(TAG, "showShareLocationScreen")
val bundle = Bundle() val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) bundle.putString(KEY_ROOM_TOKEN, roomToken)
router.pushController( router.pushController(
RouterTransaction.with(LocationPickerController(bundle)) RouterTransaction.with(LocationPickerController(bundle))
.pushChangeHandler(HorizontalChangeHandler()) .pushChangeHandler(HorizontalChangeHandler())
@ -1487,7 +1488,7 @@ class ChatController(args: Bundle) :
private fun showConversationInfoScreen() { private fun showConversationInfoScreen() {
val bundle = Bundle() val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser) bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) bundle.putString(KEY_ROOM_TOKEN, roomToken)
bundle.putBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, inOneToOneCall()) bundle.putBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, inOneToOneCall())
router.pushController( router.pushController(
RouterTransaction.with(ConversationInfoController(bundle)) RouterTransaction.with(ConversationInfoController(bundle))
@ -2299,6 +2300,7 @@ class ChatController(args: Bundle) :
conversationInfoMenuItem = menu.findItem(R.id.conversation_info) conversationInfoMenuItem = menu.findItem(R.id.conversation_info)
conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call) conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)
conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call) conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call)
conversationSharedItemsItem = menu.findItem(R.id.shared_items)
loadAvatarForStatusBar() loadAvatarForStatusBar()
} }
@ -2337,10 +2339,21 @@ class ChatController(args: Bundle) :
showConversationInfoScreen() showConversationInfoScreen()
return true return true
} }
R.id.shared_items -> {
showSharedItems()
return true
}
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
} }
private fun showSharedItems() {
val intent = Intent(activity, SharedItemsActivity::class.java)
intent.putExtra(KEY_ROOM_TOKEN, roomToken)
intent.putExtra(KEY_USER_ENTITY, conversationUser as Parcelable)
activity!!.startActivity(intent)
}
private fun handleSystemMessages(chatMessageList: List<ChatMessage>): List<ChatMessage> { private fun handleSystemMessages(chatMessageList: List<ChatMessage>): List<ChatMessage> {
val chatMessageMap = chatMessageList.map { it.id to it }.toMap().toMutableMap() val chatMessageMap = chatMessageList.map { it.id to it }.toMap().toMutableMap()
val chatMessageIterator = chatMessageMap.iterator() val chatMessageIterator = chatMessageMap.iterator()

View File

@ -27,9 +27,11 @@
package com.nextcloud.talk.controllers package com.nextcloud.talk.controllers
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.LayerDrawable
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
@ -49,6 +51,7 @@ import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.SharedItemsActivity
import com.nextcloud.talk.adapters.items.ParticipantItem import com.nextcloud.talk.adapters.items.ParticipantItem
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
@ -88,11 +91,8 @@ import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import java.util.ArrayList
import java.util.Calendar import java.util.Calendar
import java.util.Collections import java.util.Collections
import java.util.Comparator
import java.util.HashMap
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@ -175,10 +175,18 @@ class ConversationInfoController(args: Bundle) :
binding.leaveConversationAction.setOnClickListener { leaveConversation() } binding.leaveConversationAction.setOnClickListener { leaveConversation() }
binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog(null) } binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog(null) }
binding.addParticipantsAction.setOnClickListener { addParticipants() } binding.addParticipantsAction.setOnClickListener { addParticipants() }
binding.showSharedItemsAction.setOnClickListener { showSharedItems() }
fetchRoomInfo() fetchRoomInfo()
} }
private fun showSharedItems() {
val intent = Intent(activity, SharedItemsActivity::class.java)
intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, conversationToken)
intent.putExtra(BundleKeys.KEY_USER_ENTITY, conversationUser as Parcelable)
activity!!.startActivity(intent)
}
override fun onViewBound(view: View) { override fun onViewBound(view: View) {
super.onViewBound(view) super.onViewBound(view)

View File

@ -0,0 +1,77 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.chat;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.nextcloud.talk.models.json.generic.GenericOCS;
import org.parceler.Parcel;
import java.util.HashMap;
import java.util.Objects;
@Parcel
@JsonObject
public class ChatShareOCS extends GenericOCS {
@JsonField(name = "data")
public HashMap<String, ChatMessage> data;
public HashMap<String, ChatMessage> getData() {
return this.data;
}
public void setData(HashMap<String, ChatMessage> data) {
this.data = data;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ChatShareOCS)) {
return false;
}
final ChatShareOCS other = (ChatShareOCS) o;
if (!other.canEqual(this)) {
return false;
}
final Object this$data = this.getData();
final Object other$data = other.getData();
return Objects.equals(this$data, other$data);
}
protected boolean canEqual(final Object other) {
return other instanceof ChatShareOCS;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $data = this.getData();
result = result * PRIME + ($data == null ? 43 : $data.hashCode());
return result;
}
public String toString() {
return "ChatShareOCS(data=" + this.getData() + ")";
}
}

View File

@ -0,0 +1,76 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.chat;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import org.parceler.Parcel;
import java.util.Objects;
@Parcel
@JsonObject
public class ChatShareOverall {
@JsonField(name = "ocs")
public ChatShareOCS ocs;
public ChatShareOCS getOcs() {
return this.ocs;
}
public void setOcs(ChatShareOCS ocs) {
this.ocs = ocs;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ChatShareOverall)) {
return false;
}
final ChatShareOverall other = (ChatShareOverall) o;
if (!other.canEqual(this)) {
return false;
}
final Object this$ocs = this.getOcs();
final Object other$ocs = other.getOcs();
return Objects.equals(this$ocs, other$ocs);
}
protected boolean canEqual(final Object other) {
return other instanceof ChatShareOverall;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $ocs = this.getOcs();
result = result * PRIME + ($ocs == null ? 43 : $ocs.hashCode());
return result;
}
public String toString() {
return "ChatShareOverall(ocs=" + this.getOcs() + ")";
}
}

View File

@ -0,0 +1,10 @@
package com.nextcloud.talk.repositories
data class SharedItem(
val id: String,
val name: String,
val mimeType: String,
val link: String,
val previewAvailable: Boolean,
val previewLink: String
)

View File

@ -0,0 +1,53 @@
package com.nextcloud.talk.repositories
import autodagger.AutoInjector
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.json.chat.ChatShareOverall
import com.nextcloud.talk.utils.ApiUtils
import io.reactivex.Observable
import retrofit2.Response
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class SharedItemsRepository {
companion object {
private val TAG = SharedItemsRepository::class.simpleName
}
var parameters: Parameters? = null
@Inject
lateinit var ncApi: NcApi
init {
sharedApplication!!.componentApplication.inject(this)
}
fun media(): Observable<Response<ChatShareOverall>>? {
val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken)
return ncApi.getSharedItems(
credentials,
ApiUtils.getUrlForChatSharedItems(1, parameters!!.baseUrl, parameters!!.roomToken),
"media", null, null
)
}
fun authHeader(): Map<String, String> {
return mapOf(Pair("Authorization", ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken)))
}
fun previewLink(fileId: String?): String {
return ApiUtils.getUrlForFilePreviewWithFileId(parameters!!.baseUrl, fileId, 100)
}
data class Parameters(
val userName: String,
val userToken: String,
val baseUrl: String,
val roomToken: String
)
}

View File

@ -0,0 +1,7 @@
package com.nextcloud.talk.repositories
class SharedMediaItems(
val items: List<SharedItem>,
val lastSeenId: String,
val authHeader: Map<String, String>
)

View File

@ -261,6 +261,10 @@ public class ApiUtils {
return getUrlForChat(version, baseUrl, token) + "/" + messageId; return getUrlForChat(version, baseUrl, token) + "/" + messageId;
} }
public static String getUrlForChatSharedItems(int version, String baseUrl, String token) {
return getUrlForChat(version, baseUrl, token) + "/share";
}
public static String getUrlForSignaling(int version, String baseUrl) { public static String getUrlForSignaling(int version, String baseUrl) {
return getUrlForApi(version, baseUrl) + "/signaling"; return getUrlForApi(version, baseUrl) + "/signaling";
} }

View File

@ -0,0 +1,95 @@
package com.nextcloud.talk.viewmodels
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.chat.ChatShareOverall
import com.nextcloud.talk.repositories.SharedItem
import com.nextcloud.talk.repositories.SharedItemsRepository
import com.nextcloud.talk.repositories.SharedMediaItems
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import retrofit2.Response
class SharedItemsViewModel(private val repository: SharedItemsRepository) : ViewModel() {
private val _media: MutableLiveData<SharedMediaItems> by lazy {
MutableLiveData<SharedMediaItems>().also {
loadMediaItems()
}
}
val media: LiveData<SharedMediaItems>
get() = _media
private fun loadMediaItems() {
repository.media()?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<Response<ChatShareOverall>> {
var chatLastGiven: String = ""
val items = mutableListOf<SharedItem>()
override fun onSubscribe(d: Disposable) = Unit
override fun onNext(response: Response<ChatShareOverall>) {
chatLastGiven = response.headers()["x-chat-last-given"]!!
val mediaItems = response.body()!!.ocs!!.data
mediaItems?.forEach {
val fileParameters = it.value.messageParameters["file"]!!
val previewAvailable = "yes".equals(fileParameters["preview-available"]!!, ignoreCase = true)
items.add(
SharedItem(
fileParameters["id"]!!, fileParameters["name"]!!,
fileParameters["mimetype"]!!, fileParameters["link"]!!,
previewAvailable,
repository.previewLink(fileParameters["id"])
)
)
}
}
override fun onError(e: Throwable) {
Log.d(TAG, "An error occurred: $e")
}
override fun onComplete() {
this@SharedItemsViewModel._media.value =
SharedMediaItems(items.asReversed(), chatLastGiven, repository.authHeader())
}
})
}
class Factory(val userEntity: UserEntity, val roomToken: String) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(SharedItemsViewModel::class.java)) {
val repository = SharedItemsRepository()
repository.parameters = SharedItemsRepository.Parameters(
userEntity.userId,
userEntity.token,
userEntity.baseUrl,
roomToken
)
return SharedItemsViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
companion object {
private val TAG = SharedItemsViewModel::class.simpleName
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.SharedItemsActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/image_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="4"
tools:listitem="@layout/attachment_item" />
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<com.facebook.drawee.view.SimpleDraweeView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="100dp"
android:padding="4dp"
android:src="@drawable/account_circle_96dp"
app:layout_constraintTop_toTopOf="parent"
fresco:actualImageScaleType="centerCrop"
fresco:failureImage="@drawable/account_circle_96dp"
fresco:placeholderImage="@drawable/account_circle_96dp"
fresco:roundedCornerRadius="4dp" />

View File

@ -129,7 +129,7 @@
android:id="@+id/participants_list_category" android:id="@+id/participants_list_category"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/settings" android:layout_below="@+id/category_shared_items"
android:visibility="gone" android:visibility="gone"
apc:cardBackgroundColor="@color/bg_default" apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp" apc:cardElevation="0dp"
@ -213,6 +213,29 @@
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </LinearLayout>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/category_shared_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/settings"
android:animateLayoutChanges="true"
apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp"
apc:mpc_title="Shared Items">
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/show_shared_items_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_icon="@drawable/ic_timer_black_24dp"
apc:mp_icon_tint="@color/grey_600"
apc:mp_summary="See all shared photos, voice messages, files, etc."
apc:mp_title="Shared Items" />
</com.yarolegovich.mp.MaterialPreferenceCategory>
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>
</RelativeLayout> </RelativeLayout>

View File

@ -37,8 +37,13 @@
<item <item
android:id="@+id/conversation_info" android:id="@+id/conversation_info"
android:icon="@drawable/ic_info_white_24dp"
android:orderInCategory="1" android:orderInCategory="1"
android:title="@string/nc_conversation_menu_conversation_info" android:title="@string/nc_conversation_menu_conversation_info"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/shared_items"
android:orderInCategory="1"
android:title="Shared Items"
app:showAsAction="never" />
</menu> </menu>

View File

@ -512,6 +512,7 @@
<string name="audio_output_phone">Phone</string> <string name="audio_output_phone">Phone</string>
<string name="audio_output_dialog_headline">Audio output</string> <string name="audio_output_dialog_headline">Audio output</string>
<string name="audio_output_wired_headset">Wired headset</string> <string name="audio_output_wired_headset">Wired headset</string>
<string name="title_attachments">Attachements</string>
<string name="reactions_tab_all">All</string> <string name="reactions_tab_all">All</string>