Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<ID>FunctionNaming:ProfileScreen.kt$@Composable private fun ProfileSearchButton( onClick: () -&gt; Unit, enabled: Boolean, isLoading: Boolean, modifier: Modifier = Modifier )</ID>
<ID>FunctionNaming:ProfileScreen.kt$@OptIn(ExperimentalComposeUiApi::class) @Composable private fun UserSearchCard( email: String, onEmailChange: (String) -&gt; Unit, onSearchClick: () -&gt; Unit, isLoading: Boolean, modifier: Modifier = Modifier )</ID>
<ID>FunctionNaming:ProfileScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ProfileScreen( modifier: Modifier = Modifier, onNavigateUp: () -&gt; Unit, profileViewModel: ProfileViewModel )</ID>
<ID>FunctionNaming:PushCommentCard.kt$@Composable fun PushCommentCard(comment: String, author: String?, revision: String)</ID>
<ID>FunctionNaming:PushCommentCard.kt$@Composable fun PushCommentCard( comment: String, author: String?, revision: String, pushTimestamp: Long, )</ID>
<ID>FunctionNaming:Theme.kt$@Composable fun FenixInstallerTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, content: @Composable () -&gt; Unit )</ID>
<ID>FunctionNaming:TreeherderApksScreen.kt$@Composable fun ErrorState(errorMessage: String)</ID>
<ID>FunctionNaming:TreeherderApksScreen.kt$@Composable fun LoadingState()</ID>
Expand All @@ -52,7 +52,7 @@
<ID>LongMethod:ProfileScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ProfileScreen( modifier: Modifier = Modifier, onNavigateUp: () -&gt; Unit, profileViewModel: ProfileViewModel )</ID>
<ID>LongMethod:ProfileViewModel.kt$ProfileViewModel$fun downloadArtifact(artifactUiModel: ArtifactUiModel, context: Context)</ID>
<ID>LongMethod:ProfileViewModel.kt$ProfileViewModel$fun searchByAuthor(context: Context)</ID>
<ID>LongMethod:PushCommentCard.kt$@Composable fun PushCommentCard(comment: String, author: String?, revision: String)</ID>
<ID>LongMethod:PushCommentCard.kt$@Composable fun PushCommentCard( comment: String, author: String?, revision: String, pushTimestamp: Long, )</ID>
<ID>LongMethod:TreeherderApksScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun FenixInstallerApp( fenixInstallerViewModel: FenixInstallerViewModel, onNavigateUp: () -&gt; Unit, )</ID>
<ID>LongMethod:TreeherderApksScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchSection( selectedProject: String, onProjectSelected: (String) -&gt; Unit, revision: String, onRevisionChange: (String) -&gt; Unit, onSearchClick: () -&gt; Unit, isLoading: Boolean )</ID>
<ID>LongParameterList:TreeherderApksScreen.kt$( selectedProject: String, onProjectSelected: (String) -&gt; Unit, revision: String, onRevisionChange: (String) -&gt; Unit, onSearchClick: () -&gt; Unit, isLoading: Boolean )</ID>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ class ProfileScreenTest {
.fetchSemanticsNodes().isNotEmpty()
}

val timestampChips = composeTestRule
.onAllNodesWithTag("push_timestamp_chip_fakerevision123", useUnmergedTree = true)
.fetchSemanticsNodes()
assertTrue(
"Expected a push timestamp chip to be rendered for Try push entry",
timestampChips.isNotEmpty(),
)

composeTestRule.onNodeWithTag(downloadButtonInitialTag, useUnmergedTree = true)
.performClick()

Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/org/mozilla/tryfox/TryFoxViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class TryFoxViewModel(
var relevantPushAuthor by mutableStateOf<String?>(null)
private set

var relevantPushTimestamp by mutableStateOf<Long?>(null)
private set

var isLoading by mutableStateOf(false)
private set

Expand Down Expand Up @@ -161,6 +164,7 @@ class TryFoxViewModel(
revision = newRevision
relevantPushComment = null
relevantPushAuthor = null
relevantPushTimestamp = null
selectedJobs = emptyList()
isLoadingJobArtifacts.clear()
errorMessage = null
Expand Down Expand Up @@ -197,6 +201,7 @@ class TryFoxViewModel(
errorMessage = null
relevantPushComment = null
relevantPushAuthor = null
relevantPushTimestamp = null
selectedJobs = emptyList()
isLoadingJobArtifacts.clear()
cacheManager.checkCacheStatus() // Use CacheManager
Expand All @@ -216,8 +221,10 @@ class TryFoxViewModel(
}
}
relevantPushAuthor = firstPushResult.author
relevantPushTimestamp = firstPushResult.pushTimestamp
} else {
relevantPushAuthor = null
relevantPushTimestamp = null
}
relevantPushComment = foundComment

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material3.AssistChip
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
Expand All @@ -28,7 +29,17 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withLink
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.format.FormatStringsInDatetimeFormats
import kotlinx.datetime.format.byUnicodePattern
import kotlinx.datetime.toLocalDateTime
import org.mozilla.tryfox.ui.theme.TryFoxTheme
import java.util.regex.Pattern

// Helper data class to store link information
Expand All @@ -39,8 +50,14 @@ private data class LinkableSpan(
val url: String,
)

@OptIn(FormatStringsInDatetimeFormats::class)
@Composable
fun PushCommentCard(comment: String, author: String?, revision: String) { // Added revision parameter
fun PushCommentCard(
comment: String,
author: String?,
revision: String,
pushTimestamp: Long,
) {
val urlPattern = remember {
Pattern.compile(
"(https?://|www\\.)" + // Scheme or www.
Expand Down Expand Up @@ -150,6 +167,66 @@ fun PushCommentCard(comment: String, author: String?, revision: String) { // Add
},
)
}

val formattedTimestamp = remember(pushTimestamp) {
val format = LocalDateTime.Format { byUnicodePattern("yyyy-MM-dd HH:mm") }
format.format(
Instant.fromEpochSeconds(pushTimestamp)
.toLocalDateTime(TimeZone.currentSystemDefault()),
)
}
AssistChip(
onClick = { },
label = { Text(formattedTimestamp) },
leadingIcon = {
Icon(
imageVector = Icons.Filled.Schedule,
contentDescription = "Push timestamp",
)
},
modifier = Modifier.testTag("push_timestamp_chip_$revision"),
)
}
}
}

private data class PushCommentCardPreviewState(
val name: String,
val comment: String,
val author: String?,
)

private class PushCommentCardStateProvider : PreviewParameterProvider<PushCommentCardPreviewState> {
override val values: Sequence<PushCommentCardPreviewState> = sequenceOf(
PushCommentCardPreviewState(
name = "With bug and URL",
comment = "Bug 1234567 - Fix flaky test. See https://treeherder.mozilla.org/jobs for details.",
author = "developer@mozilla.com",
),
PushCommentCardPreviewState(
name = "Plain text, no author",
comment = "Try push for performance investigation on macOS.",
author = null,
),
PushCommentCardPreviewState(
name = "Multiple bugs",
comment = "Bug 1000001, Bug 1000002 - Backout for build bustage.",
author = "releng@mozilla.com",
),
)
}

@Preview(showBackground = true, widthDp = 360)
@Composable
private fun PushCommentCardPreview(
@PreviewParameter(PushCommentCardStateProvider::class) state: PushCommentCardPreviewState,
) {
TryFoxTheme {
PushCommentCard(
comment = state.comment,
author = state.author,
revision = "abc123def456",
pushTimestamp = 1_716_460_800L,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ data class PushUiModel(
val author: String,
val jobs: List<JobDetailsUiModel>,
val revision: String?,
val pushTimestamp: Long,
)
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ fun ProfileScreen(
comment = push.pushComment,
author = push.author,
revision = push.revision ?: "unknown_revision",
pushTimestamp = push.pushTimestamp,
)
push.jobs.forEach { job ->
JobCard(job = job, profileViewModel = profileViewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class ProfileViewModel(
author = pushResult.author,
jobs = jobsWithArtifacts,
revision = pushResult.revision,
pushTimestamp = pushResult.pushTimestamp,
)
} else {
logcat(LogPriority.VERBOSE, TAG) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,14 @@ fun TryFoxMainScreen(
}

tryFoxViewModel.relevantPushComment?.let { comment ->
if (comment.isNotBlank() || tryFoxViewModel.relevantPushAuthor != null) { // Show card if comment or author exists
val pushTimestamp = tryFoxViewModel.relevantPushTimestamp
if ((comment.isNotBlank() || tryFoxViewModel.relevantPushAuthor != null) && pushTimestamp != null) {
item {
PushCommentCard(
comment = comment ?: "",
comment = comment,
author = tryFoxViewModel.relevantPushAuthor,
revision = tryFoxViewModel.revision, // Added revision
revision = tryFoxViewModel.revision,
pushTimestamp = pushTimestamp,
)
}
}
Expand Down
Loading