fix(git): close Issues/PR feed top gap; add "Mine" repo feed filter

The status feed drew its filter-chip header at the top of the content area
(under the disappearing top bar) while the feed's LazyColumn separately
re-applied the full bar-height inset as content padding, leaving an empty
band above the first item. The header now consumes the scaffold top inset
itself and the inner feed renders with the top inset zeroed, matching the
Code tab's padding pattern.

Also adds a "Mine" option to the git repositories top-nav filter so the
feed can show only the logged-in user's own repositories. The feed side
already resolves TopFilter.Mine generically; this just exposes it via a
dedicated gitRepositoryRoutes catalog (kind3 + Around Me + Global + Mine).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpNmN8CvP6HnEsdTGAjVUr
This commit is contained in:
Claude
2026-06-28 23:55:35 +00:00
parent 714d202e7d
commit d6ec458117
3 changed files with 57 additions and 11 deletions
@@ -310,6 +310,24 @@ class TopNavFilterState(
)
}
private val _gitRepositoryRoutes =
combineTransform(
livePeopleListsFlow,
liveInterestFlows,
) { peopleLists, interests ->
checkNotInMainThread()
emit(
listOf(
// Git repository announcements can be narrowed by author, hashtag and geohash,
// so this mirrors the kind3 catalog plus "Mine" — the user's own repositories.
listOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow, mineFollow),
peopleLists,
interests,
listOf(muteListFollow),
).flatten().toImmutableList(),
)
}
private val _kind3GlobalPeople =
livePeopleListsFlow.transform { peopleLists ->
checkNotInMainThread()
@@ -385,6 +403,11 @@ class TopNavFilterState(
.flowOn(Dispatchers.IO)
.stateIn(scope, SharingStarted.Eagerly, persistentListOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow, mineFollow, muteListFollow))
val gitRepositoryRoutes =
_gitRepositoryRoutes
.flowOn(Dispatchers.IO)
.stateIn(scope, SharingStarted.Eagerly, persistentListOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow, mineFollow, muteListFollow))
fun destroy() {
Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" }
}
@@ -28,6 +28,8 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -43,6 +45,7 @@ import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -52,6 +55,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -62,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.nip34Git.GitRepositoryBrowserViewModel
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent
@@ -394,7 +399,23 @@ private fun StatusSplitFeed(
if (selectedLabel != null && selectedLabel !in labels) selectedLabel = null
}
Column(Modifier.fillMaxSize()) {
// The filter header is drawn statically below the disappearing top bar, so it must
// consume the scaffold's top inset itself. The inner feed then renders with the top
// inset zeroed — otherwise its LazyColumn re-applies the full bar height as content
// padding on top of the header, leaving the empty band reported above the items.
val scaffoldPadding = LocalDisappearingScaffoldPadding.current
val layoutDirection = LocalLayoutDirection.current
val feedPadding =
remember(scaffoldPadding, layoutDirection) {
PaddingValues(
start = scaffoldPadding.calculateStartPadding(layoutDirection),
top = 0.dp,
end = scaffoldPadding.calculateEndPadding(layoutDirection),
bottom = scaffoldPadding.calculateBottomPadding(),
)
}
Column(Modifier.fillMaxSize().padding(top = scaffoldPadding.calculateTopPadding())) {
Row(
modifier =
Modifier
@@ -456,15 +477,17 @@ private fun StatusSplitFeed(
}
}
RefresheableFeedView(
viewModel = if (showClosed) closedViewModel else openViewModel,
routeForLastRead = null,
accountViewModel = accountViewModel,
nav = nav,
onLoaded = { loaded, listState ->
GitItemFeedLoaded(loaded, listState, accountViewModel, nav, labelFilter = selectedLabel)
},
)
CompositionLocalProvider(LocalDisappearingScaffoldPadding provides feedPadding) {
RefresheableFeedView(
viewModel = if (showClosed) closedViewModel else openViewModel,
routeForLastRead = null,
accountViewModel = accountViewModel,
nav = nav,
onLoaded = { loaded, listState ->
GitItemFeedLoaded(loaded, listState, accountViewModel, nav, labelFilter = selectedLabel)
},
)
}
}
}
@@ -58,7 +58,7 @@ private fun GitRepositoriesTopNavFilterBar(
accountViewModel: AccountViewModel,
onChange: (FeedDefinition) -> Unit,
) {
val allLists by followListsModel.kind3GlobalPeopleRoutes.collectAsStateWithLifecycle()
val allLists by followListsModel.gitRepositoryRoutes.collectAsStateWithLifecycle()
FeedFilterSpinner(
placeholderCode = listName,