add sensitive media overlay
This commit is contained in:
parent
0e8ad1e9ed
commit
4984a68750
|
@ -46,7 +46,7 @@ class TimelineFragment : DaggerFragment(R.layout.fragment_timeline), TimeLineAct
|
||||||
binding.timelineRecyclerView.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL))
|
binding.timelineRecyclerView.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL))
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.flow.collectLatest { pagingData ->
|
viewModel.statusFlow.collectLatest { pagingData ->
|
||||||
adapter.submitData(pagingData)
|
adapter.submitData(pagingData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,4 +77,8 @@ class TimelineFragment : DaggerFragment(R.layout.fragment_timeline), TimeLineAct
|
||||||
override fun onReply(status: StatusEntity) {
|
override fun onReply(status: StatusEntity) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onMediaVisibilityChanged(status: StatusEntity) {
|
||||||
|
viewModel.onMediaVisibilityChanged(status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ interface TimeLineActionListener {
|
||||||
fun onFavorite(post: StatusEntity)
|
fun onFavorite(post: StatusEntity)
|
||||||
fun onBoost(post: StatusEntity)
|
fun onBoost(post: StatusEntity)
|
||||||
fun onReply(status: StatusEntity)
|
fun onReply(status: StatusEntity)
|
||||||
|
fun onMediaVisibilityChanged(status: StatusEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
object TimelineDiffUtil : DiffUtil.ItemCallback<StatusEntity>() {
|
object TimelineDiffUtil : DiffUtil.ItemCallback<StatusEntity>() {
|
||||||
|
@ -82,6 +83,12 @@ class TimelineListAdapter(
|
||||||
holder.binding.postDescription.text = status.content.parseAsHtml().trim()
|
holder.binding.postDescription.text = status.content.parseAsHtml().trim()
|
||||||
|
|
||||||
holder.binding.postDate.text = dateTimeFormatter.format(status.createdAt)
|
holder.binding.postDate.text = dateTimeFormatter.format(status.createdAt)
|
||||||
|
|
||||||
|
holder.binding.postSensitiveMediaOverlay.visible = status.attachments.isNotEmpty() && !status.mediaVisible
|
||||||
|
|
||||||
|
holder.binding.postSensitiveMediaOverlay.setOnClickListener {
|
||||||
|
listener.onMediaVisibilityChanged(status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package at.connyduck.pixelcat.components.timeline
|
package at.connyduck.pixelcat.components.timeline
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.ExperimentalPagingApi
|
import androidx.paging.ExperimentalPagingApi
|
||||||
|
@ -11,37 +10,39 @@ import at.connyduck.pixelcat.db.AccountManager
|
||||||
import at.connyduck.pixelcat.db.AppDatabase
|
import at.connyduck.pixelcat.db.AppDatabase
|
||||||
import at.connyduck.pixelcat.db.entitity.StatusEntity
|
import at.connyduck.pixelcat.db.entitity.StatusEntity
|
||||||
import at.connyduck.pixelcat.network.FediverseApi
|
import at.connyduck.pixelcat.network.FediverseApi
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
import kotlinx.coroutines.flow.asFlow
|
||||||
|
import kotlinx.coroutines.flow.flatMapConcat
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TimelineViewModel @Inject constructor(
|
class TimelineViewModel @Inject constructor(
|
||||||
// private val repository: TimelineRepo,
|
|
||||||
private val accountManager: AccountManager,
|
private val accountManager: AccountManager,
|
||||||
private val db: AppDatabase,
|
private val db: AppDatabase,
|
||||||
fediverseApi: FediverseApi
|
fediverseApi: FediverseApi
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val accountId = MutableLiveData<Long>()
|
@OptIn(FlowPreview::class)
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch {
|
|
||||||
val currentAccountId = accountManager.activeAccount()?.id!!
|
|
||||||
accountId.postValue(currentAccountId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExperimentalPagingApi
|
@ExperimentalPagingApi
|
||||||
val flow = Pager(
|
val statusFlow = accountManager::activeAccount.asFlow()
|
||||||
// Configure how data is loaded by passing additional properties to
|
.flatMapConcat { activeAccount ->
|
||||||
// PagingConfig, such as prefetchDistance.
|
Pager(
|
||||||
config = PagingConfig(pageSize = 10, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 10, enablePlaceholders = false),
|
||||||
remoteMediator = TimelineRemoteMediator(0, fediverseApi, db),
|
remoteMediator = TimelineRemoteMediator(activeAccount?.id!!, fediverseApi, db),
|
||||||
pagingSourceFactory = { db.statusDao().statuses(0) }
|
pagingSourceFactory = { db.statusDao().statuses(activeAccount.id) }
|
||||||
).flow.cachedIn(viewModelScope)
|
).flow
|
||||||
|
}
|
||||||
|
.cachedIn(viewModelScope)
|
||||||
|
|
||||||
fun onFavorite(status: StatusEntity) {
|
fun onFavorite(status: StatusEntity) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
// repository.onFavorite(status, accountManager.activeAccount()?.id!!)
|
// repository.onFavorite(status, accountManager.activeAccount()?.id!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onMediaVisibilityChanged(status: StatusEntity) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
db.statusDao().changeMediaVisibility(!status.mediaVisible, status.id, accountManager.activeAccount()?.id!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,4 +25,7 @@ interface TimelineDao {
|
||||||
|
|
||||||
@Query("DELETE FROM StatusEntity WHERE accountId = :accountId")
|
@Query("DELETE FROM StatusEntity WHERE accountId = :accountId")
|
||||||
suspend fun clearAll(accountId: Long)
|
suspend fun clearAll(accountId: Long)
|
||||||
|
|
||||||
|
@Query("UPDATE StatusEntity SET mediaVisible = :visible WHERE id = :statusId AND accountId = :accountId")
|
||||||
|
suspend fun changeMediaVisibility(visible: Boolean, statusId: String, accountId: Long)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ data class StatusEntity(
|
||||||
val mediaVisible: Boolean
|
val mediaVisible: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Status.toEntity(accountId: Long, mediaPosition: Int = 0, mediaVisible: Boolean = this.sensitive) = StatusEntity(
|
fun Status.toEntity(accountId: Long, mediaPosition: Int = 0, mediaVisible: Boolean = !this.sensitive) = StatusEntity(
|
||||||
accountId = accountId,
|
accountId = accountId,
|
||||||
id = id,
|
id = id,
|
||||||
url = actionableStatus.url,
|
url = actionableStatus.url,
|
||||||
|
|
|
@ -1,137 +1,147 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:sparkbutton="http://schemas.android.com/apk/res-auto"
|
xmlns:sparkbutton="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="8dp">
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/postAvatar"
|
android:id="@+id/postAvatar"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:background="#f00" />
|
tools:background="#f00" />
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiTextView
|
<androidx.emoji.widget.EmojiTextView
|
||||||
android:id="@+id/postDisplayName"
|
android:id="@+id/postDisplayName"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@id/postName"
|
app:layout_constraintBottom_toTopOf="@id/postName"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/postAvatar"
|
app:layout_constraintStart_toEndOf="@id/postAvatar"
|
||||||
app:layout_constraintTop_toTopOf="@id/postAvatar"
|
app:layout_constraintTop_toTopOf="@id/postAvatar"
|
||||||
tools:text="Conny Duck" />
|
tools:text="Conny Duck" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/postName"
|
android:id="@+id/postName"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/postAvatar"
|
app:layout_constraintBottom_toBottomOf="@id/postAvatar"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/postAvatar"
|
app:layout_constraintStart_toEndOf="@id/postAvatar"
|
||||||
app:layout_constraintTop_toBottomOf="@id/postDisplayName"
|
app:layout_constraintTop_toBottomOf="@id/postDisplayName"
|
||||||
tools:text="\@connyduck\@chaos.social" />
|
tools:text="\@connyduck\@chaos.social" />
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/postImages"
|
android:id="@+id/postImages"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:background="#000"
|
android:background="#000"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layout_constraintTop_toBottomOf="@id/postAvatar" />
|
||||||
app:layout_constraintTop_toBottomOf="@id/postAvatar" />
|
|
||||||
|
|
||||||
<at.connyduck.sparkbutton.SparkButton
|
|
||||||
android:id="@+id/postLikeButton"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/postImages"
|
|
||||||
sparkbutton:activeImage="@drawable/ic_heart_filled"
|
|
||||||
sparkbutton:iconSize="24dp"
|
|
||||||
sparkbutton:inactiveImage="@drawable/ic_heart"
|
|
||||||
sparkbutton:primaryColor="@color/heart_button_primary"
|
|
||||||
sparkbutton:secondaryColor="@color/heart_button_secondary" />
|
|
||||||
|
|
||||||
<at.connyduck.sparkbutton.SparkButton
|
|
||||||
android:id="@+id/postBoostButton"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/postLikeButton"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/postImages"
|
|
||||||
sparkbutton:activeImage="@drawable/ic_repeat"
|
|
||||||
sparkbutton:iconSize="24dp"
|
|
||||||
sparkbutton:inactiveImage="@drawable/ic_repeat"
|
|
||||||
sparkbutton:primaryColor="@color/boost_button_primary"
|
|
||||||
sparkbutton:secondaryColor="@color/boost_button_secondary" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/postReplyButton"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:src="@drawable/ic_message"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/postBoostButton"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/postImages" />
|
|
||||||
|
|
||||||
<me.relex.circleindicator.CircleIndicator3
|
|
||||||
android:id="@+id/postIndicator"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="104dp"
|
|
||||||
app:ci_drawable="@drawable/pager_indicator_dot"
|
|
||||||
app:ci_drawable_unselected="@drawable/pager_indicator_dot"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/postReplyButton"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/postReplyButton"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/postReplyButton" />
|
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiTextView
|
|
||||||
android:id="@+id/postDescription"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/postLikeButton"
|
|
||||||
tools:text="This is the caption" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/postDate"
|
android:id="@+id/postSensitiveMediaOverlay"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:layout_marginStart="16dp"
|
android:background="#ccc"
|
||||||
android:layout_marginTop="8dp"
|
android:gravity="center"
|
||||||
android:layout_marginEnd="16dp"
|
android:textStyle="bold"
|
||||||
android:textSize="12sp"
|
android:text="@string/sensitive_media"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/postImages"
|
||||||
app:layout_constraintTop_toBottomOf="@id/postDescription"
|
app:layout_constraintTop_toTopOf="@id/postImages" />
|
||||||
tools:text="4 hours ago" />
|
|
||||||
|
<at.connyduck.sparkbutton.SparkButton
|
||||||
|
android:id="@+id/postLikeButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/postImages"
|
||||||
|
sparkbutton:activeImage="@drawable/ic_heart_filled"
|
||||||
|
sparkbutton:iconSize="24dp"
|
||||||
|
sparkbutton:inactiveImage="@drawable/ic_heart"
|
||||||
|
sparkbutton:primaryColor="@color/heart_button_primary"
|
||||||
|
sparkbutton:secondaryColor="@color/heart_button_secondary" />
|
||||||
|
|
||||||
|
<at.connyduck.sparkbutton.SparkButton
|
||||||
|
android:id="@+id/postBoostButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/postLikeButton"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/postImages"
|
||||||
|
sparkbutton:activeImage="@drawable/ic_repeat"
|
||||||
|
sparkbutton:iconSize="24dp"
|
||||||
|
sparkbutton:inactiveImage="@drawable/ic_repeat"
|
||||||
|
sparkbutton:primaryColor="@color/boost_button_primary"
|
||||||
|
sparkbutton:secondaryColor="@color/boost_button_secondary" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/postReplyButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_message"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/postBoostButton"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/postImages" />
|
||||||
|
|
||||||
|
<me.relex.circleindicator.CircleIndicator3
|
||||||
|
android:id="@+id/postIndicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="104dp"
|
||||||
|
app:ci_drawable="@drawable/pager_indicator_dot"
|
||||||
|
app:ci_drawable_unselected="@drawable/pager_indicator_dot"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/postReplyButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/postReplyButton"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/postReplyButton" />
|
||||||
|
|
||||||
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
android:id="@+id/postDescription"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/postLikeButton"
|
||||||
|
tools:text="This is the caption" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/postDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/postDescription"
|
||||||
|
tools:text="4 hours ago" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -74,5 +74,6 @@
|
||||||
<string name="navigation_menu">Menu</string>
|
<string name="navigation_menu">Menu</string>
|
||||||
<string name="navigation_accounts">Accounts</string>
|
<string name="navigation_accounts">Accounts</string>
|
||||||
<string name="action_add_new_account">Add Account</string>
|
<string name="action_add_new_account">Add Account</string>
|
||||||
|
<string name="sensitive_media">Sensitive media</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue