Skip to content

Commit 25cf733

Browse files
author
Josh
committed
lots of bug fixes
1 parent 053f638 commit 25cf733

30 files changed

Lines changed: 1002 additions & 618 deletions

app/src/main/java/net/frozendevelopment/openletters/MainActivity.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.content.Intent
55
import android.os.Bundle
66
import android.widget.Toast
77
import androidx.activity.ComponentActivity
8+
import androidx.activity.compose.BackHandler
89
import androidx.activity.compose.setContent
910
import androidx.activity.enableEdgeToEdge
1011
import androidx.compose.foundation.layout.Box
@@ -115,6 +116,10 @@ class MainActivity : ComponentActivity() {
115116
directive = directive,
116117
)
117118

119+
BackHandler(drawerState.isOpen) {
120+
coroutineScope.launch { drawerState.close() }
121+
}
122+
118123
OpenLettersTheme(
119124
appTheme = currentTheme.first,
120125
colorPalette = currentTheme.second,

app/src/main/java/net/frozendevelopment/openletters/data/sqldelight/Reminder.sq

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ SELECT id FROM reminder ORDER BY scheduledFor DESC, title ASC;
33

44
urgentReminders:
55
SELECT id FROM reminder WHERE
6-
-- (scheduledFor BETWEEN (strftime('%s','now', 'utc') - 86400) AND (strftime('%s','now', 'utc')) + 86400) AND acknowledged = 0 OR
7-
scheduledFor <= strftime('%s','now', 'utc') AND acknowledged = 0
8-
ORDER BY scheduledFor ASC, created ASC;
6+
(scheduledFor <= strftime('%s','now', 'utc') OR scheduledFor <= strftime('%s', 'now', '+48 hours'))
7+
AND acknowledged = 0
8+
ORDER BY scheduledFor ASC, created DESC;
99

1010
upcomingReminders:
1111
SELECT id FROM reminder WHERE
12-
(scheduledFor > (strftime('%s','now', 'utc'))) AND acknowledged = 0
13-
ORDER BY scheduledFor ASC, created ASC;
12+
(scheduledFor > (strftime('%s', 'now', '+48 hours'))) AND acknowledged = 0
13+
ORDER BY scheduledFor ASC, created DESC;
1414

1515
pastReminders:
16-
SELECT id FROM reminder WHERE acknowledged != 0 ORDER BY scheduledFor DESC, created DESC;
16+
SELECT id FROM reminder WHERE acknowledged = 1 ORDER BY scheduledFor DESC, created DESC;
1717

1818
upsert:
1919
INSERT INTO reminder (id, title, description, scheduledFor, created, lastModified, notificationId) VALUES (

app/src/main/java/net/frozendevelopment/openletters/extensions/LocalDateTimeExtensions.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.frozendevelopment.openletters.extensions
22

3+
import android.text.format.DateUtils
34
import java.time.LocalDateTime
45
import java.time.format.DateTimeFormatter
56

@@ -14,3 +15,9 @@ val LocalDateTime.dateString: String
1415
val dateTimeFormatter = DateTimeFormatter.ofPattern("MMM d, yyyy")
1516
return this.format(dateTimeFormatter)
1617
}
18+
19+
val LocalDateTime.relativeDateString: String
20+
get() {
21+
val targetMillis = toInstant(java.time.ZoneOffset.UTC).toEpochMilli()
22+
return DateUtils.getRelativeTimeSpanString(targetMillis).toString()
23+
}

app/src/main/java/net/frozendevelopment/openletters/extensions/ModifierExtensions.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,29 @@ import androidx.compose.animation.core.tween
99
import androidx.compose.runtime.Composable
1010
import androidx.compose.runtime.getValue
1111
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.draw.scale
1213

1314
@Composable
14-
fun Modifier.pulse() {
15+
fun Modifier.pulse(
16+
initialScale: Float = 1f,
17+
targetScale: Float = 0.95f,
18+
durationMillis: Int = 600,
19+
): Modifier {
1520
val infiniteTransition = rememberInfiniteTransition(label = "pulseInfiniteTransition")
1621
val scale by infiniteTransition.animateFloat(
1722
label = "pulseAnimation",
18-
initialValue = 1f,
19-
targetValue = 0.95f,
23+
initialValue = initialScale,
24+
targetValue = targetScale,
2025
animationSpec =
2126
infiniteRepeatable(
2227
animation =
2328
tween(
24-
durationMillis = 600,
29+
durationMillis = durationMillis,
2530
easing = FastOutLinearInEasing,
2631
),
2732
repeatMode = RepeatMode.Reverse,
2833
),
2934
)
35+
36+
return this.scale(scale)
3037
}

app/src/main/java/net/frozendevelopment/openletters/feature/category/form/CategoryFormView.kt

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.compose.ui.Alignment
3030
import androidx.compose.ui.Modifier
3131
import androidx.compose.ui.graphics.Color
3232
import androidx.compose.ui.graphics.SolidColor
33+
import androidx.compose.ui.res.stringResource
3334
import androidx.compose.ui.text.input.KeyboardCapitalization
3435
import androidx.compose.ui.text.style.TextAlign
3536
import androidx.compose.ui.tooling.preview.PreviewLightDark
@@ -41,6 +42,7 @@ import com.github.skydoves.colorpicker.compose.HsvColorPicker
4142
import com.github.skydoves.colorpicker.compose.rememberColorPickerController
4243
import kotlinx.coroutines.launch
4344
import kotlinx.serialization.Serializable
45+
import net.frozendevelopment.openletters.R
4446
import net.frozendevelopment.openletters.data.sqldelight.models.CategoryId
4547
import net.frozendevelopment.openletters.extensions.Random
4648
import net.frozendevelopment.openletters.extensions.contrastColor
@@ -106,6 +108,7 @@ fun CategoryFormView(
106108

107109
Column(
108110
verticalArrangement = Arrangement.spacedBy(16.dp),
111+
horizontalAlignment = Alignment.CenterHorizontally,
109112
) {
110113
CenterAlignedTopAppBar(
111114
title = { Text(text = state.title) },
@@ -133,10 +136,9 @@ fun CategoryFormView(
133136
}
134137

135138
CategoryPill(
136-
modifier =
137-
Modifier
138-
.padding(horizontal = 16.dp)
139-
.fillMaxWidth(),
139+
modifier = Modifier
140+
.padding(horizontal = 16.dp)
141+
.fillMaxWidth(),
140142
color = state.color,
141143
) {
142144
BasicTextField(
@@ -155,7 +157,7 @@ fun CategoryFormView(
155157
) { innerTextField ->
156158
if (state.label.isBlank() && !isFocused) {
157159
Text(
158-
text = "Tap to type your label",
160+
text = stringResource(R.string.tap_to_type_your_label),
159161
color = state.color.contrastColor,
160162
style = MaterialTheme.typography.titleLarge,
161163
)
@@ -167,36 +169,41 @@ fun CategoryFormView(
167169

168170
HorizontalDivider()
169171

172+
HsvColorPicker(
173+
modifier = Modifier
174+
.fillMaxWidth()
175+
.weight(1f)
176+
.padding(horizontal = 16.dp),
177+
onColorChanged = { onColorChanged(it.color) },
178+
controller = controller,
179+
initialColor = state.color,
180+
)
181+
182+
BrightnessSlider(
183+
modifier = Modifier
184+
.fillMaxWidth()
185+
.height(35.dp)
186+
.padding(horizontal = 16.dp),
187+
controller = controller,
188+
borderRadius = 32.dp,
189+
)
190+
170191
TextButton(
171-
modifier = Modifier.fillMaxWidth(.95f),
192+
modifier = Modifier
193+
.fillMaxWidth()
194+
.padding(16.dp)
195+
.navigationBarsPadding(),
172196
onClick = {
173197
val color = Color.Random
174198
controller.selectByColor(color, true)
175199
onColorChanged(color)
176200
},
177201
) {
178-
Text(text = "Randomize Color")
202+
Text(
203+
text = "Randomize Color",
204+
style = MaterialTheme.typography.titleLarge,
205+
)
179206
}
180-
181-
BrightnessSlider(
182-
modifier =
183-
Modifier
184-
.fillMaxWidth(.95f)
185-
.height(35.dp),
186-
controller = controller,
187-
borderRadius = 32.dp,
188-
)
189-
190-
HsvColorPicker(
191-
modifier =
192-
Modifier
193-
.fillMaxWidth()
194-
.navigationBarsPadding()
195-
.padding(horizontal = 16.dp),
196-
onColorChanged = { onColorChanged(it.color) },
197-
controller = controller,
198-
initialColor = state.color,
199-
)
200207
}
201208
}
202209

@@ -219,11 +226,11 @@ private fun CategoryFormPreview(state: CategoryFormState) {
219226
@PreviewLightDark
220227
private fun CategoryForm() {
221228
CategoryFormPreview(
222-
state =
223-
CategoryFormState(
224-
mode = CategoryFormDestination.Mode.Create,
225-
label = "",
226-
color = Color(0xFF0F0FF0),
227-
),
229+
state = CategoryFormState(
230+
mode = CategoryFormDestination.Mode.Create,
231+
label = "",
232+
color = Color(0xFF0F0FF0),
233+
isBusy = false,
234+
),
228235
)
229236
}

app/src/main/java/net/frozendevelopment/openletters/feature/letter/detail/LetterDetailView.kt

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
package net.frozendevelopment.openletters.feature.letter.detail
22

33
import android.net.Uri
4+
import androidx.compose.foundation.background
45
import androidx.compose.foundation.gestures.detectTapGestures
56
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Box
68
import androidx.compose.foundation.layout.Column
79
import androidx.compose.foundation.layout.PaddingValues
810
import androidx.compose.foundation.layout.fillMaxSize
911
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.layout.height
1013
import androidx.compose.foundation.layout.padding
1114
import androidx.compose.foundation.layout.size
1215
import androidx.compose.foundation.lazy.LazyColumn
1316
import androidx.compose.foundation.lazy.LazyRow
1417
import androidx.compose.foundation.lazy.items
18+
import androidx.compose.foundation.shape.RoundedCornerShape
19+
import androidx.compose.foundation.text.selection.SelectionContainer
1520
import androidx.compose.material.icons.Icons
1621
import androidx.compose.material.icons.automirrored.filled.ArrowBack
1722
import androidx.compose.material.icons.filled.MoreVert
1823
import androidx.compose.material3.CenterAlignedTopAppBar
19-
import androidx.compose.material3.CircularProgressIndicator
2024
import androidx.compose.material3.DropdownMenu
2125
import androidx.compose.material3.DropdownMenuItem
2226
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -86,7 +90,7 @@ fun Module.letterDetailNavigation() = navigation<LetterDetailDestination>(
8690
LetterDetailView(
8791
modifier = Modifier.fillMaxSize(),
8892
state = state,
89-
onEditClicked = { navigator.navigate(ScanLetterDestination(route.letterId)) },
93+
onEditClicked = { navigator.replace(route, ScanLetterDestination(route.letterId)) },
9094
onCreateReminderClicked = {
9195
navigator.navigate(
9296
ReminderFormDestination(preselectedLetters = listOf(route.letterId)),
@@ -197,11 +201,13 @@ fun LetterDetail(
197201
modifier = Modifier.padding(horizontal = 16.dp),
198202
)
199203

200-
Text(
201-
text = state.letter.body ?: stringResource(R.string.no_transcript_available),
202-
style = MaterialTheme.typography.bodyLarge,
203-
modifier = Modifier.padding(horizontal = 16.dp),
204-
)
204+
SelectionContainer {
205+
Text(
206+
text = state.letter.body ?: stringResource(R.string.no_transcript_available),
207+
style = MaterialTheme.typography.bodyLarge,
208+
modifier = Modifier.padding(horizontal = 16.dp),
209+
)
210+
}
205211
}
206212

207213
item {
@@ -236,63 +242,67 @@ fun LetterDetail(
236242
item {
237243
Column(
238244
modifier = Modifier.padding(horizontal = 16.dp),
239-
verticalArrangement = Arrangement.spacedBy(16.dp),
245+
verticalArrangement = Arrangement.spacedBy(8.dp),
240246
) {
241-
Text(
242-
text =
243-
buildAnnotatedString {
247+
SelectionContainer {
248+
Text(
249+
text = buildAnnotatedString {
244250
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
245-
append(stringResource(R.string.from))
251+
append("${stringResource(R.string.from)} ")
246252
}
247253

248254
withStyle(style = SpanStyle(fontWeight = FontWeight.Light)) {
249255
append(state.letter.sender ?: stringResource(R.string.unknown))
250256
}
251257
},
252-
fontSize = MaterialTheme.typography.labelMedium.fontSize,
253-
)
258+
fontSize = MaterialTheme.typography.labelMedium.fontSize,
259+
)
260+
}
254261

255-
Text(
256-
text =
257-
buildAnnotatedString {
262+
SelectionContainer {
263+
Text(
264+
text = buildAnnotatedString {
258265
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
259-
append(stringResource(R.string.to))
266+
append("${stringResource(R.string.to)} ")
260267
}
261268

262269
withStyle(style = SpanStyle(fontWeight = FontWeight.Light)) {
263270
append(state.letter.recipient ?: stringResource(R.string.unknown))
264271
}
265272
},
266-
fontSize = MaterialTheme.typography.labelMedium.fontSize,
267-
)
273+
fontSize = MaterialTheme.typography.labelMedium.fontSize,
274+
)
275+
}
268276

269-
Text(
270-
text =
271-
buildAnnotatedString {
277+
SelectionContainer {
278+
Text(
279+
text = buildAnnotatedString {
272280
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
273-
append(stringResource(R.string.created))
281+
append("${stringResource(R.string.created)} ")
274282
}
275283

276284
withStyle(style = SpanStyle(fontWeight = FontWeight.Light)) {
277285
append(state.letter.created.dateString)
278286
}
279287
},
280-
fontSize = MaterialTheme.typography.labelMedium.fontSize,
281-
)
288+
fontSize = MaterialTheme.typography.labelMedium.fontSize,
289+
)
290+
}
282291

283-
Text(
284-
text =
285-
buildAnnotatedString {
292+
SelectionContainer {
293+
Text(
294+
text = buildAnnotatedString {
286295
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
287-
append(stringResource(R.string.last_modified))
296+
append("${stringResource(R.string.last_modified)} ")
288297
}
289298

290299
withStyle(style = SpanStyle(fontWeight = FontWeight.Light)) {
291300
append(state.letter.created.dateString)
292301
}
293302
},
294-
fontSize = MaterialTheme.typography.labelMedium.fontSize,
295-
)
303+
fontSize = MaterialTheme.typography.labelMedium.fontSize,
304+
)
305+
}
296306
}
297307
}
298308
}
@@ -309,7 +319,19 @@ private fun LetterNotFound() {
309319

310320
@Composable
311321
private fun Loading() {
312-
CircularProgressIndicator()
322+
Column(
323+
verticalArrangement = Arrangement.spacedBy(8.dp),
324+
) {
325+
repeat(5) { index ->
326+
Box(
327+
Modifier
328+
.padding(horizontal = 16.dp)
329+
.background(color = MaterialTheme.colorScheme.surfaceVariant, shape = RoundedCornerShape(8.dp))
330+
.height(24.dp)
331+
.fillMaxWidth(1f - (index * .1f)),
332+
)
333+
}
334+
}
313335
}
314336

315337
@Composable

0 commit comments

Comments
 (0)