mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 09:25:49 +03:00
Merge remote-tracking branch 'origin/develop' into feature/eric/msc3773
This commit is contained in:
commit
51251c2b2b
25 changed files with 509 additions and 85 deletions
2
.github/workflows/danger.yml
vendored
2
.github/workflows/danger.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
- run: |
|
||||
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||
- name: Danger
|
||||
uses: danger/danger-js@11.1.3
|
||||
uses: danger/danger-js@11.1.4
|
||||
with:
|
||||
args: "--dangerfile tools/danger/dangerfile.js"
|
||||
env:
|
||||
|
|
2
.github/workflows/post-pr.yml
vendored
2
.github/workflows/post-pr.yml
vendored
|
@ -52,7 +52,7 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Start synapse server
|
||||
uses: michaelkaye/setup-matrix-synapse@v1.0.3
|
||||
uses: michaelkaye/setup-matrix-synapse@v1.0.4
|
||||
with:
|
||||
uploadLogs: true
|
||||
httpPort: 8080
|
||||
|
|
2
.github/workflows/quality.yml
vendored
2
.github/workflows/quality.yml
vendored
|
@ -66,7 +66,7 @@ jobs:
|
|||
yarn add danger-plugin-lint-report --dev
|
||||
- name: Danger lint
|
||||
if: always()
|
||||
uses: danger/danger-js@11.1.3
|
||||
uses: danger/danger-js@11.1.4
|
||||
with:
|
||||
args: "--dangerfile tools/danger/dangerfile-lint.js"
|
||||
env:
|
||||
|
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
@ -50,7 +50,7 @@ jobs:
|
|||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: michaelkaye/setup-matrix-synapse@v1.0.3
|
||||
- uses: michaelkaye/setup-matrix-synapse@v1.0.4
|
||||
with:
|
||||
uploadLogs: true
|
||||
httpPort: 8080
|
||||
|
|
2
.github/workflows/triage-incoming.yml
vendored
2
.github/workflows/triage-incoming.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
|||
# Skip in forks
|
||||
if: github.repository == 'vector-im/element-android'
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||
with:
|
||||
project: Issue triage
|
||||
column: Incoming
|
||||
|
|
4
.github/workflows/triage-priority-bugs.yml
vendored
4
.github/workflows/triage-priority-bugs.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
|||
contains(github.event.issue.labels.*.name, 'A11y') &&
|
||||
contains(github.event.issue.labels.*.name, 'O-Frequent'))
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||
with:
|
||||
project: Android App Team
|
||||
column: Important Issues & Topics (P1)
|
||||
|
@ -50,7 +50,7 @@ jobs:
|
|||
contains(github.event.issue.labels.*.name, 'A11y') &&
|
||||
contains(github.event.issue.labels.*.name, 'O-Frequent')))
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||
with:
|
||||
project: Crypto Team
|
||||
column: Ready
|
||||
|
|
2
.github/workflows/triage-unlabelled.yml
vendored
2
.github/workflows/triage-unlabelled.yml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
|||
echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Move issue
|
||||
uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||
if: ${{ env.ALREADY_IN_BOARD == 'true' }}
|
||||
with:
|
||||
project: Issue triage
|
||||
|
|
|
@ -33,7 +33,7 @@ buildscript {
|
|||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20"
|
||||
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
||||
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
|
||||
classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.1.0'
|
||||
classpath libs.squareup.paparazziPlugin
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ plugins {
|
|||
// Detekt
|
||||
id "io.gitlab.arturbosch.detekt" version "1.21.0"
|
||||
// Ksp
|
||||
id "com.google.devtools.ksp" version "1.7.20-1.0.6"
|
||||
id "com.google.devtools.ksp" version "1.7.20-1.0.7"
|
||||
|
||||
// Dependency Analysis
|
||||
id 'com.autonomousapps.dependency-analysis' version "1.13.1"
|
||||
|
@ -322,7 +322,7 @@ ext.initScreenshotTests = { project ->
|
|||
if (hasScreenshots) {
|
||||
project.apply plugin: 'app.cash.paparazzi'
|
||||
}
|
||||
project.dependencies { testCompileOnly "app.cash.paparazzi:paparazzi:1.0.0" }
|
||||
project.dependencies { testCompileOnly libs.squareup.paparazzi }
|
||||
project.android.testOptions.unitTests.all {
|
||||
def screenshotTestCapture = "**/*ScreenshotTest*"
|
||||
if (hasScreenshots) {
|
||||
|
|
1
changelog.d/7429.feature
Normal file
1
changelog.d/7429.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Add new UI for selecting an attachment
|
|
@ -1,5 +1,4 @@
|
|||
ext.versions = [
|
||||
|
||||
'minSdk' : 21,
|
||||
'compileSdk' : 33,
|
||||
'targetSdk' : 33,
|
||||
|
@ -12,7 +11,7 @@ def gradle = "7.3.1"
|
|||
def kotlin = "1.7.20"
|
||||
def kotlinCoroutines = "1.6.4"
|
||||
def dagger = "2.44"
|
||||
def appDistribution = "16.0.0-beta04"
|
||||
def appDistribution = "16.0.0-beta05"
|
||||
def retrofit = "2.9.0"
|
||||
def markwon = "4.6.2"
|
||||
def moshi = "1.14.0"
|
||||
|
@ -27,22 +26,20 @@ def jjwt = "0.11.5"
|
|||
// Temporary version to unblock #6929. Once 0.16.0 is released we should use it, and revert
|
||||
// the whole commit which set version 0.16.0-SNAPSHOT
|
||||
def vanniktechEmoji = "0.16.0-SNAPSHOT"
|
||||
|
||||
def sentry = "6.4.3"
|
||||
|
||||
def fragment = "1.5.3"
|
||||
|
||||
def sentry = "6.6.0"
|
||||
def fragment = "1.5.4"
|
||||
// Testing
|
||||
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
|
||||
def espresso = "3.4.0"
|
||||
def androidxTest = "1.4.0"
|
||||
def androidxOrchestrator = "1.4.1"
|
||||
def paparazzi = "1.1.0"
|
||||
|
||||
ext.libs = [
|
||||
gradle : [
|
||||
'gradlePlugin' : "com.android.tools.build:gradle:$gradle",
|
||||
'kotlinPlugin' : "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin",
|
||||
'hiltPlugin' : "com.google.dagger:hilt-android-gradle-plugin:$dagger"
|
||||
|
||||
],
|
||||
jetbrains : [
|
||||
'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines",
|
||||
|
@ -55,7 +52,7 @@ ext.libs = [
|
|||
'biometric' : "androidx.biometric:biometric:1.1.0",
|
||||
'core' : "androidx.core:core-ktx:1.9.0",
|
||||
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
|
||||
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.4",
|
||||
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.5",
|
||||
'fragmentKtx' : "androidx.fragment:fragment-ktx:$fragment",
|
||||
'fragmentTesting' : "androidx.fragment:fragment-testing:$fragment",
|
||||
'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.4",
|
||||
|
@ -82,7 +79,7 @@ ext.libs = [
|
|||
'transition' : "androidx.transition:transition:1.2.0",
|
||||
],
|
||||
google : [
|
||||
'material' : "com.google.android.material:material:1.6.1",
|
||||
'material' : "com.google.android.material:material:1.7.0",
|
||||
'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
|
||||
'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution",
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
|
@ -108,6 +105,8 @@ ext.libs = [
|
|||
'moshiKt' : "com.squareup.moshi:moshi-kotlin:$moshi",
|
||||
'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
|
||||
'moshiAdapters' : "com.squareup.moshi:moshi-adapters:$moshi",
|
||||
'paparazzi' : "app.cash.paparazzi:paparazzi:$paparazzi",
|
||||
'paparazziPlugin' : "app.cash.paparazzi:paparazzi-gradle-plugin:$paparazzi",
|
||||
'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit",
|
||||
'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit"
|
||||
],
|
||||
|
@ -167,7 +166,7 @@ ext.libs = [
|
|||
'sentryAndroid' : "io.sentry:sentry-android:$sentry"
|
||||
],
|
||||
tests : [
|
||||
'kluent' : "org.amshove.kluent:kluent-android:1.68",
|
||||
'kluent' : "org.amshove.kluent:kluent-android:1.72",
|
||||
'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1",
|
||||
'junit' : "junit:junit:4.13.2",
|
||||
]
|
||||
|
|
|
@ -3205,6 +3205,15 @@
|
|||
<string name="tooltip_attachment_location">Share location</string>
|
||||
<string name="tooltip_attachment_voice_broadcast">Start a voice broadcast</string>
|
||||
|
||||
<string name="attachment_type_selector_gallery">Photo library</string>
|
||||
<string name="attachment_type_selector_sticker">Stickers</string>
|
||||
<string name="attachment_type_selector_file">Attachments</string>
|
||||
<string name="attachment_type_selector_voice_broadcast">Voice broadcast</string>
|
||||
<string name="attachment_type_selector_poll">Polls</string>
|
||||
<string name="attachment_type_selector_location">Location</string>
|
||||
<string name="attachment_type_selector_camera">Camera</string>
|
||||
<string name="attachment_type_selector_contact">Contact</string>
|
||||
|
||||
<string name="message_reaction_show_less">Show less</string>
|
||||
<plurals name="message_reaction_show_more">
|
||||
<item quantity="one">"%1$d more"</item>
|
||||
|
|
|
@ -372,7 +372,7 @@ dependencies {
|
|||
debugImplementation 'com.facebook.soloader:soloader:0.10.4'
|
||||
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
|
||||
|
||||
gplayImplementation "com.google.android.gms:play-services-location:20.0.0"
|
||||
gplayImplementation "com.google.android.gms:play-services-location:21.0.0"
|
||||
// UnifiedPush gplay flavor only
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:23.1.0') {
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
|
|
|
@ -239,7 +239,7 @@ dependencies {
|
|||
implementation libs.sentry.sentryAndroid
|
||||
|
||||
// UnifiedPush
|
||||
implementation 'com.github.UnifiedPush:android-connector:2.1.0'
|
||||
implementation 'com.github.UnifiedPush:android-connector:2.1.1'
|
||||
|
||||
implementation "androidx.emoji2:emoji2:1.2.0"
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import dagger.hilt.InstallIn
|
|||
import dagger.multibindings.IntoMap
|
||||
import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorViewModel
|
||||
import im.vector.app.features.auth.ReAuthViewModel
|
||||
import im.vector.app.features.call.VectorCallViewModel
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
|
@ -677,4 +678,9 @@ interface MavericksViewModelModule {
|
|||
@IntoMap
|
||||
@MavericksViewModelKey(VectorSettingsLabsViewModel::class)
|
||||
fun vectorSettingsLabsViewModelFactory(factory: VectorSettingsLabsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@MavericksViewModelKey(AttachmentTypeSelectorViewModel::class)
|
||||
fun attachmentTypeSelectorViewModelFactory(factory: AttachmentTypeSelectorViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
val views: ViewBottomSheetActionButtonBinding
|
||||
|
||||
override fun setOnClickListener(l: OnClickListener?) {
|
||||
views.bottomSheetActionClickableZone.setOnClickListener(l)
|
||||
}
|
||||
|
||||
var title: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_VOICE_BROADCAST
|
||||
|
||||
/**
|
||||
* The all possible types to pick with their required permissions.
|
||||
*/
|
||||
enum class AttachmentType(val permissions: List<String>) {
|
||||
CAMERA(PERMISSIONS_FOR_TAKING_PHOTO),
|
||||
GALLERY(PERMISSIONS_EMPTY),
|
||||
FILE(PERMISSIONS_EMPTY),
|
||||
STICKER(PERMISSIONS_EMPTY),
|
||||
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT),
|
||||
POLL(PERMISSIONS_EMPTY),
|
||||
LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING),
|
||||
VOICE_BROADCAST(PERMISSIONS_FOR_VOICE_BROADCAST),
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.databinding.BottomSheetAttachmentTypeSelectorBinding
|
||||
import im.vector.app.features.home.room.detail.TimelineViewModel
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AttachmentTypeSelectorBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetAttachmentTypeSelectorBinding>() {
|
||||
|
||||
private val viewModel: AttachmentTypeSelectorViewModel by fragmentViewModel()
|
||||
private val timelineViewModel: TimelineViewModel by parentFragmentViewModel()
|
||||
private val sharedActionViewModel: AttachmentTypeSelectorSharedActionViewModel by viewModels(
|
||||
ownerProducer = { requireParentFragment() }
|
||||
)
|
||||
|
||||
override val showExpanded = true
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetAttachmentTypeSelectorBinding {
|
||||
return BottomSheetAttachmentTypeSelectorBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel, timelineViewModel) { viewState, timelineState ->
|
||||
super.invalidate()
|
||||
views.location.isVisible = viewState.isLocationVisible
|
||||
views.voiceBroadcast.isVisible = viewState.isVoiceBroadcastVisible
|
||||
views.poll.isVisible = !timelineState.isThreadTimeline()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
views.gallery.debouncedClicks { onAttachmentSelected(AttachmentType.GALLERY) }
|
||||
views.stickers.debouncedClicks { onAttachmentSelected(AttachmentType.STICKER) }
|
||||
views.file.debouncedClicks { onAttachmentSelected(AttachmentType.FILE) }
|
||||
views.voiceBroadcast.debouncedClicks { onAttachmentSelected(AttachmentType.VOICE_BROADCAST) }
|
||||
views.poll.debouncedClicks { onAttachmentSelected(AttachmentType.POLL) }
|
||||
views.location.debouncedClicks { onAttachmentSelected(AttachmentType.LOCATION) }
|
||||
views.camera.debouncedClicks { onAttachmentSelected(AttachmentType.CAMERA) }
|
||||
views.contact.debouncedClicks { onAttachmentSelected(AttachmentType.CONTACT) }
|
||||
}
|
||||
|
||||
private fun onAttachmentSelected(attachmentType: AttachmentType) {
|
||||
val action = AttachmentTypeSelectorSharedAction.SelectAttachmentTypeAction(attachmentType)
|
||||
sharedActionViewModel.post(action)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun show(fragmentManager: FragmentManager) {
|
||||
val bottomSheet = AttachmentTypeSelectorBottomSheet()
|
||||
bottomSheet.show(fragmentManager, "AttachmentTypeSelectorBottomSheet")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import im.vector.app.core.platform.VectorSharedAction
|
||||
import im.vector.app.core.platform.VectorSharedActionViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class AttachmentTypeSelectorSharedActionViewModel @Inject constructor() :
|
||||
VectorSharedActionViewModel<AttachmentTypeSelectorSharedAction>()
|
||||
|
||||
sealed interface AttachmentTypeSelectorSharedAction : VectorSharedAction {
|
||||
data class SelectAttachmentTypeAction(
|
||||
val attachmentType: AttachmentType
|
||||
) : AttachmentTypeSelectorSharedAction
|
||||
}
|
|
@ -30,17 +30,11 @@ import android.view.animation.TranslateAnimation
|
|||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_VOICE_BROADCAST
|
||||
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
||||
import kotlin.math.max
|
||||
|
@ -59,7 +53,7 @@ class AttachmentTypeSelectorView(
|
|||
) : PopupWindow(context) {
|
||||
|
||||
interface Callback {
|
||||
fun onTypeSelected(type: Type)
|
||||
fun onTypeSelected(type: AttachmentType)
|
||||
}
|
||||
|
||||
private val views: ViewAttachmentTypeSelectorBinding
|
||||
|
@ -69,14 +63,14 @@ class AttachmentTypeSelectorView(
|
|||
init {
|
||||
contentView = inflater.inflate(R.layout.view_attachment_type_selector, null, false)
|
||||
views = ViewAttachmentTypeSelectorBinding.bind(contentView)
|
||||
views.attachmentGalleryButton.configure(Type.GALLERY)
|
||||
views.attachmentCameraButton.configure(Type.CAMERA)
|
||||
views.attachmentFileButton.configure(Type.FILE)
|
||||
views.attachmentStickersButton.configure(Type.STICKER)
|
||||
views.attachmentContactButton.configure(Type.CONTACT)
|
||||
views.attachmentPollButton.configure(Type.POLL)
|
||||
views.attachmentLocationButton.configure(Type.LOCATION)
|
||||
views.attachmentVoiceBroadcast.configure(Type.VOICE_BROADCAST)
|
||||
views.attachmentGalleryButton.configure(AttachmentType.GALLERY)
|
||||
views.attachmentCameraButton.configure(AttachmentType.CAMERA)
|
||||
views.attachmentFileButton.configure(AttachmentType.FILE)
|
||||
views.attachmentStickersButton.configure(AttachmentType.STICKER)
|
||||
views.attachmentContactButton.configure(AttachmentType.CONTACT)
|
||||
views.attachmentPollButton.configure(AttachmentType.POLL)
|
||||
views.attachmentLocationButton.configure(AttachmentType.LOCATION)
|
||||
views.attachmentVoiceBroadcast.configure(AttachmentType.VOICE_BROADCAST)
|
||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||
height = LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
animationStyle = 0
|
||||
|
@ -127,16 +121,16 @@ class AttachmentTypeSelectorView(
|
|||
}
|
||||
}
|
||||
|
||||
fun setAttachmentVisibility(type: Type, isVisible: Boolean) {
|
||||
fun setAttachmentVisibility(type: AttachmentType, isVisible: Boolean) {
|
||||
when (type) {
|
||||
Type.CAMERA -> views.attachmentCameraButton
|
||||
Type.GALLERY -> views.attachmentGalleryButton
|
||||
Type.FILE -> views.attachmentFileButton
|
||||
Type.STICKER -> views.attachmentStickersButton
|
||||
Type.CONTACT -> views.attachmentContactButton
|
||||
Type.POLL -> views.attachmentPollButton
|
||||
Type.LOCATION -> views.attachmentLocationButton
|
||||
Type.VOICE_BROADCAST -> views.attachmentVoiceBroadcast
|
||||
AttachmentType.CAMERA -> views.attachmentCameraButton
|
||||
AttachmentType.GALLERY -> views.attachmentGalleryButton
|
||||
AttachmentType.FILE -> views.attachmentFileButton
|
||||
AttachmentType.STICKER -> views.attachmentStickersButton
|
||||
AttachmentType.CONTACT -> views.attachmentContactButton
|
||||
AttachmentType.POLL -> views.attachmentPollButton
|
||||
AttachmentType.LOCATION -> views.attachmentLocationButton
|
||||
AttachmentType.VOICE_BROADCAST -> views.attachmentVoiceBroadcast
|
||||
}.let {
|
||||
it.isVisible = isVisible
|
||||
}
|
||||
|
@ -200,13 +194,13 @@ class AttachmentTypeSelectorView(
|
|||
return Pair(x, y)
|
||||
}
|
||||
|
||||
private fun ImageButton.configure(type: Type): ImageButton {
|
||||
private fun ImageButton.configure(type: AttachmentType): ImageButton {
|
||||
this.setOnClickListener(TypeClickListener(type))
|
||||
TooltipCompat.setTooltipText(this, context.getString(type.tooltipRes))
|
||||
TooltipCompat.setTooltipText(this, context.getString(attachmentTooltipLabels.getValue(type)))
|
||||
return this
|
||||
}
|
||||
|
||||
private inner class TypeClickListener(private val type: Type) : View.OnClickListener {
|
||||
private inner class TypeClickListener(private val type: AttachmentType) : View.OnClickListener {
|
||||
|
||||
override fun onClick(v: View) {
|
||||
dismiss()
|
||||
|
@ -217,14 +211,18 @@ class AttachmentTypeSelectorView(
|
|||
/**
|
||||
* The all possible types to pick with their required permissions and tooltip resource.
|
||||
*/
|
||||
enum class Type(val permissions: List<String>, @StringRes val tooltipRes: Int) {
|
||||
CAMERA(PERMISSIONS_FOR_TAKING_PHOTO, R.string.tooltip_attachment_photo),
|
||||
GALLERY(PERMISSIONS_EMPTY, R.string.tooltip_attachment_gallery),
|
||||
FILE(PERMISSIONS_EMPTY, R.string.tooltip_attachment_file),
|
||||
STICKER(PERMISSIONS_EMPTY, R.string.tooltip_attachment_sticker),
|
||||
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT, R.string.tooltip_attachment_contact),
|
||||
POLL(PERMISSIONS_EMPTY, R.string.tooltip_attachment_poll),
|
||||
LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, R.string.tooltip_attachment_location),
|
||||
VOICE_BROADCAST(PERMISSIONS_FOR_VOICE_BROADCAST, R.string.tooltip_attachment_voice_broadcast),
|
||||
private companion object {
|
||||
private val attachmentTooltipLabels: Map<AttachmentType, Int> = AttachmentType.values().associateWith {
|
||||
when (it) {
|
||||
AttachmentType.CAMERA -> R.string.tooltip_attachment_photo
|
||||
AttachmentType.GALLERY -> R.string.tooltip_attachment_gallery
|
||||
AttachmentType.FILE -> R.string.tooltip_attachment_file
|
||||
AttachmentType.STICKER -> R.string.tooltip_attachment_sticker
|
||||
AttachmentType.CONTACT -> R.string.tooltip_attachment_contact
|
||||
AttachmentType.POLL -> R.string.tooltip_attachment_poll
|
||||
AttachmentType.LOCATION -> R.string.tooltip_attachment_location
|
||||
AttachmentType.VOICE_BROADCAST -> R.string.tooltip_attachment_voice_broadcast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.EmptyAction
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.VectorFeatures
|
||||
|
||||
class AttachmentTypeSelectorViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: AttachmentTypeSelectorViewState,
|
||||
private val vectorFeatures: VectorFeatures,
|
||||
) : VectorViewModel<AttachmentTypeSelectorViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<AttachmentTypeSelectorViewModel, AttachmentTypeSelectorViewState> {
|
||||
override fun create(initialState: AttachmentTypeSelectorViewState): AttachmentTypeSelectorViewModel
|
||||
}
|
||||
|
||||
companion object : MavericksViewModelFactory<AttachmentTypeSelectorViewModel, AttachmentTypeSelectorViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
override fun handle(action: EmptyAction) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
init {
|
||||
setState {
|
||||
copy(
|
||||
isLocationVisible = vectorFeatures.isLocationSharingEnabled(),
|
||||
isVoiceBroadcastVisible = vectorFeatures.isVoiceBroadcastEnabled(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class AttachmentTypeSelectorViewState(
|
||||
val isLocationVisible: Boolean = false,
|
||||
val isVoiceBroadcastVisible: Boolean = false,
|
||||
) : MavericksState
|
|
@ -54,7 +54,7 @@ class AttachmentsHelper(
|
|||
private var captureUri: Uri? = null
|
||||
|
||||
// The pending type is set if we have to handle permission request. It must be restored if the activity gets killed.
|
||||
var pendingType: AttachmentTypeSelectorView.Type? = null
|
||||
var pendingType: AttachmentType? = null
|
||||
|
||||
// Restorable
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import androidx.core.text.buildSpannedString
|
|||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -63,6 +64,10 @@ import im.vector.app.core.utils.onPermissionDeniedDialog
|
|||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.databinding.FragmentComposerBinding
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.attachments.AttachmentType
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorBottomSheet
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorSharedAction
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorSharedActionViewModel
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView
|
||||
import im.vector.app.features.attachments.AttachmentsHelper
|
||||
import im.vector.app.features.attachments.ContactAttachment
|
||||
|
@ -92,6 +97,7 @@ import im.vector.app.features.settings.VectorPreferences
|
|||
import im.vector.app.features.share.SharedData
|
||||
import im.vector.app.features.voice.VoiceFailure
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -161,6 +167,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||
private val timelineViewModel: TimelineViewModel by parentFragmentViewModel()
|
||||
private val messageComposerViewModel: MessageComposerViewModel by parentFragmentViewModel()
|
||||
private lateinit var sharedActionViewModel: MessageSharedActionViewModel
|
||||
private val attachmentViewModel: AttachmentTypeSelectorSharedActionViewModel by viewModels()
|
||||
|
||||
private val composer: MessageComposerView get() {
|
||||
return if (vectorPreferences.isRichTextEditorEnabled()) {
|
||||
|
@ -219,6 +226,11 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||
}
|
||||
}
|
||||
|
||||
attachmentViewModel.stream()
|
||||
.filterIsInstance<AttachmentTypeSelectorSharedAction.SelectAttachmentTypeAction>()
|
||||
.onEach { onTypeSelected(it.attachmentType) }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
handleShareData()
|
||||
}
|
||||
|
@ -299,21 +311,25 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||
}
|
||||
composer.callback = object : PlainTextComposerLayout.Callback {
|
||||
override fun onAddAttachment() {
|
||||
if (!::attachmentTypeSelector.isInitialized) {
|
||||
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@MessageComposerFragment)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentTypeSelectorView.Type.LOCATION,
|
||||
vectorFeatures.isLocationSharingEnabled(),
|
||||
)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentTypeSelectorView.Type.POLL, !isThreadTimeLine()
|
||||
)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentTypeSelectorView.Type.VOICE_BROADCAST,
|
||||
vectorPreferences.isVoiceBroadcastEnabled(), // TODO check user permission
|
||||
)
|
||||
if (vectorPreferences.isRichTextEditorEnabled()) {
|
||||
AttachmentTypeSelectorBottomSheet.show(childFragmentManager)
|
||||
} else {
|
||||
if (!::attachmentTypeSelector.isInitialized) {
|
||||
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@MessageComposerFragment)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentType.LOCATION,
|
||||
vectorFeatures.isLocationSharingEnabled(),
|
||||
)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentType.POLL, !isThreadTimeLine()
|
||||
)
|
||||
attachmentTypeSelector.setAttachmentVisibility(
|
||||
AttachmentType.VOICE_BROADCAST,
|
||||
vectorPreferences.isVoiceBroadcastEnabled(), // TODO check user permission
|
||||
)
|
||||
}
|
||||
attachmentTypeSelector.show(composer.attachmentButton)
|
||||
}
|
||||
attachmentTypeSelector.show(composer.attachmentButton)
|
||||
}
|
||||
|
||||
override fun onExpandOrCompactChange() {
|
||||
|
@ -662,20 +678,20 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||
}
|
||||
}
|
||||
|
||||
private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
|
||||
private fun launchAttachmentProcess(type: AttachmentType) {
|
||||
when (type) {
|
||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(
|
||||
AttachmentType.CAMERA -> attachmentsHelper.openCamera(
|
||||
activity = requireActivity(),
|
||||
vectorPreferences = vectorPreferences,
|
||||
cameraActivityResultLauncher = attachmentCameraActivityResultLauncher,
|
||||
cameraVideoActivityResultLauncher = attachmentCameraVideoActivityResultLauncher
|
||||
)
|
||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
|
||||
AttachmentTypeSelectorView.Type.STICKER -> timelineViewModel.handle(RoomDetailAction.SelectStickerAttachment)
|
||||
AttachmentTypeSelectorView.Type.POLL -> navigator.openCreatePoll(requireContext(), roomId, null, PollMode.CREATE)
|
||||
AttachmentTypeSelectorView.Type.LOCATION -> {
|
||||
AttachmentType.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||
AttachmentType.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher)
|
||||
AttachmentType.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
|
||||
AttachmentType.STICKER -> timelineViewModel.handle(RoomDetailAction.SelectStickerAttachment)
|
||||
AttachmentType.POLL -> navigator.openCreatePoll(requireContext(), roomId, null, PollMode.CREATE)
|
||||
AttachmentType.LOCATION -> {
|
||||
navigator
|
||||
.openLocationSharing(
|
||||
context = requireContext(),
|
||||
|
@ -685,11 +701,11 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
|||
locationOwnerId = session.myUserId
|
||||
)
|
||||
}
|
||||
AttachmentTypeSelectorView.Type.VOICE_BROADCAST -> timelineViewModel.handle(VoiceBroadcastAction.Recording.Start)
|
||||
AttachmentType.VOICE_BROADCAST -> timelineViewModel.handle(VoiceBroadcastAction.Recording.Start)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) {
|
||||
override fun onTypeSelected(type: AttachmentType) {
|
||||
if (checkPermissions(type.permissions, requireActivity(), typeSelectedActivityResultLauncher)) {
|
||||
launchAttachmentProcess(type)
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/gallery"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_gallery"
|
||||
app:leftIcon="@drawable/ic_attachment_gallery"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/stickers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_sticker"
|
||||
app:leftIcon="@drawable/ic_attachment_sticker"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/file"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_file"
|
||||
app:leftIcon="@drawable/ic_attachment_file"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/voiceBroadcast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_voice_broadcast"
|
||||
app:leftIcon="@drawable/ic_attachment_voice_broadcast"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/poll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_poll"
|
||||
app:leftIcon="@drawable/ic_attachment_poll"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_location"
|
||||
app:leftIcon="@drawable/ic_attachment_location"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/camera"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_camera"
|
||||
app:leftIcon="@drawable/ic_attachment_camera"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
<im.vector.app.core.ui.views.BottomSheetActionButton
|
||||
android:id="@+id/contact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:actionTitle="@string/attachment_type_selector_contact"
|
||||
app:leftIcon="@drawable/ic_attachment_contact_white_24dp"
|
||||
app:tint="?colorPrimary"
|
||||
app:titleTextColor="?vctr_content_primary" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.attachments
|
||||
|
||||
import com.airbnb.mvrx.test.MavericksTestRule
|
||||
import im.vector.app.test.fakes.FakeVectorFeatures
|
||||
import im.vector.app.test.test
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
internal class AttachmentTypeSelectorViewModelTest {
|
||||
|
||||
@get:Rule
|
||||
val mavericksTestRule = MavericksTestRule()
|
||||
|
||||
private val fakeVectorFeatures = FakeVectorFeatures()
|
||||
private val initialState = AttachmentTypeSelectorViewState()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
// Disable all features by default
|
||||
fakeVectorFeatures.givenLocationSharing(isEnabled = false)
|
||||
fakeVectorFeatures.givenVoiceBroadcast(isEnabled = false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given features are not enabled, then options are not visible`() {
|
||||
createViewModel()
|
||||
.test()
|
||||
.assertStates(
|
||||
listOf(
|
||||
initialState,
|
||||
)
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given location sharing is enabled, then location sharing option is visible`() {
|
||||
fakeVectorFeatures.givenLocationSharing(isEnabled = true)
|
||||
|
||||
createViewModel()
|
||||
.test()
|
||||
.assertStates(
|
||||
listOf(
|
||||
initialState.copy(
|
||||
isLocationVisible = true
|
||||
),
|
||||
)
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given voice broadcast is enabled, then voice broadcast option is visible`() {
|
||||
fakeVectorFeatures.givenVoiceBroadcast(isEnabled = true)
|
||||
|
||||
createViewModel()
|
||||
.test()
|
||||
.assertStates(
|
||||
listOf(
|
||||
initialState.copy(
|
||||
isVoiceBroadcastVisible = true
|
||||
),
|
||||
)
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
|
||||
private fun createViewModel(): AttachmentTypeSelectorViewModel {
|
||||
return AttachmentTypeSelectorViewModel(
|
||||
initialState,
|
||||
vectorFeatures = fakeVectorFeatures,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -42,4 +42,12 @@ class FakeVectorFeatures : VectorFeatures by spyk<DefaultVectorFeatures>() {
|
|||
fun givenCombinedLoginDisabled() {
|
||||
every { isOnboardingCombinedLoginEnabled() } returns false
|
||||
}
|
||||
|
||||
fun givenLocationSharing(isEnabled: Boolean) {
|
||||
every { isLocationSharingEnabled() } returns isEnabled
|
||||
}
|
||||
|
||||
fun givenVoiceBroadcast(isEnabled: Boolean) {
|
||||
every { isVoiceBroadcastEnabled() } returns isEnabled
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue