Skip to content
Snippets Groups Projects
Unverified Commit 41d3c1bc authored by Mohamed's avatar Mohamed Committed by GitHub
Browse files

Extend poster testability (EXPOSUREAPP-6308) (#2792)


* Rename

* Support  positioning configurations

* Connect sliders values

* Change color

* Polishing

* ViewModel test - resize qr-code

* Font size

* lint

* Polishing

* Add tooltip

* lint

Co-authored-by: default avatarharambasicluka <64483219+harambasicluka@users.noreply.github.com>
parent 97ca2939
No related branches found
No related tags found
No related merge requests found
Showing
with 778 additions and 42 deletions
......@@ -10,7 +10,7 @@ import de.rki.coronawarnapp.test.crash.ui.SettingsCrashReportFragment
import de.rki.coronawarnapp.test.datadonation.ui.DataDonationTestFragment
import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment
import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment
import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment
......@@ -36,7 +36,7 @@ class TestMenuFragmentViewModel @AssistedInject constructor() : CWAViewModel() {
PlaygroundFragment.MENU_ITEM,
DataDonationTestFragment.MENU_ITEM,
DeltaonboardingFragment.MENU_ITEM,
EventRegistrationTestFragment.MENU_ITEM,
PresenceTracingTestFragment.MENU_ITEM,
).let { MutableLiveData(it) }
}
val showTestScreenEvent = SingleLiveEvent<TestMenuItem>()
......
package de.rki.coronawarnapp.test.eventregistration.ui
package de.rki.coronawarnapp.test.presencetracing.ui
import android.annotation.SuppressLint
import android.os.Bundle
......@@ -11,7 +11,7 @@ import androidx.core.text.scale
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestEventregistrationBinding
import de.rki.coronawarnapp.databinding.FragmentTestPresenceTracingBinding
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
......@@ -24,12 +24,12 @@ import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject
@SuppressLint("SetTextI18n")
class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregistration), AutoInject {
class PresenceTracingTestFragment : Fragment(R.layout.fragment_test_presence_tracing), AutoInject {
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val viewModel: EventRegistrationTestFragmentViewModel by cwaViewModels { viewModelFactory }
private val viewModel: PresenceTracingTestViewModel by cwaViewModels { viewModelFactory }
private val binding: FragmentTestEventregistrationBinding by viewBindingLazy()
private val binding: FragmentTestPresenceTracingBinding by viewBindingLazy()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
......@@ -71,8 +71,8 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
lastOrganiserLocationUrl.text = styleText("URL", traceLocation.locationUrl)
qrcodeButton.setOnClickListener {
doNavigate(
EventRegistrationTestFragmentDirections
.actionEventRegistrationTestFragmentToQrCodePosterFragmentTest(traceLocation.id)
PresenceTracingTestFragmentDirections
.actionPresenceTracingTestFragmentToQrCodePosterTestFragment(traceLocation.id)
)
}
}
......@@ -112,7 +112,7 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
buildSpannedString {
bold {
color(requireContext().getColorCompat(R.color.colorAccent)) {
append("$key=")
append("$key = ")
}
}
......@@ -121,14 +121,14 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
append(value.toString())
}
}
append("\n")
appendLine()
}
companion object {
val MENU_ITEM = TestMenuItem(
title = "Event Registration",
description = "View & Control the event registration.",
targetId = R.id.eventRegistrationTestFragment
title = "Presence Tracing",
description = "View & Control presence tracing",
targetId = R.id.presenceTracingTestFragment
)
}
}
package de.rki.coronawarnapp.test.eventregistration.ui
package de.rki.coronawarnapp.test.presencetracing.ui
import dagger.Binds
import dagger.Module
......@@ -8,11 +8,11 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
@Module
abstract class EventRegistrationTestFragmentModule {
abstract class PresenceTracingTestFragmentModule {
@Binds
@IntoMap
@CWAViewModelKey(EventRegistrationTestFragmentViewModel::class)
abstract fun testEventRegistrationFragment(
factory: EventRegistrationTestFragmentViewModel.Factory
@CWAViewModelKey(PresenceTracingTestViewModel::class)
abstract fun testPresenceTracingFragment(
factory: PresenceTracingTestViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
package de.rki.coronawarnapp.test.eventregistration.ui
package de.rki.coronawarnapp.test.presencetracing.ui
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
......@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.map
import timber.log.Timber
import kotlin.system.measureTimeMillis
class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
class PresenceTracingTestViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
traceLocationRepository: TraceLocationRepository,
checkInRepository: CheckInRepository,
......@@ -144,5 +144,5 @@ class EventRegistrationTestFragmentViewModel @AssistedInject constructor(
}
@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<EventRegistrationTestFragmentViewModel>
interface Factory : SimpleCWAViewModelFactory<PresenceTracingTestViewModel>
}
package de.rki.coronawarnapp.test.presencetracing.ui.poster
import android.annotation.SuppressLint
import android.os.Bundle
import android.print.PrintAttributes
import android.print.PrintManager
import android.text.SpannedString
import android.util.TypedValue
import android.view.View
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.getSystemService
import androidx.core.text.bold
import androidx.core.text.buildSpannedString
import androidx.core.text.color
import androidx.core.view.isVisible
import androidx.core.widget.TextViewCompat
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestQrCodePosterBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.server.protocols.internal.pt.QrCodePosterTemplate
import de.rki.coronawarnapp.ui.color.parseColor
import de.rki.coronawarnapp.ui.print.PrintingAdapter
import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.popBackStack
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
import timber.log.Timber
import java.io.File
import javax.inject.Inject
@SuppressLint("SetTextI18n")
class QrCodePosterTestFragment : Fragment(R.layout.fragment_test_qr_code_poster), AutoInject {
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val args by navArgs<QrCodePosterTestFragmentArgs>()
private val viewModel: QrCodePosterTestViewModel by cwaViewModelsAssisted(
factoryProducer = { viewModelFactory },
constructorCall = { factory, _ ->
factory as QrCodePosterTestViewModel.Factory
factory.create(args.traceLocationId)
}
)
private var itemId = -1
private val binding: FragmentTestQrCodePosterBinding by viewBindingLazy()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding) {
toolbar.setNavigationOnClickListener { popBackStack() }
viewModel.poster.observe(viewLifecycleOwner) { poster ->
bindPoster(poster)
bindToolbar()
}
}
viewModel.sharingIntent.observe(viewLifecycleOwner) { fileIntent ->
when (itemId) {
R.id.action_print -> printFile(fileIntent.file)
R.id.action_share -> startActivity(fileIntent.intent(requireActivity()))
}
}
viewModel.qrCodeBitmap.observe(viewLifecycleOwner) {
binding.qrCodeImage.setImageBitmap(it)
}
}
private fun FragmentTestQrCodePosterBinding.bindPoster(poster: QrCodePosterTestViewModel.Poster) {
Timber.d("poster=$poster")
progressBar.hide()
val template = poster.template ?: return // Exit early
Timber.d("template=$template")
// Adjust poster image dimensions ratio to have a proper printing preview
val posterLayoutParam = posterImage.layoutParams as ConstraintLayout.LayoutParams
val dimensionRatio = template.run { "$width:$height" } // W:H
Timber.d("dimensionRatio=$dimensionRatio")
posterLayoutParam.dimensionRatio = dimensionRatio
// Display images
qrCodeImage.setImageBitmap(poster.qrCode)
posterImage.setImageBitmap(template.bitmap)
// Position QR Code image based on data provided by server
topGuideline.setGuidelinePercent(template.offsetY)
startGuideline.setGuidelinePercent(template.offsetX)
endGuideline.setGuidelinePercent(1 - template.offsetX)
// Qr Code positioning
qrOffsetXSlider.apply {
value = template.offsetX.sliderValue
addOnChangeListener { _, value, fromUser ->
if (fromUser) {
val offset = value.percentage
startGuideline.setGuidelinePercent(offset)
endGuideline.setGuidelinePercent(1 - offset)
updateQrCodeOffsetText()
}
}
}
qrOffsetYSlider.apply {
value = template.offsetY.sliderValue
addOnChangeListener { _, value, fromUser ->
if (fromUser) {
topGuideline.setGuidelinePercent(value.percentage)
updateQrCodeOffsetText()
}
}
}
updateQrCodeOffsetText()
qrLengthSlider.apply {
value = poster.template.qrCodeLength.toFloat()
addOnChangeListener { _, value, _ ->
updateQrCodeLengthText()
viewModel.generateQrCode(value.toInt())
}
}
updateQrCodeLengthText()
// Bind text info
bindTextBox(poster.infoText, poster.template.textBox)
offsetsPanel.isVisible = true
tooltip.setOnClickListener {
Toast.makeText(requireContext(), toastText(), Toast.LENGTH_LONG).show()
}
}
private fun toastText(): SpannedString =
buildSpannedString {
bold {
append("Tips:")
}
color(requireContext().getColorCompat(R.color.colorAccent)) {
appendLine()
appendLine()
append(
"- Qr-Code Length defines Qr-Code bitmap length and not" +
"\nthe displayed Qr-Code ImageView where its length is flexible per screen size" +
"\nIn a way it defines the bitmap quality." +
"\nThe more the length the more the bitmaps's sharpness."
)
appendLine()
appendLine()
append(
"- Text below Qr-Code has max 2 lines and has a uniform auto scaling down to `fontSize - 6`." +
"\nIf the size is way larger than it fits in two lines, it will be cut."
)
appendLine()
appendLine()
append(
"- OffsetX defines the position of two guidelines left and right for the edges." +
"\n If the offset is increasing, the space in between the guidelines is decreasing." +
"\n Which means less width of the respective view. -> | -> view_width <- | <- "
)
}
}
private fun updateQrCodeLengthText() {
val value = binding.qrLengthSlider.value
binding.qrCodeLength.text = "Qr Code length:%d".format(value.toInt())
}
private fun FragmentTestQrCodePosterBinding.bindTextBox(
infoText: String,
textBox: QrCodePosterTemplate.QRCodePosterTemplateAndroid.QRCodeTextBoxAndroid
) = with(infoTextView) {
text = infoText
setFontSize(textBox.fontSize)
setTextColor(textBox.fontColor.parseColor())
textEndGuideline.setGuidelinePercent(1 - textBox.offsetX)
textStartGuideline.setGuidelinePercent(textBox.offsetX)
textTopGuideline.setGuidelinePercent(textBox.offsetY)
// Text Position
txtOffsetXSlider.apply {
value = textBox.offsetX.sliderValue
addOnChangeListener { _, value, fromUser ->
if (fromUser) {
val offset = value.percentage
textEndGuideline.setGuidelinePercent(1 - offset)
textStartGuideline.setGuidelinePercent(offset)
updateInfoOffsetText()
}
}
}
txtOffsetYSlider.apply {
value = textBox.offsetY.sliderValue
addOnChangeListener { _, value, fromUser ->
if (fromUser) {
textTopGuideline.setGuidelinePercent(value.percentage)
updateInfoOffsetText()
}
}
}
updateInfoOffsetText()
// Text Size
infoTextSizeSlider.apply {
value = textBox.fontSize.toFloat()
addOnChangeListener { _, value, _ ->
updateFontSizeText()
setFontSize(value.toInt())
}
}
updateFontSizeText()
// Text Color
infoTextColorValue.doOnTextChanged { color, _, _, _ ->
infoTextView.setTextColor(color.toString().parseColor())
}
}
private fun updateFontSizeText() {
binding.infoTextSize.text =
"Font size: %s sp".format(binding.infoTextSizeSlider.value)
}
private fun FragmentTestQrCodePosterBinding.setFontSize(maxFontSize: Int) {
val minFontSize = maxFontSize - 6
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
infoTextView,
minFontSize,
maxFontSize,
1,
TypedValue.COMPLEX_UNIT_SP
)
infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, maxFontSize.toFloat())
}
private fun FragmentTestQrCodePosterBinding.bindToolbar() {
toolbar.setOnMenuItemClickListener {
itemId = it.itemId
viewModel.createPDF(binding.qrCodePoster)
true
}
}
private fun printFile(file: File) {
val printingManger = context?.getSystemService<PrintManager>()
Timber.i("PrintingManager=$printingManger")
if (printingManger == null) {
Toast.makeText(requireContext(), R.string.errors_generic_headline, Toast.LENGTH_LONG).show()
return
}
try {
val job = printingManger.print(
getString(R.string.app_name),
PrintingAdapter(file),
PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A3)
.build()
)
Timber.d("JobState=%s", job.info.state)
} catch (e: Exception) {
Timber.d(e, "Printing job failed")
e.report(ExceptionCategory.INTERNAL)
}
}
private fun updateQrCodeOffsetText() {
with(binding) {
qrCodeOffsets.text = "Qr Code offsets: X=%.3f, Y=%.3f".format(
qrOffsetXSlider.value.percentage,
qrOffsetYSlider.value.percentage
)
}
}
private fun updateInfoOffsetText() {
with(binding) {
infoTextOffsets.text = "Text offsets: X=%.3f, Y=%.3f".format(
txtOffsetXSlider.value.percentage,
txtOffsetYSlider.value.percentage
)
}
}
private val Float.percentage get() = this / 1000
private val Float.sliderValue get() = this * 1000
}
package de.rki.coronawarnapp.test.presencetracing.ui.poster
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
@Module
abstract class QrCodePosterTestFragmentModule {
@Binds
@IntoMap
@CWAViewModelKey(QrCodePosterTestViewModel::class)
abstract fun qrCodePosterTestFragmentModule(
factory: QrCodePosterTestViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
package de.rki.coronawarnapp.test.presencetracing.ui.poster
import android.graphics.Bitmap
import android.graphics.pdf.PdfDocument
import android.view.View
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.PosterTemplateProvider
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.QrCodeGenerator
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.Template
import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.files.FileSharing
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.lang.ref.WeakReference
class QrCodePosterTestViewModel @AssistedInject constructor(
@Assisted private val traceLocationId: Long,
private val dispatcher: DispatcherProvider,
private val qrCodeGenerator: QrCodeGenerator,
private val posterTemplateProvider: PosterTemplateProvider,
private val traceLocationRepository: TraceLocationRepository,
private val fileSharing: FileSharing
) : CWAViewModel(dispatcher) {
private val posterLiveData = MutableLiveData<Poster>()
val poster: LiveData<Poster> = posterLiveData
val sharingIntent = SingleLiveEvent<FileSharing.FileIntentProvider>()
val qrCodeBitmap = SingleLiveEvent<Bitmap>()
private var isRunning = false
init {
generatePoster()
}
/**
* Create a new PDF file and result is delivered by [sharingIntent]
* as a sharing [FileSharing.ShareIntentProvider]
*/
@Suppress("BlockingMethodInNonBlockingContext")
fun createPDF(view: View) = launch(context = dispatcher.IO) {
try {
val weakViewRef = WeakReference(view) // Accessing view in background thread
val directory = File(view.context.cacheDir, "poster").apply { if (!exists()) mkdirs() }
val file = File(directory, "cwa-qr-code.pdf")
val weakView = weakViewRef.get() ?: return@launch // View is not existing anymore
val pageInfo = PdfDocument.PageInfo.Builder(weakView.width, weakView.height, 1).create()
PdfDocument().apply {
startPage(pageInfo).apply {
weakView.draw(canvas)
finishPage(this)
}
FileOutputStream(file).use {
writeTo(it)
close()
}
}
sharingIntent.postValue(fileSharing.getFileIntentProvider(file, traceLocation().description))
} catch (e: Exception) {
Timber.d(e, "Creating pdf failed")
e.report(ExceptionCategory.INTERNAL)
}
}
fun generateQrCode(length: Int) = launch(context = dispatcher.IO) {
try {
if (isRunning) return@launch
isRunning = true
val traceLocation = traceLocation()
val qrCode = qrCodeGenerator.createQrCode(
input = traceLocation.locationUrl,
length = length,
margin = 0
)
qrCodeBitmap.postValue(qrCode)
} catch (e: Exception) {
Timber.e(e)
e.report(ExceptionCategory.INTERNAL)
} finally {
isRunning = false
}
}
private fun generatePoster() = launch(context = dispatcher.IO) {
try {
val traceLocation = traceLocation()
val template = posterTemplateProvider.template()
Timber.d("template=$template")
val qrCode = qrCodeGenerator.createQrCode(
input = traceLocation.locationUrl,
length = template.qrCodeLength,
margin = 0
)
val textInfo = buildString {
append(traceLocation.description)
appendLine()
append(traceLocation.address)
}
posterLiveData.postValue(
Poster(qrCode, template, textInfo)
)
} catch (e: Exception) {
Timber.d(e, "Generating poster failed")
posterLiveData.postValue(Poster())
e.report(ExceptionCategory.INTERNAL)
}
}
private suspend fun traceLocation() = traceLocationRepository.traceLocationForId(traceLocationId)
@AssistedFactory
interface Factory : CWAViewModelFactory<QrCodePosterTestViewModel> {
fun create(
traceLocationId: Long
): QrCodePosterTestViewModel
}
data class Poster(
val qrCode: Bitmap? = null,
val template: Template? = null,
val infoText: String = ""
)
}
......@@ -14,22 +14,22 @@ import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragmentModule
import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragmentModule
import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaonboardingFragment
import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment
import de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragmentModule
import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment
import de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragmentModule
import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragmentModule
import de.rki.coronawarnapp.test.menu.ui.TestMenuFragment
import de.rki.coronawarnapp.test.menu.ui.TestMenuFragmentModule
import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
import de.rki.coronawarnapp.test.playground.ui.PlaygroundModule
import de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragment
import de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragmentModule
import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment
import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragmentModule
import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragment
import de.rki.coronawarnapp.test.submission.ui.SubmissionTestFragmentModule
import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragment
import de.rki.coronawarnapp.test.tasks.ui.TestTaskControllerFragmentModule
import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragment
import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragmentModule
@Module
abstract class MainActivityTestModule {
......@@ -70,9 +70,9 @@ abstract class MainActivityTestModule {
@ContributesAndroidInjector(modules = [DeltaOnboardingFragmentModule::class])
abstract fun deltaOnboarding(): DeltaonboardingFragment
@ContributesAndroidInjector(modules = [EventRegistrationTestFragmentModule::class])
abstract fun eventRegistration(): EventRegistrationTestFragment
@ContributesAndroidInjector(modules = [PresenceTracingTestFragmentModule::class])
abstract fun eventRegistration(): PresenceTracingTestFragment
@ContributesAndroidInjector(modules = [QrCodeDetailFragmentModule::class])
abstract fun showEventDetail(): QrCodeDetailFragment
@ContributesAndroidInjector(modules = [QrCodePosterTestFragmentModule::class])
abstract fun showEventDetail(): QrCodePosterTestFragment
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="HardcodedText">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/CWAToolbar.BackArrow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="2dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/menu_trace_location_qr_code_poster"
app:title="@string/trace_location_organiser_poster_title" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/qr_code_poster"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<ImageView
android:id="@+id/poster_image"
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_constraintDimensionRatio="595:841" />
<ImageView
android:id="@+id/qr_code_image"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="@id/end_guideline"
app:layout_constraintStart_toStartOf="@id/start_guideline"
app:layout_constraintTop_toTopOf="@id/top_guideline"
tools:src="@drawable/ic_qrcode"
tools:tint="@android:color/black" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/start_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.16" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/end_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.84" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.095" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/text_start_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.132" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/text_end_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.87" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/text_top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.61" />
<TextView
android:id="@+id/info_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="2"
app:layout_constraintEnd_toEndOf="@id/text_end_guideline"
app:layout_constraintStart_toStartOf="@id/text_start_guideline"
app:layout_constraintTop_toTopOf="@id/text_top_guideline"
tools:ignore="SmallSp"
tools:text="Vereinsaktivität: Jahrestreffen der deutschen SAP Anwendergruppe\nHauptstr 3, 69115 Heidelberg"
tools:textColor="#000000"
tools:textSize="10sp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:indeterminate="true"
app:hideAnimationBehavior="inward"
app:indicatorColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ScrollView
android:id="@+id/offsets_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:behavior_peekHeight="60dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<LinearLayout
style="@style/Card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:paddingBottom="20dp">
<ImageView
android:id="@+id/tooltip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:background="?selectableItemBackgroundBorderless"
app:srcCompat="@drawable/ic_info" />
<View
android:layout_width="100dp"
android:layout_height="5dp"
android:layout_gravity="center"
android:background="@color/colorAccent" />
</FrameLayout>
<TextView
android:id="@+id/qr_code_offsets"
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QR Code offsets" />
<com.google.android.material.slider.Slider
android:id="@+id/qrOffsetXSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="1"
android:valueFrom="0"
android:valueTo="1000"
app:labelBehavior="gone" />
<com.google.android.material.slider.Slider
android:id="@+id/qrOffsetYSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="1"
android:valueFrom="0"
android:valueTo="1000"
app:labelBehavior="gone" />
<TextView
android:id="@+id/qr_code_length"
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Qr Code length" />
<com.google.android.material.slider.Slider
android:id="@+id/qrLengthSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="100"
android:valueFrom="500"
android:valueTo="2000"
app:labelBehavior="gone" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_marginVertical="10dp"
android:background="#BE818181" />
<TextView
android:id="@+id/info_text_offsets"
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Text offsets" />
<com.google.android.material.slider.Slider
android:id="@+id/txtOffsetXSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="1"
android:valueFrom="0"
android:valueTo="1000"
app:labelBehavior="gone" />
<com.google.android.material.slider.Slider
android:id="@+id/txtOffsetYSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="1"
android:valueFrom="0"
android:valueTo="1000"
app:labelBehavior="gone" />
<TextView
android:id="@+id/info_text_size"
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Font size" />
<com.google.android.material.slider.Slider
android:id="@+id/infoTextSizeSlider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:stepSize="1"
android:valueFrom="10"
android:valueTo="30"
app:labelBehavior="gone" />
<TextView
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Font Color" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/info_text_color_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:hint="#000000 - FallbackColor=#000000" />
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
......@@ -47,8 +47,8 @@
android:id="@+id/action_test_menu_fragment_to_deltaonboardingFragment"
app:destination="@id/test_deltaonboarding_fragment" />
<action
android:id="@+id/action_test_menu_fragment_to_eventRegistrationTestFragment"
app:destination="@id/eventRegistrationTestFragment" />
android:id="@+id/action_test_menu_fragment_to_presenceTracingTestFragment"
app:destination="@id/presenceTracingTestFragment" />
</fragment>
<fragment
......@@ -128,19 +128,19 @@
android:label="DeltaonboardingFragment"
tools:layout="@layout/fragment_test_deltaonboarding" />
<fragment
android:id="@+id/eventRegistrationTestFragment"
android:name="de.rki.coronawarnapp.test.eventregistration.ui.EventRegistrationTestFragment"
android:label="EventRegistrationTestFragment"
tools:layout="@layout/fragment_test_eventregistration">
android:id="@+id/presenceTracingTestFragment"
android:name="de.rki.coronawarnapp.test.presencetracing.ui.PresenceTracingTestFragment"
android:label="PresenceTracingTestFragment"
tools:layout="@layout/fragment_test_presence_tracing">
<action
android:id="@+id/action_eventRegistrationTestFragment_to_qrCodePosterFragmentTest"
app:destination="@id/qrCodePosterFragmentTest" />
android:id="@+id/action_presenceTracingTestFragment_to_qrCodePosterTestFragment"
app:destination="@id/qrCodePosterTestFragment" />
</fragment>
<fragment
android:id="@+id/qrCodePosterFragmentTest"
android:name="de.rki.coronawarnapp.ui.eventregistration.organizer.poster.QrCodePosterFragment"
android:label="qr_code_poster_fragment"
tools:layout="@layout/qr_code_poster_fragment">
android:id="@+id/qrCodePosterTestFragment"
android:name="de.rki.coronawarnapp.test.presencetracing.ui.poster.QrCodePosterTestFragment"
android:label="QrCodePosterTestFragment"
tools:layout="@layout/fragment_test_qr_code_poster">
<argument
android:name="traceLocationId"
......
......@@ -16,6 +16,8 @@ import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocatio
import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragmentModule
import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragment
import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragmentModule
import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragment
import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragmentModule
import de.rki.coronawarnapp.ui.eventregistration.organizer.list.TraceLocationsFragment
import de.rki.coronawarnapp.ui.eventregistration.organizer.list.TraceLocationsFragmentModule
import de.rki.coronawarnapp.ui.eventregistration.organizer.poster.QrCodePosterFragment
......@@ -55,4 +57,7 @@ internal abstract class EventRegistrationUIModule {
@ContributesAndroidInjector(modules = [QrCodePosterFragmentModule::class])
abstract fun qrCodePosterFragment(): QrCodePosterFragment
@ContributesAndroidInjector(modules = [QrCodeDetailFragmentModule::class])
abstract fun showEventDetail(): QrCodeDetailFragment
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment