Share to signal from CallSheet.
This commit is contained in:
parent
5fa9a27ee0
commit
99abfd0d98
6 changed files with 63 additions and 19 deletions
|
@ -54,7 +54,7 @@ object CallLinks {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isCallLink(url: String): Boolean {
|
fun isCallLink(url: String): Boolean {
|
||||||
if (FeatureFlags.adHocCalling()) {
|
if (!FeatureFlags.adHocCalling()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,12 +46,10 @@ import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||||
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
||||||
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
||||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
|
||||||
import org.thoughtcrime.securesms.database.CallLinkTable
|
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||||
import org.thoughtcrime.securesms.service.webrtc.links.CreateCallLinkResult
|
import org.thoughtcrime.securesms.service.webrtc.links.CreateCallLinkResult
|
||||||
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
|
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
|
||||||
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
import org.thoughtcrime.securesms.sharing.v2.ShareActivity
|
||||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
|
||||||
|
@ -212,15 +210,10 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
||||||
lifecycleDisposable += viewModel.commitCallLink().subscribeBy(onSuccess = {
|
lifecycleDisposable += viewModel.commitCallLink().subscribeBy(onSuccess = {
|
||||||
when (it) {
|
when (it) {
|
||||||
is EnsureCallLinkCreatedResult.Success -> {
|
is EnsureCallLinkCreatedResult.Success -> {
|
||||||
MultiselectForwardFragment.showFullScreen(
|
startActivity(
|
||||||
childFragmentManager,
|
ShareActivity.sendSimpleText(
|
||||||
MultiselectForwardFragmentArgs(
|
requireContext(),
|
||||||
canSendToNonPush = false,
|
getString(R.string.CreateCallLink__use_this_link_to_join_a_signal_call, CallLinks.url(viewModel.linkKeyBytes))
|
||||||
multiShareArgs = listOf(
|
|
||||||
MultiShareArgs.Builder()
|
|
||||||
.withDraftText(CallLinks.url(viewModel.linkKeyBytes))
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1095,6 +1095,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
if (callToActionStub.resolved()) callToActionStub.get().setVisibility(View.GONE);
|
if (callToActionStub.resolved()) callToActionStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
revealableStub.get().setMessage((MmsMessageRecord) messageRecord, hasWallpaper);
|
revealableStub.get().setMessage((MmsMessageRecord) messageRecord, hasWallpaper);
|
||||||
|
@ -1113,6 +1114,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
sharedContactStub.get().setContact(((MediaMmsMessageRecord) messageRecord).getSharedContacts().get(0), glideRequests, locale);
|
sharedContactStub.get().setContact(((MediaMmsMessageRecord) messageRecord).getSharedContacts().get(0), glideRequests, locale);
|
||||||
|
@ -1134,6 +1136,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
@ -1195,6 +1198,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
audioViewStub.get().setAudio(Objects.requireNonNull(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide()), new AudioViewCallbacks(), showControls, true);
|
audioViewStub.get().setAudio(Objects.requireNonNull(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide()), new AudioViewCallbacks(), showControls, true);
|
||||||
|
@ -1222,6 +1226,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
@ -1250,6 +1255,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
|
if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (hasSticker(messageRecord)) {
|
if (hasSticker(messageRecord)) {
|
||||||
|
@ -1281,6 +1287,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
List<Slide> thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides();
|
List<Slide> thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides();
|
||||||
|
@ -1335,6 +1342,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
|
if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord;
|
MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord;
|
||||||
|
@ -1351,6 +1359,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
|
|
||||||
MediaMmsMessageRecord mediaMmsMessageRecord = (MediaMmsMessageRecord) messageRecord;
|
MediaMmsMessageRecord mediaMmsMessageRecord = (MediaMmsMessageRecord) messageRecord;
|
||||||
|
|
||||||
|
@ -1367,6 +1376,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
|
||||||
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
if (revealableStub.resolved()) revealableStub.get().setVisibility(View.GONE);
|
||||||
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
|
||||||
|
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
|
||||||
paymentViewStub.setVisibility(View.GONE);
|
paymentViewStub.setVisibility(View.GONE);
|
||||||
|
|
||||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.thoughtcrime.securesms.sharing.v2
|
package org.thoughtcrime.securesms.sharing.v2
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -12,6 +13,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import org.signal.core.util.Result
|
import org.signal.core.util.Result
|
||||||
|
@ -38,12 +40,24 @@ import org.thoughtcrime.securesms.sharing.MultiShareSender.MultiShareSendResultC
|
||||||
import org.thoughtcrime.securesms.sharing.interstitial.ShareInterstitialActivity
|
import org.thoughtcrime.securesms.sharing.interstitial.ShareInterstitialActivity
|
||||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
|
||||||
|
import org.thoughtcrime.securesms.util.visible
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.Callback {
|
class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = Log.tag(ShareActivity::class.java)
|
private val TAG = Log.tag(ShareActivity::class.java)
|
||||||
|
|
||||||
|
private const val EXTRA_TITLE = "ShareActivity.extra.title"
|
||||||
|
private const val EXTRA_NAVIGATION = "ShareActivity.extra.navigation"
|
||||||
|
|
||||||
|
fun sendSimpleText(context: Context, text: String): Intent {
|
||||||
|
return Intent(context, ShareActivity::class.java)
|
||||||
|
.setAction(Intent.ACTION_SEND)
|
||||||
|
.putExtra(Intent.EXTRA_TEXT, text)
|
||||||
|
.putExtra(EXTRA_TITLE, R.string.MediaReviewFragment__send_to)
|
||||||
|
.putExtra(EXTRA_NAVIGATION, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val dynamicTheme = DynamicNoActionBarTheme()
|
private val dynamicTheme = DynamicNoActionBarTheme()
|
||||||
|
@ -89,6 +103,16 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val toolbar = findViewById<MaterialToolbar>(R.id.toolbar)
|
||||||
|
|
||||||
|
if (intent?.getBooleanExtra(EXTRA_NAVIGATION, false) == true) {
|
||||||
|
toolbar.setTitle(getTitleFromExtras())
|
||||||
|
toolbar.setNavigationIcon(R.drawable.symbol_arrow_left_24)
|
||||||
|
toolbar.setNavigationOnClickListener { finish() }
|
||||||
|
} else {
|
||||||
|
toolbar.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
lifecycleDisposable.bindTo(this)
|
lifecycleDisposable.bindTo(this)
|
||||||
lifecycleDisposable += viewModel.events.subscribe { shareEvent ->
|
lifecycleDisposable += viewModel.events.subscribe { shareEvent ->
|
||||||
when (shareEvent) {
|
when (shareEvent) {
|
||||||
|
@ -210,7 +234,7 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
|
||||||
MultiselectForwardFragmentArgs(
|
MultiselectForwardFragmentArgs(
|
||||||
canSendToNonPush = resolvedShareData.isMmsOrSmsSupported,
|
canSendToNonPush = resolvedShareData.isMmsOrSmsSupported,
|
||||||
multiShareArgs = listOf(resolvedShareData.toMultiShareArgs()),
|
multiShareArgs = listOf(resolvedShareData.toMultiShareArgs()),
|
||||||
title = R.string.MultiselectForwardFragment__share_with,
|
title = getTitleFromExtras(),
|
||||||
forceDisableAddMessage = true,
|
forceDisableAddMessage = true,
|
||||||
forceSelectionOnly = true
|
forceSelectionOnly = true
|
||||||
)
|
)
|
||||||
|
@ -311,6 +335,10 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
|
||||||
Toast.makeText(this, R.string.ShareActivity__could_not_get_share_data_from_intent, Toast.LENGTH_LONG).show()
|
Toast.makeText(this, R.string.ShareActivity__could_not_get_share_data_from_intent, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getTitleFromExtras(): Int {
|
||||||
|
return intent?.getIntExtra(EXTRA_TITLE, R.string.MultiselectForwardFragment__share_with) ?: R.string.MultiselectForwardFragment__share_with
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an error with the intent when trying to extract the unresolved share data.
|
* Represents an error with the intent when trying to extract the unresolved share data.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:viewBindingIgnore="true"
|
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||||
|
app:titleTextAppearance="@style/Signal.Text.TitleLarge"
|
||||||
|
tools:title="Share with" />
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
</FrameLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -6158,6 +6158,8 @@
|
||||||
<string name="CreateCallLink__create_a_call_link">Create a Call Link</string>
|
<string name="CreateCallLink__create_a_call_link">Create a Call Link</string>
|
||||||
<!-- Call link creation item description on calls tab -->
|
<!-- Call link creation item description on calls tab -->
|
||||||
<string name="CreateCallLink__share_a_link_for">Share a link for a Signal call</string>
|
<string name="CreateCallLink__share_a_link_for">Share a link for a Signal call</string>
|
||||||
|
<!-- Text inserted when sharing a call link within Signal. Placeholder is a call link url. -->
|
||||||
|
<string name="CreateCallLink__use_this_link_to_join_a_signal_call">Use this link to join a Signal call: %1$s</string>
|
||||||
|
|
||||||
<!-- CallLinkInfoSheet -->
|
<!-- CallLinkInfoSheet -->
|
||||||
<!-- Sheet title -->
|
<!-- Sheet title -->
|
||||||
|
|
Loading…
Add table
Reference in a new issue