Merge branch 'develop' into renovate/io.nlopez.compose.rules-detekt-0.x

This commit is contained in:
Benoit Marty 2024-01-10 09:39:28 +01:00 committed by GitHub
commit 628149ff62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 309 additions and 325 deletions

View file

@ -18,12 +18,6 @@
],
"groupName" : "kotlin"
},
{
"matchPackageNames" : [
"org.jetbrains.kotlinx.kover"
],
"enabled" : false
},
{
"matchPackagePatterns" : [
"^org.maplibre"

View file

@ -33,7 +33,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈 Generate kover report and verify coverage
run: ./gradlew koverMergedReport koverMergedVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
run: ./gradlew :app:koverHtmlReport :app:koverXmlReport :app:koverVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
- name: ✅ Upload kover report
if: always()
@ -41,7 +41,7 @@ jobs:
with:
name: kover-results
path: |
**/build/reports/kover/merged
**/build/reports/kover
- name: 🔊 Publish results to Sonar
env:

View file

@ -55,7 +55,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈Generate kover report and verify coverage
run: ./gradlew koverMergedReport koverMergedVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
run: ./gradlew :app:koverHtmlReport :app:koverXmlReport :app:koverVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
- name: 🚫 Upload kover failed coverage reports
if: failure()
@ -63,7 +63,7 @@ jobs:
with:
name: kover-error-report
path: |
**/kover/merged/verification/errors.txt
app/build/reports/kover/verify.err
- name: ✅ Upload kover report (disabled)
if: always()
@ -83,4 +83,4 @@ jobs:
if: always()
uses: codecov/codecov-action@v3
# with:
# files: build/reports/kover/merged/xml/report.xml
# files: build/reports/kover/xml/report.xml

View file

@ -20,6 +20,7 @@ import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
import extension.allFeaturesImpl
import extension.allLibrariesImpl
import extension.allServicesImpl
import org.jetbrains.kotlin.cli.common.toBooleanLenient
plugins {
id("io.element.android-compose-application")
@ -190,6 +191,220 @@ knit {
}
}
/**
* Kover configuration
*/
dependencies {
// Add all sub projects to kover except some of them
project.rootProject.subprojects
.filter {
it.project.projectDir.resolve("build.gradle.kts").exists()
}
.map { it.path }
.sorted()
.filter {
it !in listOf(
":app",
":samples",
":anvilannotations",
":anvilcodegen",
":samples:minimal",
":tests:testutils",
// Exclude `:libraries:matrix:impl` module, it contains only wrappers to access the Rust Matrix
// SDK api, so it is not really relevant to unit test it: there is no logic to test.
":libraries:matrix:impl",
// Exclude modules which are not Android libraries
// See https://github.com/Kotlin/kotlinx-kover/issues/312
":appconfig",
":libraries:core",
":libraries:coroutines",
":libraries:di",
":libraries:rustsdk",
":libraries:textcomposer:lib",
)
}
.forEach {
// println("Add $it to kover")
kover(project(it))
}
}
val ciBuildProperty = "ci-build"
val isCiBuild = if (project.hasProperty(ciBuildProperty)) {
val raw = project.property(ciBuildProperty) as? String
raw?.toBooleanLenient() == true || raw?.toIntOrNull() == 1
} else {
false
}
kover {
// When running on the CI, run only debug test variants
if (isCiBuild) {
excludeTests {
// Disable instrumentation for debug test tasks
tasks(
"testDebugUnitTest",
)
}
}
}
// https://kotlin.github.io/kotlinx-kover/
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
// Run `./gradlew :app:koverXmlReport` to get XML report
koverReport {
filters {
excludes {
classes(
// Exclude generated classes.
"*_ModuleKt",
"anvil.hint.binding.io.element.*",
"anvil.hint.merge.*",
"anvil.hint.multibinding.io.element.*",
"anvil.module.*",
"com.airbnb.android.showkase*",
"io.element.android.libraries.designsystem.showkase.*",
"io.element.android.x.di.DaggerAppComponent*",
"*_Factory",
"*_Factory_Impl",
"*_Factory$*",
"*_Module",
"*_Module$*",
"*Module_Provides*",
"Dagger*Component*",
"*ComposableSingletons$*",
"*_AssistedFactory_Impl*",
"*BuildConfig",
// Generated by Showkase
"*Ioelementandroid*PreviewKt$*",
"*Ioelementandroid*PreviewKt",
// Other
// We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
"*Node",
"*Node$*",
"*Presenter\$present\$*",
// Forked from compose
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
)
annotatedBy(
"io.element.android.libraries.designsystem.preview.PreviewsDayNight",
"io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight",
)
}
}
defaults {
// add reports of both 'debug' and 'release' Android build variants to default reports
mergeWith("debug")
mergeWith("release")
verify {
onCheck = true
// General rule: minimum code coverage.
rule("Global minimum code coverage.") {
isEnabled = true
entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.APPLICATION
bound {
minValue = 65
// Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
// For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
// minValue to 25 and maxValue to 35.
maxValue = 75
metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of Presenters is sufficient.
rule("Check code coverage of presenters") {
isEnabled = true
entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
filters {
includes {
classes(
"*Presenter",
)
}
excludes {
classes(
"*Fake*Presenter",
"io.element.android.appnav.loggedin.LoggedInPresenter$*",
// Some options can't be tested at the moment
"io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
"*Presenter\$present\$*",
)
}
}
bound {
minValue = 85
metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of States is sufficient.
rule("Check code coverage of states") {
isEnabled = true
entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
filters {
includes {
classes(
"^*State$",
)
}
excludes {
classes(
"io.element.android.appnav.root.RootNavState*",
"io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
"io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*",
"io.element.android.libraries.matrix.api.room.RoomMembershipState*",
"io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*",
"io.element.android.libraries.push.impl.notifications.NotificationState*",
"io.element.android.features.messages.impl.media.local.pdf.PdfViewerState",
"io.element.android.features.messages.impl.media.local.LocalMediaViewState",
"io.element.android.features.location.impl.map.MapState*",
"io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
"io.element.android.libraries.designsystem.swipe.SwipeableActionsState*",
"io.element.android.features.messages.impl.timeline.components.ExpandableState*",
"io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*",
"io.element.android.libraries.maplibre.compose.CameraPositionState*",
"io.element.android.libraries.maplibre.compose.SaveableCameraPositionState",
"io.element.android.libraries.maplibre.compose.SymbolState*",
"io.element.android.features.ftue.api.state.*",
"io.element.android.features.ftue.impl.welcome.state.*",
)
}
}
bound {
minValue = 90
metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of Views is sufficient (deactivated for now).
rule("Check code coverage of views") {
isEnabled = true
entity = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
filters {
includes {
classes(
"*ViewKt",
)
}
}
bound {
// TODO Update this value, for now there are too many missing tests.
minValue = 0
metric = kotlinx.kover.gradle.plugin.dsl.MetricType.INSTRUCTION
aggregation = kotlinx.kover.gradle.plugin.dsl.AggregationType.COVERED_PERCENTAGE
}
}
}
}
androidReports("release") {
}
}
dependencies {
allLibrariesImpl()
allServicesImpl()

View file

@ -1,7 +1,5 @@
import com.google.devtools.ksp.gradle.KspTask
import kotlinx.kover.api.KoverTaskExtension
import org.apache.tools.ant.taskdefs.optional.ReplaceRegExp
import org.jetbrains.kotlin.cli.common.toBooleanLenient
buildscript {
dependencies {
@ -41,7 +39,7 @@ plugins {
alias(libs.plugins.ktlint)
alias(libs.plugins.dependencygraph)
alias(libs.plugins.sonarqube)
alias(libs.plugins.kover)
alias(libs.plugins.kover) apply false
}
tasks.register<Delete>("clean").configure {
@ -164,177 +162,7 @@ allprojects {
}
allprojects {
apply(plugin = "kover")
}
// https://kotlin.github.io/kotlinx-kover/
// Run `./gradlew koverMergedHtmlReport` to get report at ./build/reports/kover
// Run `./gradlew koverMergedReport` to also get XML report
koverMerged {
enable()
filters {
classes {
excludes.addAll(
listOf(
// Exclude generated classes.
"*_ModuleKt",
"anvil.hint.binding.io.element.*",
"anvil.hint.merge.*",
"anvil.hint.multibinding.io.element.*",
"anvil.module.*",
"com.airbnb.android.showkase*",
"io.element.android.libraries.designsystem.showkase.*",
"io.element.android.x.di.DaggerAppComponent*",
"*_Factory",
"*_Factory_Impl",
"*_Factory$*",
"*_Module",
"*_Module$*",
"*Module_Provides*",
"Dagger*Component*",
"*ComposableSingletons$*",
"*_AssistedFactory_Impl*",
"*BuildConfig",
// Generated by Showkase
"*Ioelementandroid*PreviewKt$*",
"*Ioelementandroid*PreviewKt",
// Other
// We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
"*Node",
"*Node$*",
// Exclude `:libraries:matrix:impl` module, it contains only wrappers to access the Rust Matrix SDK api, so it is not really relevant to unit test it: there is no logic to test.
"io.element.android.libraries.matrix.impl.*",
"*Presenter\$present\$*",
// Forked from compose
"io.element.android.libraries.designsystem.theme.components.bottomsheet.*",
)
)
}
annotations {
excludes.addAll(
listOf(
"*Preview",
)
)
}
projects {
excludes.addAll(
listOf(
":anvilannotations",
":anvilcodegen",
":samples:minimal",
":tests:testutils",
)
)
}
}
// Run ./gradlew koverMergedVerify to check the rules.
verify {
// Does not seems to work, so also run the task manually on the workflow.
onCheck.set(true)
// General rule: minimum code coverage.
rule {
name = "Global minimum code coverage."
target = kotlinx.kover.api.VerificationTarget.ALL
bound {
minValue = 65
// Setting a max value, so that if coverage is bigger, it means that we have to change minValue.
// For instance if we have minValue = 20 and maxValue = 30, and current code coverage is now 31.32%, update
// minValue to 25 and maxValue to 35.
maxValue = 75
counter = kotlinx.kover.api.CounterType.INSTRUCTION
valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of Presenters is sufficient.
rule {
name = "Check code coverage of presenters"
target = kotlinx.kover.api.VerificationTarget.CLASS
overrideClassFilter {
includes += "*Presenter"
excludes += "*Fake*Presenter"
excludes += "io.element.android.appnav.loggedin.LoggedInPresenter$*"
// Some options can't be tested at the moment
excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*"
excludes += "*Presenter\$present\$*"
}
bound {
minValue = 85
counter = kotlinx.kover.api.CounterType.INSTRUCTION
valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of States is sufficient.
rule {
name = "Check code coverage of states"
target = kotlinx.kover.api.VerificationTarget.CLASS
overrideClassFilter {
includes += "^*State$"
excludes += "io.element.android.appnav.root.RootNavState*"
excludes += "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*"
excludes += "io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*"
excludes += "io.element.android.libraries.matrix.api.room.RoomMembershipState*"
excludes += "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*"
excludes += "io.element.android.libraries.push.impl.notifications.NotificationState*"
excludes += "io.element.android.features.messages.impl.media.local.pdf.PdfViewerState"
excludes += "io.element.android.features.messages.impl.media.local.LocalMediaViewState"
excludes += "io.element.android.features.location.impl.map.MapState*"
excludes += "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*"
excludes += "io.element.android.libraries.designsystem.swipe.SwipeableActionsState*"
excludes += "io.element.android.features.messages.impl.timeline.components.ExpandableState*"
excludes += "io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*"
excludes += "io.element.android.libraries.maplibre.compose.CameraPositionState*"
excludes += "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState"
excludes += "io.element.android.libraries.maplibre.compose.SymbolState*"
excludes += "io.element.android.features.ftue.api.state.*"
excludes += "io.element.android.features.ftue.impl.welcome.state.*"
}
bound {
minValue = 90
counter = kotlinx.kover.api.CounterType.INSTRUCTION
valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE
}
}
// Rule to ensure that coverage of Views is sufficient (deactivated for now).
rule {
name = "Check code coverage of views"
target = kotlinx.kover.api.VerificationTarget.CLASS
overrideClassFilter {
includes += "*ViewKt"
}
bound {
// TODO Update this value, for now there are too many missing tests.
minValue = 0
counter = kotlinx.kover.api.CounterType.INSTRUCTION
valueType = kotlinx.kover.api.VerificationValueType.COVERED_PERCENTAGE
}
}
}
}
// When running on the CI, run only debug test variants
val ciBuildProperty = "ci-build"
val isCiBuild = if (project.hasProperty(ciBuildProperty)) {
val raw = project.property(ciBuildProperty) as? String
raw?.toBooleanLenient() == true || raw?.toIntOrNull() == 1
} else {
false
}
if (isCiBuild) {
allprojects {
afterEvaluate {
tasks.withType<Test>().configureEach {
extensions.configure<KoverTaskExtension> {
val enabled = name.contains("debug", ignoreCase = true)
isDisabled.set(!enabled)
}
}
}
}
apply(plugin = "org.jetbrains.kotlinx.kover")
}
// Register quality check tasks.

1
changelog.d/1782.misc Normal file
View file

@ -0,0 +1 @@
Migrate to Kover 0.7.X

1
changelog.d/2156.bugfix Normal file
View file

@ -0,0 +1 @@
Improve rendering of voice messages in the timeline in large displays

View file

@ -344,26 +344,26 @@ implementation of our interfaces. Mocking can be used to mock Android framework
[kover](https://github.com/Kotlin/kotlinx-kover) is used to compute code coverage. Only have unit tests can produce code coverage result. Running Maestro does
not participate to the code coverage results.
Kover configuration is defined in the main [build.gradle.kts](../build.gradle.kts) file.
Kover configuration is defined in the app [build.gradle.kts](../app/build.gradle.kts) file.
To compute the code coverage, run:
```bash
./gradlew koverMergedReport
./gradlew :app:koverHtmlReport
```
and open the Html report: [../build/reports/kover/merged/html/index.html](../build/reports/kover/merged/html/index.html)
and open the Html report: [../app/build/reports/kover/html/index.html](../app/build/reports/kover/html/index.html)
To ensure that the code coverage threshold are OK, you can run
```bash
./gradlew koverMergedVerify
./gradlew :app:koverVerify
```
Note that the CI performs this check on every pull requests.
Also, if the rule `Global minimum code coverage.` is in error because code coverage is `> maxValue`, `minValue` and `maxValue` can be updated for this rule in
the file [build.gradle.kts](../build.gradle.kts) (you will see further instructions there).
the file [build.gradle.kts](../app/build.gradle.kts) (you will see further instructions there).
### Other points

View file

@ -91,7 +91,6 @@ dependencies {
testImplementation(projects.libraries.mediapickers.test)
testImplementation(projects.libraries.permissions.test)
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.textcomposer.test)
testImplementation(projects.libraries.voicerecorder.test)
testImplementation(projects.libraries.mediaplayer.test)
testImplementation(projects.libraries.mediaviewer.test)

View file

@ -110,9 +110,7 @@ fun TimelineItemVoiceView(
showCursor = state.showCursor,
playbackProgress = state.progress,
waveform = content.waveform,
modifier = Modifier
.height(34.dp)
.weight(1f),
modifier = Modifier.height(34.dp),
seekEnabled = !context.isScreenReaderEnabled(),
onSeek = { state.eventSink(VoiceMessageEvents.Seek(it)) },
)

View file

@ -215,7 +215,7 @@ dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12"
dependencycheck = "org.owasp.dependencycheck:9.0.8"
dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" }
paparazzi = "app.cash.paparazzi:1.3.1"
kover = "org.jetbrains.kotlinx.kover:0.6.1"
kover = "org.jetbrains.kotlinx.kover:0.7.5"
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" }
knit = { id = "org.jetbrains.kotlinx.knit", version = "0.5.0" }

View file

@ -1 +0,0 @@
/build

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2023 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.
*/
plugins {
id("java-library")
alias(libs.plugins.kotlin.jvm)
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
implementation(libs.coroutines.core)
}

View file

@ -23,23 +23,22 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList
import kotlin.math.max
fun DrawScope.drawWaveform(
waveformData: ImmutableList<Float>,
canvasSize: DpSize,
canvasSizePx: Size,
brush: Brush,
minimumGraphAmplitude: Float = 2F,
lineWidth: Dp = 2.dp,
linePadding: Dp = 2.dp,
) {
val centerY = canvasSize.height.toPx() / 2
val centerY = canvasSizePx.height / 2
val cornerRadius = lineWidth / 2
waveformData.forEachIndexed { index, amplitude ->
val drawingAmplitude = max(minimumGraphAmplitude, amplitude * (canvasSize.height.toPx() - 2))
val drawingAmplitude = max(minimumGraphAmplitude, amplitude * (canvasSizePx.height - 2))
drawRoundRect(
brush = brush,
topLeft = Offset(

View file

@ -40,12 +40,13 @@ import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.RequestDisallowInterceptTouchEvent
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.compound.theme.ElementTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@ -58,7 +59,7 @@ private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F
*
* @param playbackProgress The current playback progress, between 0 and 1.
* @param showCursor Whether to show the cursor or not.
* @param waveform The waveform to display. Use [FakeWaveformFactory] to generate a fake waveform.
* @param waveform The waveform to display. Use [createFakeWaveform] to generate a fake waveform.
* @param onSeek Callback when the user seeks the waveform. Called with a value between 0 and 1.
* @param modifier The modifier to be applied to the view.
* @param seekEnabled Whether the user can seek the waveform or not.
@ -103,6 +104,11 @@ fun WaveformPlaybackView(
}
}
val density = LocalDensity.current
val waveformWidthPx by remember {
derivedStateOf { with(density) { normalizedWaveformData.size * (lineWidth + linePadding).roundToPx().toFloat() } }
}
val requestDisallowInterceptTouchEvent = remember { RequestDisallowInterceptTouchEvent() }
Canvas(
modifier = Modifier
@ -110,19 +116,18 @@ fun WaveformPlaybackView(
.graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA)
.let {
if (!seekEnabled) return@let it
it.pointerInteropFilter(requestDisallowInterceptTouchEvent = requestDisallowInterceptTouchEvent) { e ->
return@pointerInteropFilter when (e.action) {
MotionEvent.ACTION_DOWN -> {
if (e.x in 0F..canvasSizePx.width) {
if (e.x in 0F..waveformWidthPx) {
requestDisallowInterceptTouchEvent.invoke(true)
seekProgress.value = e.x / canvasSizePx.width
seekProgress.value = e.x / waveformWidthPx
true
} else false
}
MotionEvent.ACTION_MOVE -> {
if (e.x in 0F..canvasSizePx.width) {
seekProgress.value = e.x / canvasSizePx.width
if (e.x in 0F..waveformWidthPx) {
seekProgress.value = e.x / waveformWidthPx
}
true
}
@ -140,11 +145,11 @@ fun WaveformPlaybackView(
) {
canvasSize = size.toDpSize()
canvasSizePx = size
val centerY = canvasSize.height.toPx() / 2
val cornerRadius = lineWidth / 2
// Calculate the size of the waveform by summing the width of all the lines and paddings
drawWaveform(
waveformData = normalizedWaveformData,
canvasSize = canvasSize,
canvasSizePx = canvasSizePx,
brush = brush,
lineWidth = lineWidth,
linePadding = linePadding
@ -152,8 +157,8 @@ fun WaveformPlaybackView(
drawRect(
brush = progressBrush,
size = Size(
width = progressAnimated.value * canvasSize.width.toPx(),
height = canvasSize.height.toPx()
width = progressAnimated.value * waveformWidthPx,
height = canvasSizePx.height
),
blendMode = BlendMode.SrcAtop
)
@ -161,12 +166,12 @@ fun WaveformPlaybackView(
drawRoundRect(
brush = cursorBrush,
topLeft = Offset(
x = progressAnimated.value * canvasSize.width.toPx(),
y = centerY - (canvasSize.height.toPx() - 2) / 2
x = progressAnimated.value * waveformWidthPx,
y = 1f
),
size = Size(
width = lineWidth.toPx(),
height = canvasSize.height.toPx() - 2
height = canvasSizePx.height - 2
),
cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx()),
style = Fill

View file

@ -31,6 +31,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.graphicsLayer
@ -66,7 +67,6 @@ fun LiveWaveformView(
}
}
Box(contentAlignment = Alignment.CenterEnd,
modifier = modifier
.fillMaxWidth()
@ -79,11 +79,12 @@ fun LiveWaveformView(
.graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA)
.then(modifier)
) {
canvasSize = DpSize(Dp(min(waveformWidth, parentWidth.toFloat())), size.height.toDp())
val width = min(waveformWidth, parentWidth.toFloat())
canvasSize = DpSize(width.dp, size.height.toDp())
val countThatFitsWidth = (parentWidth.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt()
drawWaveform(
waveformData = levels.takeLast(countThatFitsWidth).toPersistentList(),
canvasSize = canvasSize,
canvasSizePx = Size(canvasSize.width.toPx(), size.height),
brush = brush,
lineWidth = lineWidth,
linePadding = linePadding,

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2023 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.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.libraries.textcomposer.test"
}
dependencies {
api(projects.libraries.textcomposer.impl)
implementation(projects.tests.testutils)
}

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:298c750f283995af2552ac72f86fe4747287a781b8c25e890616efd08b4ae54e
size 45436
oid sha256:070f5cc86ef672c0999e0c926bcdee09a4d8b8c70d89152a61abfe34e2289a66
size 44929

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d6871183e7bba8fc9574dc838ef10626a7d573d21cea6d0a1a4219ac928c8697
size 44211
oid sha256:b8b86b0ff5d34a8f9223cd4a33a95494321540102ed0515d19437911abe387ac
size 43742

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bc14498cb4178dbf6a103159eabe6e0c7f4458f2e10350eacd58a9c0beefff10
size 10056
oid sha256:0df1912bae9bdfb9778bfe9c8cc10c2f12a09d6b26f0d379cbec3ce5fac0a0cf
size 10050

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9df0b76dd3d46022243b03d5c5f1accabf2345b9412d2cf1f9d3e6e7d5bb18f4
size 9565
oid sha256:6d2949f01b23ffca6eac0eb6a21768caf27a5fc8cbca501ac691160276d32636
size 9626

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:260e882a9a068b5a81a251cfd20c6c99473fc7d905551f1e8de12d0d6165538d
size 9919
oid sha256:0facb6fd321f293b6856724bbae2f4f686f7a87ce6229e17202b1d283b6c6f0e
size 9921

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9e0772d6c4f9b994d2b32de900b80faccb5598774db46fc161009a4774d6efd2
size 5531
oid sha256:2897384e35af54220b8f2555a376c20f289173448a5afb027fedd82a5b868966
size 5783

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:438d24d36310528695e0f79d9a515a599ae27fa028c2290477a0df622240ab87
size 6077
oid sha256:a765606c839ce01c256aaf334e2db3bb9bb05616b5f817ea5c91b40ba2443e63
size 6021

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:52ae85fdd9eeb0e3d81336c38147d8251079e2ae61364ca7f7cd573676dc2c57
size 7085
oid sha256:748b45d63f0614fe78e569474a4b18bb53656a023518b382d7143b8f6f95c8e9
size 7094

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a0f92bf5702aa5c05be66bfd03f2a4437385abe20e8d397c21aaa329018f38ee
size 6617
oid sha256:db4dd789fa9205a59551ee15e2f08d7a37711257c5a35df4169aed8e057f87e1
size 6729

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:212d6a2efc1d6464086a4fbf60922efc6285705d0365752e5d264c1b19c1f97c
size 7063
oid sha256:4845646cc19c7077373de85485a5be098d1cf1e6ab98ac80dd32de683d3595cc
size 6686

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:219a6f8e4032493f96a4df0e1072ad8ddfcd5d77c15878f26c4ffd462417b2d0
size 7303
oid sha256:fd11dd439776c390f18614152a34b0845a2ab99ff6c9e482cd50437c85a22b31
size 6782

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1dfdaca0c643c81a281658b4cee4d0e938d542a57964c3831496d04db543da45
size 9827
oid sha256:842aac7dfd6cf1a7f0100583508bfcf2d2cf636a3b77d175252d90260868f985
size 9822

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f4b748360d95b3898a471c38ca6f1440a6b83590ebd297abdeb59539e08f25a0
size 9535
oid sha256:a87b958c2d5b0bc4826339ecd33eb5bbe68326b8dbe2cff8242796d031323ac1
size 9585

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:01a918a5cbe544f7f0536373b94e41673fa0dfb70a1616aebdab385b9f5e6b74
size 9635
oid sha256:e7ff4f4b2f76c58d94d8f31f1b86a0679d786037efa4e0077f2c7eb59bd14901
size 9640

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c4578011963fa9d2d0a6c5e7278cabf301450e8f2b350ede3cf0b7a175657dcc
size 5519
oid sha256:d2f8cb28bc614e73a70b5192c4c13a1ec580d0aeafa89b096443b514691d26ab
size 5749

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b3c5a7bfa1564787ee64d967e77ca84793f365e3a6d77beeba19106192eb26a3
size 6011
oid sha256:7d2a6926520c23d086b25bd05231943a5f094d3afe8705027b4266e4d17393a9
size 5966

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3817e348ba2775528e3805ad6f5eed044f82b241f73692180c0638c95fb79fa2
size 7076
oid sha256:c669c896158bc19ae916b0e6f1d12f42fe86506323c5bea55e0dd12d9d077153
size 7090

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7aabc26dcb237a1d87c8f888812643e472cff9f082a5fb18d800698762becb63
size 6636
oid sha256:457a91cca308177ac9fb46479c711e4c0863f212e0d20b82008db34a1fb6bb7a
size 6732

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:11a48af25f2b2f656a3e6ce323d2a4b392cf180555f06423c2ecc0044ef9de22
size 6901
oid sha256:a119b19c49aa8fc5aa092cf3a195dbd1ba48e858b7ecf4c9a922624dde9e3213
size 6590

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ce011eeb89741dcdb9c98edfd3f0daf4268e0e02b013caf12fec9b4a33d20b05
size 7132
oid sha256:2154ae0f36cb0b220e8f3b644a16d9a4a61f143d5edcb62f3c962a8136cce577
size 6670

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dbe3214d0b8c497f563957c9df870aa7b6cbf981e174a7f9481cc1555af50533
size 10247
oid sha256:62b94ac085616506e2433b451259d209751fadd43d4442dacc49bf479329dc42
size 10227

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:876ac7c1ac9f3a188bd4ebcc4faef6fd363e166b1ec3d5a844872f7a0cf676aa
size 9969
oid sha256:db18e528fa11b3800dfb48b68b5618edcc8d019320db68e4be5bcf5ad7d8f736
size 9948

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1040e8767f3ce29d40842cb054dea64dc0d355b91ae86b1d25280b9308cdbda7
size 24517
oid sha256:e03637c50b40c8509dac9ff7c06077183945e024ee2a3d6ead14fca5cf79353f
size 24522

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:162a6b2a725ecfda754f8fe8bc06da0bd6b7efd7eb217a2e77b1ece57f89d5d6
size 22936
oid sha256:6a6c39ffde0c5db010ec4df376b4dc89949d4e023afbd5771a0880144c478b6f
size 22920

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6ae5e1ef943fb5f0e0badf41d4ce6317117ab15c8ce8d1bb3a1712260f7f637b
size 28703
oid sha256:a3559b8bbdf1127ab39b884d472c5690ae51d36811e5b27a0e6140aa58480977
size 28661

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a498224c5657212ae19d2854c687a6057735f12521c2a97db9f5754fb23ecfd
size 27828
oid sha256:c144bbc058d1dfe3b75640e017c8e91f455ad86075ef415fa1e25d69d46899ee
size 27816