Skip to content

Commit 7a82af0

Browse files
committed
Implement disable button, and code cleanup
1 parent fd90e60 commit 7a82af0

File tree

6 files changed

+236
-36
lines changed

6 files changed

+236
-36
lines changed

app/src/main/java/at/bitfire/icsdroid/Settings.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class Settings(context: Context) {
2020
val forceDarkMode = booleanPreferencesKey("forceDarkMode")
2121

2222
val nextReminder = longPreferencesKey("nextDonationReminder")
23+
24+
val hideWinterEasterEgg = booleanPreferencesKey("hideWinterEasterEgg")
2325
}
2426

2527
private val dataStore = context.dataStore
@@ -32,4 +34,10 @@ class Settings(context: Context) {
3234
dataStore.edit { it[forceDarkMode] = force }
3335
}
3436

37+
fun hideWinterEasterEggFlow(): Flow<Boolean> = dataStore.data.map { it[hideWinterEasterEgg] ?: false }
38+
suspend fun hideWinterEasterEgg(hide: Boolean) {
39+
// save setting
40+
dataStore.edit { it[hideWinterEasterEgg] = hide }
41+
}
42+
3543
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package at.bitfire.icsdroid.ui
2+
3+
import androidx.compose.foundation.layout.fillMaxSize
4+
import androidx.compose.material.icons.Icons
5+
import androidx.compose.material.icons.filled.AcUnit
6+
import androidx.compose.material.icons.rounded.AcUnit
7+
import androidx.compose.material3.Icon
8+
import androidx.compose.material3.IconButton
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.collectAsState
11+
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.remember
13+
import androidx.compose.runtime.rememberCoroutineScope
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.graphics.vector.rememberVectorPainter
16+
import androidx.compose.ui.platform.LocalContext
17+
import androidx.compose.ui.res.stringResource
18+
import androidx.compose.ui.zIndex
19+
import at.bitfire.icsdroid.R
20+
import at.bitfire.icsdroid.Settings
21+
import at.bitfire.icsdroid.ui.icons.ModeCoolOff
22+
import io.github.vinceglb.confettikit.compose.ConfettiKit
23+
import io.github.vinceglb.confettikit.core.Angle
24+
import io.github.vinceglb.confettikit.core.Party
25+
import io.github.vinceglb.confettikit.core.Position
26+
import io.github.vinceglb.confettikit.core.Rotation
27+
import io.github.vinceglb.confettikit.core.Spread
28+
import io.github.vinceglb.confettikit.core.emitter.Emitter
29+
import io.github.vinceglb.confettikit.core.models.Shape
30+
import io.github.vinceglb.confettikit.core.models.Size
31+
import kotlinx.coroutines.Dispatchers
32+
import kotlinx.coroutines.launch
33+
import java.time.MonthDay
34+
import kotlin.time.Duration
35+
36+
/**
37+
* Determines whether the winter easter egg should be displayed.
38+
*
39+
* It is displayed from December 20th to December 31st.
40+
*/
41+
fun displayWinterEasterEgg(): Boolean {
42+
// return true // Uncomment for testing
43+
val now = MonthDay.now()
44+
return now >= MonthDay.of(12, 20) && now <= MonthDay.of(12, 31)
45+
}
46+
47+
@Composable
48+
fun WinterEasterEggToggleButton() {
49+
val shouldDisplay = remember { displayWinterEasterEgg() }
50+
if (!shouldDisplay) return
51+
52+
val context = LocalContext.current
53+
val settings = remember(context) { Settings(context) }
54+
val scope = rememberCoroutineScope()
55+
56+
val easterEggDisabled by settings.hideWinterEasterEggFlow().collectAsState(false)
57+
58+
IconButton(
59+
onClick = {
60+
scope.launch(Dispatchers.IO) {
61+
settings.hideWinterEasterEgg(!easterEggDisabled)
62+
}
63+
}
64+
) {
65+
Icon(
66+
if (easterEggDisabled) Icons.Rounded.AcUnit else Icons.Rounded.ModeCoolOff,
67+
stringResource(if (easterEggDisabled) R.string.winter_easter_egg_enable else R.string.winter_easter_egg_disable)
68+
)
69+
}
70+
}
71+
72+
@Composable
73+
fun WinterEasterEgg() {
74+
val shouldDisplay = remember { displayWinterEasterEgg() }
75+
if (!shouldDisplay) return
76+
77+
val context = LocalContext.current
78+
val settings = remember(context) { Settings(context) }
79+
val easterEggDisabled by settings.hideWinterEasterEggFlow().collectAsState(false)
80+
if (easterEggDisabled) return
81+
82+
ConfettiKit(
83+
modifier = Modifier
84+
.fillMaxSize()
85+
.zIndex(999f),
86+
parties = listOf(
87+
Party(
88+
speed = 0f,
89+
maxSpeed = 10f,
90+
damping = 0.3f,
91+
size = listOf(Size(20, mass = 2f)),
92+
angle = Angle.BOTTOM,
93+
spread = Spread.ROUND,
94+
colors = listOf(0xb9d0eb, 0xa4abb3, 0x85b8f2),
95+
emitter = Emitter(duration = Duration.INFINITE).perSecond(3),
96+
position = Position.Relative(0.0, 0.0).between(Position.Relative(1.0, 0.0)),
97+
shapes = listOf(
98+
Shape.Vector(rememberVectorPainter(Icons.Default.AcUnit))
99+
),
100+
rotation = Rotation.disabled(),
101+
fadeOutEnabled = false,
102+
timeToLive = 15_000
103+
)
104+
)
105+
)
106+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package at.bitfire.icsdroid.ui.icons
2+
3+
import androidx.compose.material.icons.Icons
4+
import androidx.compose.ui.graphics.Color
5+
import androidx.compose.ui.graphics.SolidColor
6+
import androidx.compose.ui.graphics.vector.ImageVector
7+
import androidx.compose.ui.graphics.vector.path
8+
import androidx.compose.ui.unit.dp
9+
10+
val Icons.Rounded.ModeCoolOff: ImageVector
11+
get() {
12+
if (_ModeCoolOff != null) {
13+
return _ModeCoolOff!!
14+
}
15+
_ModeCoolOff = ImageVector.Builder(
16+
name = "Rounded.ModeCoolOff",
17+
defaultWidth = 24.dp,
18+
defaultHeight = 24.dp,
19+
viewportWidth = 960f,
20+
viewportHeight = 960f
21+
).apply {
22+
path(fill = SolidColor(Color.Black)) {
23+
moveTo(520f, 713f)
24+
verticalLineToRelative(127f)
25+
quadToRelative(0f, 17f, -11.5f, 28.5f)
26+
reflectiveQuadTo(480f, 880f)
27+
quadToRelative(-17f, 0f, -28.5f, -11.5f)
28+
reflectiveQuadTo(440f, 840f)
29+
verticalLineToRelative(-126f)
30+
lineTo(338f, 815f)
31+
quadToRelative(-12f, 11f, -28.5f, 10.5f)
32+
reflectiveQuadTo(282f, 814f)
33+
quadToRelative(-11f, -11f, -11f, -28f)
34+
reflectiveQuadToRelative(11f, -28f)
35+
lineToRelative(141f, -142f)
36+
lineToRelative(-80f, -80f)
37+
lineToRelative(-141f, 142f)
38+
quadToRelative(-11f, 11f, -27.5f, 11.5f)
39+
reflectiveQuadTo(146f, 678f)
40+
quadToRelative(-11f, -11f, -11f, -28f)
41+
reflectiveQuadToRelative(11f, -28f)
42+
lineToRelative(100f, -102f)
43+
lineTo(120f, 520f)
44+
quadToRelative(-17f, 0f, -28.5f, -11.5f)
45+
reflectiveQuadTo(80f, 480f)
46+
quadToRelative(0f, -17f, 11.5f, -28.5f)
47+
reflectiveQuadTo(120f, 440f)
48+
horizontalLineToRelative(127f)
49+
lineTo(59f, 252f)
50+
quadToRelative(-12f, -12f, -11.5f, -28.5f)
51+
reflectiveQuadTo(60f, 195f)
52+
quadToRelative(12f, -12f, 28.5f, -12f)
53+
reflectiveQuadToRelative(28.5f, 12f)
54+
lineTo(796f, 875f)
55+
quadToRelative(12f, 12f, 12f, 28f)
56+
reflectiveQuadToRelative(-12f, 28f)
57+
quadToRelative(-12f, 12f, -28.5f, 12f)
58+
reflectiveQuadTo(739f, 931f)
59+
lineTo(520f, 713f)
60+
close()
61+
moveTo(600f, 520f)
62+
horizontalLineToRelative(-45f)
63+
lineTo(440f, 405f)
64+
verticalLineToRelative(-45f)
65+
lineTo(282f, 202f)
66+
quadToRelative(-11f, -11f, -11.5f, -27.5f)
67+
reflectiveQuadTo(282f, 146f)
68+
quadToRelative(11f, -11f, 28f, -11f)
69+
reflectiveQuadToRelative(28f, 11f)
70+
lineToRelative(102f, 100f)
71+
verticalLineToRelative(-126f)
72+
quadToRelative(0f, -17f, 11.5f, -28.5f)
73+
reflectiveQuadTo(480f, 80f)
74+
quadToRelative(17f, 0f, 28.5f, 11.5f)
75+
reflectiveQuadTo(520f, 120f)
76+
verticalLineToRelative(126f)
77+
lineToRelative(102f, -101f)
78+
quadToRelative(12f, -11f, 28.5f, -10.5f)
79+
reflectiveQuadTo(678f, 146f)
80+
quadToRelative(11f, 11f, 11f, 28f)
81+
reflectiveQuadToRelative(-11f, 28f)
82+
lineTo(520f, 360f)
83+
verticalLineToRelative(80f)
84+
horizontalLineToRelative(80f)
85+
lineToRelative(158f, -158f)
86+
quadToRelative(11f, -11f, 27.5f, -11.5f)
87+
reflectiveQuadTo(814f, 282f)
88+
quadToRelative(11f, 11f, 11f, 28f)
89+
reflectiveQuadToRelative(-11f, 28f)
90+
lineTo(714f, 440f)
91+
horizontalLineToRelative(126f)
92+
quadToRelative(17f, 0f, 28.5f, 11.5f)
93+
reflectiveQuadTo(880f, 480f)
94+
quadToRelative(0f, 17f, -11.5f, 28.5f)
95+
reflectiveQuadTo(840f, 520f)
96+
lineTo(714f, 520f)
97+
lineToRelative(101f, 102f)
98+
quadToRelative(6f, 6f, 8.5f, 13.5f)
99+
reflectiveQuadToRelative(2.5f, 15f)
100+
quadToRelative(0f, 7.5f, -3f, 14.5f)
101+
reflectiveQuadToRelative(-9f, 13f)
102+
quadToRelative(-11f, 11f, -28f, 11f)
103+
reflectiveQuadToRelative(-28f, -11f)
104+
lineTo(600f, 520f)
105+
close()
106+
}
107+
}.build()
108+
109+
return _ModeCoolOff!!
110+
}
111+
112+
@Suppress("ObjectPropertyName")
113+
private var _ModeCoolOff: ImageVector? = null

app/src/main/java/at/bitfire/icsdroid/ui/nav/MainApp.kt

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@ import android.accounts.AccountManager
88
import android.content.Intent
99
import android.net.Uri
1010
import android.os.Bundle
11-
import androidx.compose.foundation.layout.fillMaxSize
12-
import androidx.compose.material.icons.Icons
13-
import androidx.compose.material.icons.filled.AcUnit
1411
import androidx.compose.runtime.Composable
1512
import androidx.compose.runtime.getValue
1613
import androidx.compose.runtime.mutableStateOf
1714
import androidx.compose.runtime.remember
1815
import androidx.compose.runtime.setValue
1916
import androidx.compose.ui.platform.LocalContext
20-
import androidx.compose.ui.zIndex
2117
import androidx.core.app.ShareCompat
2218
import androidx.core.content.IntentCompat
2319
import androidx.core.os.BundleCompat
@@ -31,22 +27,13 @@ import at.bitfire.icsdroid.MainActivity.Companion.EXTRA_REQUEST_CALENDAR_PERMISS
3127
import at.bitfire.icsdroid.MainActivity.Companion.EXTRA_THROWABLE
3228
import at.bitfire.icsdroid.R
3329
import at.bitfire.icsdroid.service.ComposableStartupService
30+
import at.bitfire.icsdroid.ui.WinterEasterEgg
3431
import at.bitfire.icsdroid.ui.partials.AlertDialog
3532
import at.bitfire.icsdroid.ui.screen.AddSubscriptionScreen
3633
import at.bitfire.icsdroid.ui.screen.EditSubscriptionScreen
3734
import at.bitfire.icsdroid.ui.screen.InfoScreen
3835
import at.bitfire.icsdroid.ui.screen.SubscriptionsScreen
39-
import io.github.vinceglb.confettikit.compose.ConfettiKit
40-
import io.github.vinceglb.confettikit.core.Angle
41-
import io.github.vinceglb.confettikit.core.Party
42-
import io.github.vinceglb.confettikit.core.Position
43-
import io.github.vinceglb.confettikit.core.Rotation
44-
import io.github.vinceglb.confettikit.core.Spread
45-
import io.github.vinceglb.confettikit.core.emitter.Emitter
46-
import io.github.vinceglb.confettikit.core.models.Shape
47-
import io.github.vinceglb.confettikit.core.models.Size
4836
import java.util.ServiceLoader
49-
import kotlin.time.Duration
5037

5138
/**
5239
* Computes the correct initial destination from some intent:
@@ -114,28 +101,7 @@ fun MainApp(
114101
else repeat(depth) { backStack.removeAt(backStack.lastIndex) }
115102
}
116103

117-
ConfettiKit(
118-
modifier = Modifier.fillMaxSize().zIndex(999f),
119-
parties = listOf(
120-
Party(
121-
speed = 0f,
122-
maxSpeed = 10f,
123-
damping = 0.3f,
124-
size = listOf(Size(20, mass = 2f)),
125-
angle = Angle.BOTTOM,
126-
spread = Spread.ROUND,
127-
colors = listOf(0xb9d0eb, 0xa4abb3, 0x85b8f2),
128-
emitter = Emitter(duration = Duration.INFINITE).perSecond(3),
129-
position = Position.Relative(0.0, 0.0).between(Position.Relative(1.0, 0.0)),
130-
shapes = listOf(
131-
Shape.Vector(rememberVectorPainter(Icons.Default.AcUnit))
132-
),
133-
rotation = Rotation.disabled(),
134-
fadeOutEnabled = false,
135-
timeToLive = 15_000
136-
)
137-
)
138-
)
104+
WinterEasterEgg()
139105

140106
NavDisplay(
141107
entryDecorators = listOf(

app/src/main/java/at/bitfire/icsdroid/ui/screen/SubscriptionsScreen.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import at.bitfire.icsdroid.SyncWorker
5656
import at.bitfire.icsdroid.UriUtils
5757
import at.bitfire.icsdroid.db.entity.Subscription
5858
import at.bitfire.icsdroid.model.SubscriptionsModel
59+
import at.bitfire.icsdroid.ui.WinterEasterEggToggleButton
5960
import at.bitfire.icsdroid.ui.partials.ActionCard
6061
import at.bitfire.icsdroid.ui.partials.CalendarListItem
6162
import at.bitfire.icsdroid.ui.partials.ExtendedTopAppBar
@@ -192,6 +193,8 @@ fun SubscriptionsScreen(
192193
Text(stringResource(R.string.title_activity_calendar_list))
193194
},
194195
actions = {
196+
WinterEasterEggToggleButton()
197+
195198
ActionOverflowMenu(
196199
subscriptionsCount = subscriptions.size,
197200
forceDarkMode = forceDarkMode,

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,8 @@ along with this program. If not, see <a href="https://www.gnu.org/licenses/">ht
159159
<item quantity="other">%d subscriptions imported</item>
160160
</plurals>
161161

162+
<!-- Winter Easter Egg -->
163+
<string name="winter_easter_egg_disable">Disable Easter Egg</string>
164+
<string name="winter_easter_egg_enable">Enable Easter Egg</string>
165+
162166
</resources>

0 commit comments

Comments
 (0)