diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index de1e6573..00000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e2182830..e162bb30 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { applicationId "com.activityartapp" minSdk 26 targetSdk 33 - versionCode 7 - versionName "1.1.1" + versionCode 8 + versionName "1.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -173,4 +173,5 @@ dependencies { androidTestImplementation "com.squareup.okhttp3:mockwebserver:4.9.1" androidTestImplementation "io.mockk:mockk-android:1.10.5" androidTestImplementation 'androidx.test:runner:1.5.2' + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/data/repository/AthleteUsageRepositoryImpl.kt b/app/src/main/java/com/activityartapp/data/repository/AthleteUsageRepositoryImpl.kt index 7864634d..95591e92 100644 --- a/app/src/main/java/com/activityartapp/data/repository/AthleteUsageRepositoryImpl.kt +++ b/app/src/main/java/com/activityartapp/data/repository/AthleteUsageRepositoryImpl.kt @@ -11,7 +11,7 @@ class AthleteUsageRepositoryImpl @Inject constructor(private val db: FirebaseDat AthleteUsageRepository { companion object { - private const val TIMEOUT_TASK_MS = 5000L + private const val TIMEOUT_TASK_MS = 7500L } override suspend fun getAthleteUsage(athleteId: String): Response { diff --git a/app/src/main/java/com/activityartapp/di/AppModule.kt b/app/src/main/java/com/activityartapp/di/AppModule.kt index caf44a5c..c1a8cfcf 100644 --- a/app/src/main/java/com/activityartapp/di/AppModule.kt +++ b/app/src/main/java/com/activityartapp/di/AppModule.kt @@ -140,6 +140,9 @@ object AppModule { @Provides fun provideActivitySortUtils(timeUtils: TimeUtils) = ActivitySortUtils(timeUtils) + @Provides + fun provideColorBrightnessUtils() = ColorBrightnessUtils() + @Provides fun provideImageSizeUtils() = ImageSizeUtils() @@ -155,9 +158,10 @@ object AppModule { @Provides fun provideVisualizationUtils( activitySortUtils: ActivitySortUtils, + colorBrightnessUtils: ColorBrightnessUtils, @ApplicationContext appContext: Context ) = - VisualizationUtils(appContext, activitySortUtils) + VisualizationUtils(appContext, activitySortUtils, colorBrightnessUtils) @Provides fun provideFileRepository(@ApplicationContext appContext: Context): FileRepository = diff --git a/app/src/main/java/com/activityartapp/presentation/MainActivity.kt b/app/src/main/java/com/activityartapp/presentation/MainActivity.kt index bc719a1b..9ac672ae 100644 --- a/app/src/main/java/com/activityartapp/presentation/MainActivity.kt +++ b/app/src/main/java/com/activityartapp/presentation/MainActivity.kt @@ -168,8 +168,9 @@ class MainActivity : ComponentActivity(), Router { route = SaveArt.withArgs( args = arrayOf( ActivityTypes to gson.toJson(activityTypes), + BackgroundType to backgroundType.toString(), ColorActivitiesArgb to colorActivitiesArgb.toString(), - ColorBackgroundArgb to colorBackgroundArgb.toString(), + ColorsBackgroundArgb to gson.toJson(backgroundColorsArgb), ColorFontArgb to colorFontArgb.toString(), FilterDateAfterMs to filterAfterMs.toString(), FilterDateBeforeMs to filterBeforeMs.toString(), diff --git a/app/src/main/java/com/activityartapp/presentation/MainModels.kt b/app/src/main/java/com/activityartapp/presentation/MainModels.kt index 31c79302..377ecbc4 100644 --- a/app/src/main/java/com/activityartapp/presentation/MainModels.kt +++ b/app/src/main/java/com/activityartapp/presentation/MainModels.kt @@ -6,6 +6,7 @@ import com.activityartapp.architecture.ViewEvent import com.activityartapp.architecture.ViewState import com.activityartapp.presentation.editArtScreen.StrokeWidthType import com.activityartapp.presentation.errorScreen.ErrorScreenType +import com.activityartapp.util.enums.BackgroundType import com.activityartapp.util.enums.EditArtSortDirectionType import com.activityartapp.util.enums.EditArtSortType import com.activityartapp.util.enums.FontSizeType @@ -34,8 +35,9 @@ sealed interface MainDestination : Destination { data class NavigateSaveArt( val activityTypes: List, + val backgroundType: BackgroundType, + val backgroundColorsArgb: List, val colorActivitiesArgb: Int, - val colorBackgroundArgb: Int, val colorFontArgb: Int, val filterBeforeMs: Long, val filterAfterMs: Long, diff --git a/app/src/main/java/com/activityartapp/presentation/MainNavHost.kt b/app/src/main/java/com/activityartapp/presentation/MainNavHost.kt index 63383518..5ad4ad83 100644 --- a/app/src/main/java/com/activityartapp/presentation/MainNavHost.kt +++ b/app/src/main/java/com/activityartapp/presentation/MainNavHost.kt @@ -69,8 +69,9 @@ fun MainNavHost( screen = SaveArt, navArgSpecifications = listOf( ActivityTypes, + BackgroundType, ColorActivitiesArgb, - ColorBackgroundArgb, + ColorsBackgroundArgb, ColorFontArgb, FilterDateAfterMs, FilterDateBeforeMs, diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtDialogType.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtDialogType.kt new file mode 100644 index 00000000..9e3f43a4 --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtDialogType.kt @@ -0,0 +1,8 @@ +package com.activityartapp.presentation.editArtScreen + +enum class EditArtDialogType { + INFO_CHECKERED_BACKGROUND, + INFO_TRANSPARENT, + NAVIGATE_UP, + NONE +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtModels.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtModels.kt index 1f2da935..9b67e913 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtModels.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtModels.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.ScrollState import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.room.Ignore import com.activityartapp.R import com.activityartapp.architecture.ViewEvent import com.activityartapp.architecture.ViewState @@ -30,9 +29,10 @@ annotation class UnixMS sealed interface EditArtViewEvent : ViewEvent { - object DialogNavigateUpCancelled : EditArtViewEvent + object ClickedInfoCheckeredBackground : EditArtViewEvent + object ClickedInfoTransparentBackground : EditArtViewEvent + object DialogDismissed : EditArtViewEvent object DialogNavigateUpConfirmed : EditArtViewEvent - object MakeFullscreenClicked : EditArtViewEvent object NavigateUpClicked : EditArtViewEvent data class PageHeaderClicked(val position: Int) : EditArtViewEvent object SaveClicked : EditArtViewEvent @@ -82,13 +82,25 @@ sealed interface EditArtViewEvent : ViewEvent { data class SizeRotated(val rotatedIndex: Int) : ArtMutatingEvent data class SortDirectionChanged(val changedTo: EditArtSortDirectionType) : ArtMutatingEvent data class SortTypeChanged(val changedTo: EditArtSortType) : ArtMutatingEvent - data class StyleColorFontUseCustomChanged(val useCustom: Boolean) : ArtMutatingEvent - data class StylesColorChanged( - val styleType: StyleType, + data class StyleBackgroundTypeChanged(val changedTo: BackgroundType) : ArtMutatingEvent + data class StyleColorActivitiesChanged( val colorType: ColorType, val changedTo: Float ) : ArtMutatingEvent + data class StyleColorsBackgroundChanged( + val changedIndex: Int, + val changedColorType: ColorType, + val changedTo: Float + ) : ArtMutatingEvent + + data class StyleColorFontChanged( + val colorType: ColorType, + val changedTo: Float + ) : ArtMutatingEvent + + data class StyleColorFontUseCustomChanged(val useCustom: Boolean) : ArtMutatingEvent + data class StylesStrokeWidthChanged(val changedTo: StrokeWidthType) : ArtMutatingEvent data class TypeCustomTextChanged( val section: EditArtTypeSection, @@ -112,11 +124,11 @@ sealed interface EditArtViewState : ViewState { private const val FADE_LENGTH_MS = 1000 } - val dialogNavigateUpActive: Boolean + val dialogActive: EditArtDialogType val pagerStateWrapper: PagerStateWrapper data class Loading( - override val dialogNavigateUpActive: Boolean = false, + override val dialogActive: EditArtDialogType = EditArtDialogType.NONE, override val pagerStateWrapper: PagerStateWrapper = PagerStateWrapper( pagerHeaders = EditArtHeaderType.values().toList(), pagerState = PagerState(EditArtHeaderType.values().toList().size), @@ -133,7 +145,7 @@ sealed interface EditArtViewState : ViewState { @Parcelize data class Standby( @IgnoredOnParcel val bitmap: Bitmap? = null, - @IgnoredOnParcel override val dialogNavigateUpActive: Boolean = false, + @IgnoredOnParcel override val dialogActive: EditArtDialogType = EditArtDialogType.NONE, val filterActivitiesCountDate: Int = 0, val filterActivitiesCountDistance: Int = 0, val filterActivitiesCountType: Int = 0, @@ -166,11 +178,14 @@ sealed interface EditArtViewState : ViewState { green = INIT_ACTIVITIES_GREEN, red = INIT_ACTIVITIES_RED ), - val styleBackground: ColorWrapper = ColorWrapper( - alpha = INIT_BACKGROUND_ALPHA, - blue = INIT_BACKGROUND_BLUE, - green = INIT_BACKGROUND_GREEN, - red = INIT_BACKGROUND_RED + val styleBackgroundType: BackgroundType = BackgroundType.SOLID, + val styleBackgroundColors: List = listOf( + ColorWrapper( + alpha = INIT_BACKGROUND_ALPHA, + blue = INIT_BACKGROUND_BLUE, + green = INIT_BACKGROUND_GREEN, + red = INIT_BACKGROUND_RED + ) ), val styleFont: ColorWrapper? = null, val styleStrokeWidthType: StrokeWidthType = INIT_STROKE_WIDTH, @@ -317,24 +332,6 @@ sealed interface DateSelection : Parcelable { } } -enum class StyleType( - @StringRes val headerStrRes: Int, - @StringRes val descriptionStrRes: Int -) { - BACKGROUND( - R.string.edit_art_style_background_header, - R.string.edit_art_style_background_description - ), - ACTIVITIES( - R.string.edit_art_style_activities_header, - R.string.edit_art_style_activities_description - ), - FONT( - R.string.edit_art_style_font_header, - R.string.edit_art_style_font_description - ); -} - enum class ColorType { RED, GREEN, diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewDelegate.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewDelegate.kt index e782e43d..dd5e4434 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewDelegate.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewDelegate.kt @@ -1,5 +1,6 @@ package com.activityartapp.presentation.editArtScreen +import androidx.activity.compose.BackHandler import androidx.compose.animation.Crossfade import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.tween @@ -10,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.activityartapp.R @@ -19,6 +21,8 @@ import com.activityartapp.presentation.common.type.SubheadHeavy import com.activityartapp.presentation.editArtScreen.EditArtHeaderType.* import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.NavigateUpClicked import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.SaveClicked +import com.activityartapp.presentation.editArtScreen.EditArtDialogType.* +import com.activityartapp.presentation.editArtScreen.composables.EditArtDialogInfo import com.activityartapp.presentation.editArtScreen.composables.EditArtDialogNavigateUp import com.activityartapp.presentation.editArtScreen.subscreens.filters.EditArtFiltersScreen import com.activityartapp.presentation.editArtScreen.subscreens.preview.EditArtPreview @@ -29,8 +33,7 @@ import com.activityartapp.presentation.editArtScreen.subscreens.type.EditArtType import com.activityartapp.presentation.ui.theme.White import com.activityartapp.presentation.ui.theme.spacing import com.activityartapp.util.classes.YearMonthDay -import com.activityartapp.util.enums.EditArtSortDirectionType -import com.activityartapp.util.enums.EditArtSortType +import com.activityartapp.util.enums.BackgroundType import com.google.accompanist.pager.ExperimentalPagerApi private const val DISABLED_ALPHA = 0.5f @@ -100,7 +103,9 @@ fun EditArtViewDelegate(viewModel: EditArtViewModel) { when (it) { PREVIEW -> EditArtPreview( atLeastOneActivitySelected, - bitmap + styleBackgroundType == BackgroundType.TRANSPARENT, + bitmap, + viewModel ) FILTERS -> YearMonthDay.run { EditArtFiltersScreen( @@ -120,8 +125,9 @@ fun EditArtViewDelegate(viewModel: EditArtViewModel) { ) } STYLE -> EditArtStyleViewDelegate( + styleBackgroundColors, + styleBackgroundType, styleActivities, - styleBackground, styleFont, styleStrokeWidthType, viewModel @@ -161,6 +167,24 @@ fun EditArtViewDelegate(viewModel: EditArtViewModel) { } } } - EditArtDialogNavigateUp(eventReceiver = viewModel, isVisible = dialogNavigateUpActive) + + /** Only intercept when the dialog box is not visible **/ + BackHandler(enabled = dialogActive == NONE) { + viewModel.onEvent(NavigateUpClicked) + } + + println("Here, dialog active is $dialogActive") + when (dialogActive) { + INFO_CHECKERED_BACKGROUND -> EditArtDialogInfo( + body = stringArrayResource(id = R.array.edit_art_dialog_info_background_checkered), + eventReceiver = viewModel + ) + INFO_TRANSPARENT -> EditArtDialogInfo( + body = stringArrayResource(id = R.array.edit_art_dialog_info_background_transparent), + eventReceiver = viewModel + ) + NAVIGATE_UP -> EditArtDialogNavigateUp(eventReceiver = viewModel) + NONE -> {} // No-op + } } } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewModel.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewModel.kt index b34eeaa3..51c65531 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewModel.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/EditArtViewModel.kt @@ -17,7 +17,6 @@ import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.* import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.* import com.activityartapp.presentation.editArtScreen.EditArtViewState.Loading import com.activityartapp.presentation.editArtScreen.EditArtViewState.Standby -import com.activityartapp.presentation.editArtScreen.StyleType.* import com.activityartapp.presentation.editArtScreen.subscreens.type.EditArtTypeSection import com.activityartapp.presentation.editArtScreen.subscreens.type.EditArtTypeSection.* import com.activityartapp.presentation.editArtScreen.subscreens.type.EditArtTypeType @@ -218,9 +217,10 @@ class EditArtViewModel @Inject constructor( override fun onEvent(event: EditArtViewEvent) { when (event) { is ArtMutatingEvent -> onArtMutatingEvent(event) - is DialogNavigateUpCancelled -> onDialogNavigateUpCancelled() + is ClickedInfoCheckeredBackground -> onClickedInfoCheckeredBackground() + is ClickedInfoTransparentBackground -> onClickedInfoTransparentBackground() + is DialogDismissed -> onDialogDismissed() is DialogNavigateUpConfirmed -> onDialogNavigateUpConfirmed() - is MakeFullscreenClicked -> onMakeFullscreenClicked() is NavigateUpClicked -> onNavigateUpClicked() is SaveClicked -> onSaveClicked() is SizeCustomChanged -> onSizeCustomChanged(event) @@ -236,7 +236,10 @@ class EditArtViewModel @Inject constructor( is SizeRotated -> onSizeRotated(event) is SortDirectionChanged -> onSortDirectionChanged(event) is SortTypeChanged -> onSortTypeChanged(event) - is StylesColorChanged -> onStylesColorChanged(event) + is StyleBackgroundTypeChanged -> onStyleBackgroundTypeChanged(event) + is StyleColorActivitiesChanged -> onStyleColorActivitiesChanged(event) + is StyleColorsBackgroundChanged -> onStyleColorsBackgroundChanged(event) + is StyleColorFontChanged -> onStyleColorFontChanged(event) is StyleColorFontUseCustomChanged -> onStyleColorFontUseCustomChanged(event) is StylesStrokeWidthChanged -> onStylesStrokeWidthChanged(event) is TypeCustomTextChanged -> onTypeCustomTextChanged(event) @@ -281,12 +284,20 @@ class EditArtViewModel @Inject constructor( } } - private fun onDialogNavigateUpCancelled() { - copyLastState { copy(dialogNavigateUpActive = false) }.push() + private fun onClickedInfoCheckeredBackground() { + pushStateCopy { copy(dialogActive = EditArtDialogType.INFO_CHECKERED_BACKGROUND) } + } + + private fun onClickedInfoTransparentBackground() { + pushStateCopy { copy(dialogActive = EditArtDialogType.INFO_TRANSPARENT) } + } + + private fun onDialogDismissed() { + pushStateCopy { copy(dialogActive = EditArtDialogType.NONE) } } private fun onDialogNavigateUpConfirmed() { - copyLastState { copy(dialogNavigateUpActive = false) }.push() + copyLastState { copy(dialogActive = EditArtDialogType.NONE) }.push() viewModelScope.launch { routeTo(NavigateUp) } } @@ -347,12 +358,8 @@ class EditArtViewModel @Inject constructor( }.push() } - private fun onMakeFullscreenClicked() { - // Todo - } - private fun onNavigateUpClicked() { - copyLastState { copy(dialogNavigateUpActive = true) }.push() + copyLastState { copy(dialogActive = EditArtDialogType.NAVIGATE_UP) }.push() } private fun onPageHeaderClicked(event: PageHeaderClicked) { @@ -371,8 +378,9 @@ class EditArtViewModel @Inject constructor( routeTo( NavigateSaveArt( activityTypes = filteredTypes, + backgroundColorsArgb = styleBackgroundColors.map { it.color.toArgb() }, + backgroundType = styleBackgroundType, colorActivitiesArgb = styleActivities.color.toArgb(), - colorBackgroundArgb = styleBackground.color.toArgb(), colorFontArgb = (styleFont ?: styleActivities).color.toArgb(), filterAfterMs = filterRange?.first ?: Long.MIN_VALUE, filterBeforeMs = filterRange?.last ?: Long.MAX_VALUE, @@ -453,18 +461,46 @@ class EditArtViewModel @Inject constructor( copyLastState { copy(sortTypeSelected = event.changedTo) }.push() } - private fun onStylesColorChanged(event: StylesColorChanged) { - copyLastState { - event.run { - when (styleType) { - BACKGROUND -> copy(styleBackground = styleBackground.copyWithEvent(event)) - ACTIVITIES -> copy(styleActivities = styleActivities.copyWithEvent(event)) - FONT -> copy( - styleFont = (styleFont ?: styleActivities).copyWithEvent(event) + private fun onStyleBackgroundTypeChanged(event: StyleBackgroundTypeChanged) { + copyLastState { copy(styleBackgroundType = event.changedTo) }.push() + } + + private fun onStyleColorActivitiesChanged(event: StyleColorActivitiesChanged) { + pushStateCopy { + copy( + styleActivities = styleActivities.copyWithChange( + colorType = event.colorType, + changedTo = event.changedTo + ) + ) + } + } + + private fun onStyleColorsBackgroundChanged(event: StyleColorsBackgroundChanged) { + pushStateCopy { + copy( + styleBackgroundColors = styleBackgroundColors.toMutableList().apply { + set( + event.changedIndex, + get(event.changedIndex).copyWithChange( + event.changedColorType, + event.changedTo + ) ) } - } - }.push() + ) + } + } + + private fun onStyleColorFontChanged(event: StyleColorFontChanged) { + pushStateCopy { + copy( + styleFont = (styleFont ?: styleActivities).copyWithChange( + colorType = event.colorType, + changedTo = event.changedTo + ) + ) + } } private fun onStyleColorFontUseCustomChanged(event: StyleColorFontUseCustomChanged) { @@ -533,14 +569,15 @@ class EditArtViewModel @Inject constructor( /** @return Copy of an reflecting a [StylesColorChanged] change event * to a [ColorWrapper]. **/ - private fun ColorWrapper.copyWithEvent(event: StylesColorChanged): ColorWrapper { - return event.let { - when (it.colorType) { - ALPHA -> copy(alpha = it.changedTo) - BLUE -> copy(blue = it.changedTo) - GREEN -> copy(green = it.changedTo) - RED -> copy(red = it.changedTo) - } + private fun ColorWrapper.copyWithChange( + colorType: ColorType, + changedTo: Float + ): ColorWrapper { + return when (colorType) { + ALPHA -> copy(alpha = changedTo) + BLUE -> copy(blue = changedTo) + GREEN -> copy(green = changedTo) + RED -> copy(red = changedTo) } } @@ -551,8 +588,9 @@ class EditArtViewModel @Inject constructor( copyLastState { val bitmap = visualizationUtils.createBitmap( activities = activitiesFiltered, // todo... + backgroundType = styleBackgroundType, + backgroundColorsArgb = styleBackgroundColors.map { it.color.toArgb() }, colorActivitiesArgb = styleActivities.color.toArgb(), - colorBackgroundArgb = styleBackground.color.toArgb(), colorFontArgb = (styleFont ?: styleActivities).color.toArgb(), strokeWidth = styleStrokeWidthType, bitmapSize = imageSizeUtils.sizeToMaximumSize( @@ -569,6 +607,7 @@ class EditArtViewModel @Inject constructor( italicized = typeFontItalicized ), fontSize = typeFontSizeSelected, + isPreview = true, sortType = sortTypeSelected, sortDirectionType = sortDirectionTypeSelected, textLeft = LEFT.text, @@ -584,6 +623,13 @@ class EditArtViewModel @Inject constructor( return (lastPushedState as? Standby)?.run(block) ?: error("Last state was not standby") } + private inline fun pushStateCopy(block: Standby.() -> Standby): Unit { + ((lastPushedState as? Standby) + ?.run(block) + ?: error("Last state was not standby")) + .push() + } + private inline fun withLastState(block: Standby.() -> Unit) { (lastPushedState as? Standby)?.run(block) } diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogInfo.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogInfo.kt new file mode 100644 index 00000000..d9d144a5 --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogInfo.kt @@ -0,0 +1,58 @@ +package com.activityartapp.presentation.editArtScreen.composables + +import androidx.compose.foundation.layout.* +import androidx.compose.material.Card +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.activityartapp.architecture.EventReceiver +import com.activityartapp.presentation.common.button.ButtonSize +import com.activityartapp.presentation.common.button.LowEmphasisButton +import com.activityartapp.presentation.common.type.Body +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.* +import com.activityartapp.presentation.ui.theme.spacing +import com.activityartapp.R + +@Composable +fun EditArtDialogInfo( + body: Array, + eventReceiver: EventReceiver +) { + Dialog( + onDismissRequest = { + eventReceiver.onEvent(DialogDismissed) + }, + content = { + Card { + Column( + modifier = Modifier.padding( + start = spacing.medium, + end = spacing.medium, + top = spacing.medium, + bottom = spacing.small + ), + verticalArrangement = Arrangement.spacedBy(spacing.medium) + ) { + body.forEach { Body(text = it) } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + LowEmphasisButton( + size = ButtonSize.SMALL, + modifier = Modifier, + text = stringResource(R.string.edit_art_dialog_info_dismiss) + ) { eventReceiver.onEvent(DialogDismissed) } + } + } + } + }, + properties = DialogProperties( + dismissOnBackPress = true, + dismissOnClickOutside = true + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogNavigateUp.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogNavigateUp.kt index 2cdfbd91..3828527b 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogNavigateUp.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/EditArtDialogNavigateUp.kt @@ -1,6 +1,5 @@ package com.activityartapp.presentation.editArtScreen.composables -import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.* import androidx.compose.material.Card import androidx.compose.runtime.Composable @@ -8,63 +7,55 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties +import com.activityartapp.R import com.activityartapp.architecture.EventReceiver import com.activityartapp.presentation.common.button.ButtonSize import com.activityartapp.presentation.common.button.LowEmphasisButton import com.activityartapp.presentation.common.type.Body import com.activityartapp.presentation.editArtScreen.EditArtViewEvent -import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.* +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.DialogNavigateUpConfirmed import com.activityartapp.presentation.ui.theme.spacing -import com.activityartapp.R @Composable -fun EditArtDialogNavigateUp( - eventReceiver: EventReceiver, - isVisible: Boolean -) { - /** Only intercept when the dialog box is not visible **/ - BackHandler(enabled = !isVisible) { - eventReceiver.onEvent(NavigateUpClicked) - } - - if (isVisible) { - Dialog( - onDismissRequest = { - eventReceiver.onEvent(DialogNavigateUpCancelled) - }, - content = { - Card { - Column( - modifier = Modifier.padding( - start = spacing.medium, - end = spacing.medium, - top = spacing.medium, - bottom = spacing.small - ), - verticalArrangement = Arrangement.spacedBy(spacing.medium) +fun EditArtDialogNavigateUp(eventReceiver: EventReceiver) { + Dialog( + onDismissRequest = { + eventReceiver.onEvent(EditArtViewEvent.DialogDismissed) + }, + content = { + Card { + Column( + modifier = Modifier.padding( + start = spacing.medium, + end = spacing.medium, + top = spacing.medium, + bottom = spacing.small + ), + verticalArrangement = Arrangement.spacedBy(spacing.medium) + ) { + Body(text = stringResource(R.string.edit_art_dialog_exit_confirmation_prompt)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End ) { - Body(text = stringResource(R.string.edit_art_dialog_exit_confirmation_prompt)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.End - ) { - LowEmphasisButton( - size = ButtonSize.SMALL, - text = stringResource(R.string.edit_art_dialog_exit_confirmation_no) - ) { eventReceiver.onEvent(DialogNavigateUpCancelled) } - Spacer(modifier = Modifier.width(spacing.medium)) - LowEmphasisButton( - size = ButtonSize.SMALL, - text = stringResource(R.string.edit_art_dialog_exit_confirmation_yes) - ) { eventReceiver.onEvent(DialogNavigateUpConfirmed) } - } + LowEmphasisButton( + modifier = Modifier, + size = ButtonSize.SMALL, + text = stringResource(R.string.edit_art_dialog_exit_confirmation_no) + ) { eventReceiver.onEvent(EditArtViewEvent.DialogDismissed) } + Spacer(modifier = Modifier.width(spacing.medium)) + LowEmphasisButton( + modifier = Modifier, + size = ButtonSize.SMALL, + text = stringResource(R.string.edit_art_dialog_exit_confirmation_yes) + ) { eventReceiver.onEvent(DialogNavigateUpConfirmed) } } } - }, - properties = DialogProperties( - dismissOnBackPress = true, - dismissOnClickOutside = true - ) + } + }, + properties = DialogProperties( + dismissOnBackPress = true, + dismissOnClickOutside = true ) - } + ) } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/RadioButtonWithContent.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/RadioButtonWithContent.kt new file mode 100644 index 00000000..f4afaffa --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/RadioButtonWithContent.kt @@ -0,0 +1,70 @@ +package com.activityartapp.presentation.editArtScreen.composables + +import androidx.compose.foundation.layout.* +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.RadioButton +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.HelpOutline +import androidx.compose.material.icons.outlined.HelpOutline +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import com.activityartapp.presentation.common.type.Subhead +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent +import com.activityartapp.presentation.ui.theme.Pumpkin +import com.activityartapp.presentation.ui.theme.StravaOrange +import com.activityartapp.presentation.ui.theme.spacing + +@Composable +fun RadioButtonWithContent( + isSelected: Boolean, + text: String, + content: @Composable ColumnScope.() -> Unit = {}, + onHelpPressed: (() -> Unit)? = null, + onSelected: () -> Unit = {} +) { + var heightRadioButton by remember { mutableStateOf(0.dp) } + val localDensity = LocalDensity.current + + Row( + horizontalArrangement = Arrangement.spacedBy(spacing.medium), + verticalAlignment = Alignment.Top + ) { + RadioButton( + selected = isSelected, + onClick = onSelected, + modifier = Modifier + .onGloballyPositioned { + heightRadioButton = localDensity.run { it.size.height.toDp() } + } + ) + Row( + horizontalArrangement = Arrangement.spacedBy(spacing.small), + verticalAlignment = Alignment.CenterVertically + ) { + Column( + modifier = Modifier.defaultMinSize(minHeight = heightRadioButton), + verticalArrangement = Arrangement.spacedBy( + spacing.medium, + Alignment.CenterVertically + ) + ) { + Subhead(text = text) + content() + } + onHelpPressed?.let { + IconButton(onClick = it) { + Icon( + imageVector = Icons.Default.HelpOutline, + contentDescription = null, + tint = Pumpkin + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/Section.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/Section.kt index d23d54dd..07da3723 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/Section.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/composables/Section.kt @@ -10,11 +10,11 @@ import com.activityartapp.presentation.ui.theme.spacing @Composable fun ColumnScope.Section( header: String, - description: String, modifier: Modifier = Modifier, + description: String? = null, content: @Composable ColumnScope.() -> Unit ) { TitleTwo(text = header) - Body(text = description) + description?.let { Body(text = it) } content() } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/preview/EditArtPreviewScreen.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/preview/EditArtPreviewScreen.kt index bad6fe3a..e592fcfd 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/preview/EditArtPreviewScreen.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/preview/EditArtPreviewScreen.kt @@ -4,33 +4,51 @@ import android.graphics.Bitmap import androidx.compose.foundation.Image import androidx.compose.material.CircularProgressIndicator import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import com.activityartapp.R +import com.activityartapp.architecture.EventReceiver import com.activityartapp.presentation.common.ScreenBackground +import com.activityartapp.presentation.common.button.ButtonSize +import com.activityartapp.presentation.common.button.LowEmphasisButton import com.activityartapp.presentation.common.type.Subhead +import com.activityartapp.presentation.common.type.SubheadHeavy import com.activityartapp.presentation.common.type.TitleTwo +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent @Composable fun EditArtPreview( atLeastOneActivitySelected: Boolean, - bitmap: Bitmap? + backgroundIsTransparent: Boolean, + bitmap: Bitmap?, + eventReceiver: EventReceiver ) { - if (!atLeastOneActivitySelected) { - ScreenBackground { + ScreenBackground { + + if (!atLeastOneActivitySelected) { TitleTwo(text = stringResource(R.string.edit_art_preview_activities_zero_count_header)) Subhead(text = stringResource(R.string.edit_art_preview_activities_zero_count_description)) - } - } else { - bitmap?.let { - Image( - bitmap = it.asImageBitmap(), - contentDescription = stringResource(R.string.edit_art_preview_image_content_description), - contentScale = ContentScale.Fit - ) - } ?: run { - CircularProgressIndicator() + + } else { + bitmap?.let { + Image( + bitmap = it.asImageBitmap(), + contentDescription = stringResource(R.string.edit_art_preview_image_content_description), + modifier = Modifier.weight(1f, false), + contentScale = ContentScale.Fit, + ) + if (backgroundIsTransparent) { + LowEmphasisButton( + text = "Why is there a checkered pattern?", + size = ButtonSize.SMALL + ) { eventReceiver.onEvent(EditArtViewEvent.ClickedInfoCheckeredBackground) } + } + } ?: run { + CircularProgressIndicator() + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/EditArtStyleScreen.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/EditArtStyleScreen.kt index a16c6355..faa17cef 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/EditArtStyleScreen.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/EditArtStyleScreen.kt @@ -1,137 +1,80 @@ package com.activityartapp.presentation.editArtScreen.subscreens.style -import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.verticalScroll import androidx.compose.material.RadioButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import com.activityartapp.R import com.activityartapp.architecture.EventReceiver import com.activityartapp.presentation.common.type.Subhead +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StyleBackgroundTypeChanged import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StylesStrokeWidthChanged -import com.activityartapp.presentation.editArtScreen.StyleType.* import com.activityartapp.presentation.editArtScreen.composables.Section -import com.activityartapp.presentation.editArtScreen.subscreens.style.composables.ColorPreview -import com.activityartapp.activityart.presentation.editArtScreen.subscreens.style.composables.ColorSlider import com.activityartapp.presentation.ui.theme.spacing import com.activityartapp.presentation.editArtScreen.* +import com.activityartapp.presentation.editArtScreen.composables.RadioButtonWithContent +import com.activityartapp.presentation.editArtScreen.subscreens.style.composables.* +import com.activityartapp.util.enums.BackgroundType @Composable fun ColumnScope.EditArtStyleViewDelegate( + backgroundColors: List, + backgroundType: BackgroundType, colorActivities: ColorWrapper, - colorBackground: ColorWrapper, - colorFont: ColorWrapper?, + colorText: ColorWrapper?, strokeWidthType: StrokeWidthType, eventReceiver: EventReceiver ) { - StyleType.values().forEach { styleType -> - Section( - header = stringResource(styleType.headerStrRes), - description = stringResource(styleType.descriptionStrRes) - ) { - val color: ColorWrapper = when (styleType) { - ACTIVITIES -> colorActivities - BACKGROUND -> colorBackground - FONT -> colorFont ?: colorActivities - } - ColorPreview(colorWrapper = color) - if (styleType == FONT) { - Row( - horizontalArrangement = Arrangement.spacedBy(spacing.medium), - verticalAlignment = Alignment.CenterVertically - ) { - RadioButton( - selected = colorFont == null, - onClick = { - eventReceiver.onEvent( - EditArtViewEvent.ArtMutatingEvent.StyleColorFontUseCustomChanged( - false - ) - ) - } - ) - Subhead(text = "Use the same color as Activities") - } - } - Row( - horizontalArrangement = Arrangement.spacedBy(spacing.medium), - verticalAlignment = Alignment.Top - ) { - if (styleType == FONT) { - RadioButton( - selected = colorFont != null, - onClick = { - eventReceiver.onEvent( - EditArtViewEvent.ArtMutatingEvent.StyleColorFontUseCustomChanged( - true - ) - ) + Section(header = stringResource(R.string.edit_art_style_background_type_header)) { + ColumnSmallSpacing { + BackgroundType.values().forEach { + RadioButtonWithContent( + isSelected = it == backgroundType, + text = stringResource(it.strRes), + onHelpPressed = if (it == BackgroundType.TRANSPARENT) { + { + println("Sending event?") + eventReceiver.onEvent(EditArtViewEvent.ClickedInfoTransparentBackground) } - ) - } - Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { - if (styleType == FONT) { - Subhead(text = "Choose a different color") + } else { + null } - (ColorSlider( - colorName = stringResource( - R.string.edit_art_style_color_red, - color.redAsEightBit - ), - enabled = styleType != FONT || colorFont != null, - colorValue = color.red, - colorType = ColorType.RED, - styleType = styleType, - eventReceiver = eventReceiver - )) - (ColorSlider( - colorName = stringResource( - R.string.edit_art_style_color_green, - color.greenAsEightBit - ), - enabled = styleType != FONT || colorFont != null, - colorValue = color.green, - colorType = ColorType.GREEN, - styleType = styleType, - eventReceiver = eventReceiver - )) - (ColorSlider( - colorName = stringResource( - R.string.edit_art_style_color_blue, - color.blueAsEightBit - ), - enabled = styleType != FONT || colorFont != null, - colorValue = color.blue, - colorType = ColorType.BLUE, - styleType = styleType, - eventReceiver = eventReceiver - )) - } + ) { eventReceiver.onEvent(StyleBackgroundTypeChanged(changedTo = it)) } } } } + SectionColorBackground( + backgroundType = backgroundType, + colors = backgroundColors, + onColorChanged = eventReceiver::onEvent + ) + SectionColorActivities(color = colorActivities, onColorChanged = eventReceiver::onEvent) + SectionColorText( + color = colorText, + colorActivities = colorActivities, + onColorChanged = eventReceiver::onEvent, + onUseFontChanged = eventReceiver::onEvent + ) Section( header = stringResource(R.string.edit_art_style_stroke_width_header), description = stringResource(R.string.edit_art_style_stroke_width_description) ) { - StrokeWidthType.values().forEach { - Row( - horizontalArrangement = Arrangement.spacedBy(spacing.medium), - verticalAlignment = Alignment.CenterVertically - ) { - RadioButton(selected = strokeWidthType == it, onClick = { - eventReceiver.onEvent( - StylesStrokeWidthChanged(it) - ) - }) - Subhead(text = stringResource(id = it.headerId)) + ColumnSmallSpacing { + StrokeWidthType.values().forEach { + Row( + horizontalArrangement = Arrangement.spacedBy(spacing.medium), + verticalAlignment = Alignment.CenterVertically + ) { + RadioButton(selected = strokeWidthType == it, onClick = { + eventReceiver.onEvent( + StylesStrokeWidthChanged(it) + ) + }) + Subhead(text = stringResource(id = it.headerId)) + } } } } diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderRow.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderIndividual.kt similarity index 50% rename from app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderRow.kt rename to app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderIndividual.kt index 842e6cc4..fe0289bb 100644 --- a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderRow.kt +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSliderIndividual.kt @@ -1,27 +1,23 @@ -package com.activityartapp.activityart.presentation.editArtScreen.subscreens.style.composables +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding import androidx.compose.material.Slider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.activityartapp.architecture.EventReceiver import com.activityartapp.presentation.common.type.SubheadHeavy import com.activityartapp.presentation.editArtScreen.ColorType import com.activityartapp.presentation.editArtScreen.ColorWrapper -import com.activityartapp.presentation.editArtScreen.EditArtViewEvent -import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.* -import com.activityartapp.presentation.editArtScreen.StyleType import com.activityartapp.presentation.ui.theme.spacing -// Todo, rework this, very sloppy atm @Composable fun ColorSlider( colorName: String, colorValue: Float, colorType: ColorType, enabled: Boolean, - styleType: StyleType, - eventReceiver: EventReceiver + onColorChanged: (Pair) -> Unit ) { Column(verticalArrangement = Arrangement.spacedBy(spacing.medium)) { SubheadHeavy(colorName, modifier = Modifier.padding(start = spacing.small)) @@ -30,15 +26,7 @@ fun ColorSlider( value = colorValue, enabled = enabled, valueRange = ColorWrapper.VALUE_RANGE, - onValueChange = { - eventReceiver.onEvent( - StylesColorChanged( - styleType = styleType, - colorType = colorType, - changedTo = it - ) - ) - } + onValueChange = { onColorChanged(colorType to it) } ) } } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSlidersRGB.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSlidersRGB.kt new file mode 100644 index 00000000..a17f4a9e --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColorSlidersRGB.kt @@ -0,0 +1,46 @@ +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.activityartapp.R +import com.activityartapp.presentation.editArtScreen.ColorType +import com.activityartapp.presentation.editArtScreen.ColorWrapper + +@Composable +fun ColorSlidersRGB( + color: ColorWrapper, + enabled: Boolean, + onColorChanged: (Pair) -> Unit +) { + ColorSlider( + colorName = stringResource( + R.string.edit_art_style_color_red, + color.redAsEightBit + ), + enabled = enabled, + colorValue = color.red, + colorType = ColorType.RED, + onColorChanged = onColorChanged + ) + ColorSlider( + colorName = stringResource( + R.string.edit_art_style_color_green, + color.greenAsEightBit + ), + enabled = enabled, + colorValue = color.green, + colorType = ColorType.GREEN, + onColorChanged = onColorChanged + ) + ColorSlider( + colorName = stringResource( + R.string.edit_art_style_color_blue, + color.blueAsEightBit + ), + enabled = enabled, + colorValue = color.blue, + colorType = ColorType.BLUE, + onColorChanged = onColorChanged + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColumnSmallSpacing.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColumnSmallSpacing.kt new file mode 100644 index 00000000..f42490fa --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/ColumnSmallSpacing.kt @@ -0,0 +1,15 @@ +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import com.activityartapp.presentation.ui.theme.spacing + +@Composable +fun ColumnSmallSpacing(content: @Composable ColumnScope.() -> Unit) { + Column( + content = content, + verticalArrangement = Arrangement.spacedBy(spacing.small) + ) +} diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorActivities.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorActivities.kt new file mode 100644 index 00000000..1c5f1c95 --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorActivities.kt @@ -0,0 +1,31 @@ +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.activityartapp.R +import com.activityartapp.presentation.editArtScreen.ColorType +import com.activityartapp.presentation.editArtScreen.ColorWrapper +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StyleColorActivitiesChanged +import com.activityartapp.presentation.editArtScreen.composables.Section + +@Composable +fun ColumnScope.SectionColorActivities( + color: ColorWrapper, + onColorChanged: (StyleColorActivitiesChanged) -> Unit +) { + Section( + header = stringResource(R.string.edit_art_style_activities_header), + description = stringResource(R.string.edit_art_style_activities_description) + ) { + ColorPreview(colorWrapper = color) + ColorSlidersRGB(color = color, enabled = true) { + onColorChanged( + StyleColorActivitiesChanged( + colorType = it.first, + changedTo = it.second + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorBackground.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorBackground.kt new file mode 100644 index 00000000..7d4dd75d --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorBackground.kt @@ -0,0 +1,42 @@ +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.activityartapp.R +import com.activityartapp.presentation.editArtScreen.ColorType +import com.activityartapp.presentation.editArtScreen.ColorWrapper +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StyleColorsBackgroundChanged +import com.activityartapp.presentation.editArtScreen.composables.Section +import com.activityartapp.util.enums.BackgroundType + +@Composable +fun ColumnScope.SectionColorBackground( + backgroundType: BackgroundType, + colors: List, + onColorChanged: (StyleColorsBackgroundChanged) -> Unit +) { + if (backgroundType != BackgroundType.TRANSPARENT) { + Section( + header = stringResource(R.string.edit_art_style_background_header), + description = stringResource(R.string.edit_art_style_background_type_solid_description) + ) { + colors.forEachIndexed { index, color -> + ColorPreview(colorWrapper = color) + ColorSlidersRGB( + color = color, + enabled = true, + onColorChanged = { + onColorChanged( + StyleColorsBackgroundChanged( + changedIndex = index, + changedColorType = it.first, + changedTo = it.second + ) + ) + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorText.kt b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorText.kt new file mode 100644 index 00000000..76df38b1 --- /dev/null +++ b/app/src/main/java/com/activityartapp/presentation/editArtScreen/subscreens/style/composables/SectionColorText.kt @@ -0,0 +1,47 @@ +package com.activityartapp.presentation.editArtScreen.subscreens.style.composables + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.activityartapp.R +import com.activityartapp.presentation.editArtScreen.ColorWrapper +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StyleColorFontChanged +import com.activityartapp.presentation.editArtScreen.EditArtViewEvent.ArtMutatingEvent.StyleColorFontUseCustomChanged +import com.activityartapp.presentation.editArtScreen.composables.RadioButtonWithContent +import com.activityartapp.presentation.editArtScreen.composables.Section + +@Composable +fun ColumnScope.SectionColorText( + color: ColorWrapper?, + colorActivities: ColorWrapper, + onColorChanged: (StyleColorFontChanged) -> Unit, + onUseFontChanged: (StyleColorFontUseCustomChanged) -> Unit +) { + val customEnabled = color != null + Section(header = stringResource(R.string.edit_art_style_text_header)) { + ColorPreview(colorWrapper = color ?: colorActivities) + ColumnSmallSpacing { + RadioButtonWithContent( + isSelected = !customEnabled, + text = stringResource(R.string.edit_art_style_font_use_activities) + ) { onUseFontChanged(StyleColorFontUseCustomChanged(useCustom = false)) } + RadioButtonWithContent( + isSelected = customEnabled, + text = stringResource(R.string.edit_art_style_font_use_custom), + content = { + ColorSlidersRGB( + color = color ?: colorActivities, + enabled = customEnabled, + onColorChanged = { + onColorChanged( + StyleColorFontChanged( + colorType = it.first, + changedTo = it.second + ) + ) + } + ) + }) { onUseFontChanged(StyleColorFontUseCustomChanged(useCustom = true)) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/presentation/saveArtScreen/SaveArtViewModel.kt b/app/src/main/java/com/activityartapp/presentation/saveArtScreen/SaveArtViewModel.kt index 36cf3e00..4a5d2059 100644 --- a/app/src/main/java/com/activityartapp/presentation/saveArtScreen/SaveArtViewModel.kt +++ b/app/src/main/java/com/activityartapp/presentation/saveArtScreen/SaveArtViewModel.kt @@ -17,6 +17,7 @@ import com.activityartapp.presentation.saveArtScreen.SaveArtViewState.Standby.Do import com.activityartapp.presentation.saveArtScreen.SaveArtViewEvent.* import com.activityartapp.util.* import com.activityartapp.util.NavArgSpecification.* +import com.activityartapp.util.enums.BackgroundType import com.activityartapp.util.enums.EditArtSortDirectionType import com.activityartapp.util.enums.EditArtSortType import com.activityartapp.util.enums.FontSizeType @@ -26,6 +27,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import javax.inject.Inject +import kotlin.math.roundToInt @HiltViewModel class SaveArtViewModel @Inject constructor( @@ -43,8 +45,12 @@ class SaveArtViewModel @Inject constructor( List::class.java ) private val activities = getActivitiesFromMemory() + private val backgroundType = + BackgroundType.valueOf(NavArgSpecification.BackgroundType.rawArg(ssh)) private val colorActivitiesArgb = ColorActivitiesArgb.rawArg(ssh).toInt() - private val colorBackgroundArgb = ColorBackgroundArgb.rawArg(ssh).toInt() + private val colorsBackgroundArgb: List = gson + .fromJson>(ColorsBackgroundArgb.rawArg(ssh), List::class.java) + .map { it.roundToInt() } // Gson treats the List as a List initially private val colorFontArgb = ColorFontArgb.rawArg(ssh).toInt() private val filterDateAfterMs = FilterDateAfterMs.rawArg(ssh).toLong() private val filterDateBeforeMs = FilterDateBeforeMs.rawArg(ssh).toLong() @@ -86,7 +92,7 @@ class SaveArtViewModel @Inject constructor( viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.Default) { fileRepository - .saveBitmapToGallery(createArtBitmapOfSize(sizePx)) + .saveBitmapToGallery(createArtBitmapOfSize(false, sizePx)) .doOnSuccess { pushUpdateToDownloadShareStatus(DOWNLOAD_SUCCESS) } .doOnError { pushUpdateToDownloadShareStatus(DOWNLOAD_FAILURE) } } @@ -114,7 +120,7 @@ class SaveArtViewModel @Inject constructor( pushUpdateToDownloadShareStatus(SHARE_IN_PROGRESS) viewModelScope.launch(Dispatchers.IO) { fileRepository - .saveBitmapToCache(createArtBitmapOfSize(sizePx)) + .saveBitmapToCache(createArtBitmapOfSize(false, sizePx)) .doOnSuccess { withContext(Dispatchers.Main) { routeTo(ShareFile(data)) @@ -146,7 +152,8 @@ class SaveArtViewModel @Inject constructor( viewModelScope.launch(Dispatchers.Default) { Standby( bitmapScreenSize = createArtBitmapOfSize( - imageSizeUtils.sizeToMaximumSize( + isPreview = true, + size = imageSizeUtils.sizeToMaximumSize( actualSize = sizePx, maximumSize = event.size ) @@ -155,7 +162,7 @@ class SaveArtViewModel @Inject constructor( } } - private fun createArtBitmapOfSize(size: Size): Bitmap { + private fun createArtBitmapOfSize(isPreview: Boolean, size: Size): Bitmap { return visualizationUtils.createBitmap( activities = activityFilterUtils.filterActivities( activities = activities, @@ -163,10 +170,12 @@ class SaveArtViewModel @Inject constructor( unixMsRange = filterDateAfterMs..filterDateBeforeMs, distanceRange = filterDistanceMoreThanMeters..filterDistanceLessThanMeters ), + backgroundType = backgroundType, fontAssetPath = fontAssetPath, fontSize = fontTypeSize, + isPreview = isPreview, colorActivitiesArgb = colorActivitiesArgb, - colorBackgroundArgb = colorBackgroundArgb, + backgroundColorsArgb = colorsBackgroundArgb, colorFontArgb = colorFontArgb, bitmapSize = size, sortType = sortType, diff --git a/app/src/main/java/com/activityartapp/util/ColorBrightnessUtils.kt b/app/src/main/java/com/activityartapp/util/ColorBrightnessUtils.kt new file mode 100644 index 00000000..b8d417f2 --- /dev/null +++ b/app/src/main/java/com/activityartapp/util/ColorBrightnessUtils.kt @@ -0,0 +1,36 @@ +package com.activityartapp.util + +import android.graphics.Paint +import androidx.annotation.ColorInt +import androidx.core.graphics.ColorUtils + +class ColorBrightnessUtils { + + companion object { + private const val MAXIMUM_DARK_LUMINANCE = 0.5 + } + + fun selectPaintsRelativeToColor( + @ColorInt color: Int, + @ColorInt colorWhenDarkOne: Int, + @ColorInt colorWhenDarkTwo: Int, + @ColorInt colorWhenLightOne: Int, + @ColorInt colorWhenLightTwo: Int + ): Pair { + val paintOne: Paint + val paintTwo: Paint + + if (isDark(color)) { + paintOne = Paint().apply { this.color = colorWhenDarkOne } + paintTwo = Paint().apply { this.color = colorWhenDarkTwo } + } else { + paintOne = Paint().apply { this.color = colorWhenLightOne } + paintTwo = Paint().apply { this.color = colorWhenLightTwo } + } + + return paintOne to paintTwo + } + + private fun isDark(@ColorInt color: Int): Boolean = + ColorUtils.calculateLuminance(color) <= MAXIMUM_DARK_LUMINANCE +} \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/util/NavArgSpecification.kt b/app/src/main/java/com/activityartapp/util/NavArgSpecification.kt index f2f3a547..4e73635e 100644 --- a/app/src/main/java/com/activityartapp/util/NavArgSpecification.kt +++ b/app/src/main/java/com/activityartapp/util/NavArgSpecification.kt @@ -11,8 +11,9 @@ sealed interface NavArgSpecification { private const val ACTIVITY_TYPES_KEY = "activityTypes" private const val ATHLETE_ID_KEY = "athleteId" private const val ACCESS_TOKEN_KEY = "accessToken" + private const val BACKGROUND_TYPE_KEY = "backgroundType" private const val COLOR_ACTIVITIES_KEY = "colorActivities" - private const val COLOR_BACKGROUND_KEY = "colorBackground" + private const val COLORS_BACKGROUND_KEY = "colorsBackground" private const val COLOR_FONT_KEY = "colorFont" private const val ERROR_SCREEN_TYPE = "errorScreenType" private const val FILTER_DATE_AFTER_MS_KEY = "filterDateAfterMs" @@ -60,12 +61,16 @@ sealed interface NavArgSpecification { override val name = ACCESS_TOKEN_KEY } + object BackgroundType : NavArgSpecification { + override val name = BACKGROUND_TYPE_KEY + } + object ColorActivitiesArgb : NavArgSpecification { override val name = COLOR_ACTIVITIES_KEY } - object ColorBackgroundArgb : NavArgSpecification { - override val name = COLOR_BACKGROUND_KEY + object ColorsBackgroundArgb : NavArgSpecification { + override val name = COLORS_BACKGROUND_KEY } object ColorFontArgb : NavArgSpecification { diff --git a/app/src/main/java/com/activityartapp/util/VisualizationUtils.kt b/app/src/main/java/com/activityartapp/util/VisualizationUtils.kt index 60511252..105a793f 100644 --- a/app/src/main/java/com/activityartapp/util/VisualizationUtils.kt +++ b/app/src/main/java/com/activityartapp/util/VisualizationUtils.kt @@ -3,9 +3,13 @@ package com.activityartapp.util import android.content.Context import android.graphics.* import android.util.Size +import androidx.annotation.ColorInt import androidx.annotation.Px +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.SweepGradientShader import com.activityartapp.domain.models.Activity import com.activityartapp.presentation.editArtScreen.StrokeWidthType +import com.activityartapp.util.enums.BackgroundType import com.activityartapp.util.enums.EditArtSortDirectionType import com.activityartapp.util.enums.EditArtSortType import com.activityartapp.util.enums.FontSizeType @@ -13,11 +17,13 @@ import com.google.maps.android.PolyUtil import javax.inject.Inject import kotlin.math.ceil import kotlin.math.floor +import kotlin.math.roundToInt import kotlin.math.sqrt class VisualizationUtils @Inject constructor( private val context: Context, - private val activitySortUtils: ActivitySortUtils + private val activitySortUtils: ActivitySortUtils, + private val colorBrightnessUtils: ColorBrightnessUtils ) { companion object { @@ -26,16 +32,19 @@ class VisualizationUtils @Inject constructor( private const val ACTIVITY_STROKE_MEDIUM_REDUCE_FRACTION = 0.25f private const val ACTIVITY_STROKE_LARGE_REDUCE_FRACTION = 0.50f private const val OFFSET_ZERO_PX = 0f + private const val TRANSPARENT_GRID_SIZE_PX = 50 } fun createBitmap( activities: List, + backgroundType: BackgroundType, + backgroundColorsArgb: List, colorActivitiesArgb: Int, - colorBackgroundArgb: Int, colorFontArgb: Int, bitmapSize: Size, fontAssetPath: String, fontSize: FontSizeType, + isPreview: Boolean, sortType: EditArtSortType, sortDirectionType: EditArtSortDirectionType, strokeWidth: StrokeWidthType, @@ -78,7 +87,14 @@ class VisualizationUtils @Inject constructor( Bitmap.Config.ARGB_8888 ).also { bitmap -> Canvas(bitmap).apply { - drawBackground(colorBackgroundArgb) + when (backgroundType) { + BackgroundType.TRANSPARENT -> if (isPreview) { + drawBackgroundGrid(colorActivitiesArgb) + } + BackgroundType.SOLID -> backgroundColorsArgb + .firstOrNull() + ?.let { drawBackgroundSolid(it) } + } val padding = paddingFraction * minOf(width, height) val paddingOnEachSide = (padding * 2f).toInt() @@ -198,7 +214,7 @@ class VisualizationUtils @Inject constructor( } } - private fun Canvas.drawBackground(argb: Int) { + private fun Canvas.drawBackgroundSolid(argb: Int) { drawRect( OFFSET_ZERO_PX, OFFSET_ZERO_PX, @@ -208,6 +224,36 @@ class VisualizationUtils @Inject constructor( ) } + private fun Canvas.drawBackgroundGrid(@ColorInt colorActivities: Int) { + val paints = colorBrightnessUtils.selectPaintsRelativeToColor( + color = colorActivities, + colorWhenDarkOne = Color.WHITE, + colorWhenDarkTwo = Color.argb(255, 240, 240, 240), + colorWhenLightOne = Color.BLACK, + colorWhenLightTwo = Color.DKGRAY + ) + + val rows = (height.toFloat() / TRANSPARENT_GRID_SIZE_PX).roundToInt() + val cols = (width.toFloat() / TRANSPARENT_GRID_SIZE_PX).roundToInt() + + var offsetY = OFFSET_ZERO_PX + for (row in 0..rows) { + var offsetX = OFFSET_ZERO_PX + for (col in 0..cols) { + drawRect( + offsetX, + offsetY, + offsetX + TRANSPARENT_GRID_SIZE_PX, + offsetY + TRANSPARENT_GRID_SIZE_PX, + if ((row + col) % 2 == 0) paints.first else paints.second + ) + offsetX += TRANSPARENT_GRID_SIZE_PX + } + offsetY += TRANSPARENT_GRID_SIZE_PX + } + + } + private data class DrawingSpecification( val activitySize: Float, val cols: Int, diff --git a/app/src/main/java/com/activityartapp/util/classes/ApiError.kt b/app/src/main/java/com/activityartapp/util/classes/ApiError.kt index 444b20a5..b9ae859b 100644 --- a/app/src/main/java/com/activityartapp/util/classes/ApiError.kt +++ b/app/src/main/java/com/activityartapp/util/classes/ApiError.kt @@ -14,6 +14,7 @@ sealed interface ApiError { companion object { fun valueOf(value: Exception?): ApiError { + println("Determining what exception $value is") return when (value) { is UnknownHostException -> NoInternet is AthleteRateLimitedException -> AthleteRateLimited diff --git a/app/src/main/java/com/activityartapp/util/constants/StringConstants.kt b/app/src/main/java/com/activityartapp/util/constants/StringConstants.kt index 390f5e2c..4efbe12b 100644 --- a/app/src/main/java/com/activityartapp/util/constants/StringConstants.kt +++ b/app/src/main/java/com/activityartapp/util/constants/StringConstants.kt @@ -2,5 +2,5 @@ package com.activityartapp.util.constants object StringConstants { const val BASE_URL = "https://www.strava.com/" - const val APP_VERSION = "1.1.1" + const val APP_VERSION = "1.2.0" } \ No newline at end of file diff --git a/app/src/main/java/com/activityartapp/util/enums/BackgroundType.kt b/app/src/main/java/com/activityartapp/util/enums/BackgroundType.kt new file mode 100644 index 00000000..de835537 --- /dev/null +++ b/app/src/main/java/com/activityartapp/util/enums/BackgroundType.kt @@ -0,0 +1,9 @@ +package com.activityartapp.util.enums + +import androidx.annotation.StringRes +import com.activityartapp.R + +enum class BackgroundType(@StringRes val strRes: Int) { + SOLID(R.string.edit_art_style_background_type_solid), + TRANSPARENT(R.string.edit_art_style_background_type_transparent) +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2f0a9551..72f5fbf9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,8 +32,8 @@ About - Activity Art lets athletes create fully-customizable digital artwork of their Strava activities at a high resolution appropriate for printing and framing. - Athletes may visualize only some of their activities as determined by filters they set that include the activity date, distance, and type. + Activity Art helps you create customizable artwork with your Strava activities. The art you can make with this app is perfect for framing, computer wallpaper, printing on a shirt, and more! + This app is my project, and I want to make it the best I can! Please consider leaving a review if you are enjoying the app to help others find it. If you have any feature requests or find a bug, write me at tyler@activityartapp.com - thanks! @@ -162,18 +162,18 @@ Which range of distances should be used? - Background - - What color should the background of the art be? - - Activities - - What color should the activities of the art be? - - Font - - What color should any text be? - + Background Type + Which type of background should be used? + Transparent + Solid Color + Background Color + What solid color should the background of the art be? + Activities Color + What color should the activities of the art be? + Font Color + What color should any text be? + Use the same color as your activities + Choose a different color Red: %d Green: %d Blue: %d @@ -243,6 +243,15 @@ Height: %d pixels Width: %d pixels %d x %d pixels + + We added a checkerboard pattern to help you see your art with a transparent background. + Don\'t worry - we\'ll remove it when you download or share it! + + + A transparent background is like having no background at all. + If you want to print your art on something (like a t-shirt), a transparent background can be a great option! + + @android:string/ok Discard unsaved changes? Discard Cancel