Merge remote-tracking branch 'origin/main' into eric/nova

* origin/main: (22 commits)
  basic public RSS feed for profiles (#2229)
  use `s.likeColor` everywhere (#2234)
  Add credits to localization doc (#2233)
  Fix `Logotype` fill for dark mode (#2230)
  Hide label appeal on self-labeled posts (#2232)
  Fix & Add: Japanese Translation (3) (#2226)
  tweak social card meta yet again (#2228)
  bskyweb: update golang indigo dep (from May!), and some small devex tweaks (#2227)
  Fix: Some display issues (#2219)
  Update splash screen tagline, update translations, bump ios build number
  Bump ios build number
  Tweaks (#2225)
  1.60
  Traffic reduction and tuned caching strats (#2215)
  Super secret changes don't look (#2218)
  Fix android icon dims (#2213)
  Log post creation failures (#2205)
  Some brand, some pwi (#2212)
  🤫  (#2211)
  PWI behavior updates (#2207)
  ...
This commit is contained in:
Eric Bailey
2023-12-18 16:04:43 -06:00
92 changed files with 2590 additions and 1732 deletions
+1
View File
@@ -10,6 +10,7 @@ help: ## Print info about all commands
.PHONY: build-web .PHONY: build-web
build-web: ## Compile web bundle, copy to bskyweb directory build-web: ## Compile web bundle, copy to bskyweb directory
yarn intl:build
yarn build-web yarn build-web
.PHONY: test .PHONY: test
+8 -5
View File
@@ -9,12 +9,12 @@ module.exports = function () {
/** /**
* iOS build number. Must be incremented for each TestFlight version. * iOS build number. Must be incremented for each TestFlight version.
*/ */
const IOS_BUILD_NUMBER = '2' const IOS_BUILD_NUMBER = '4'
/** /**
* Android build number. Must be incremented for each release. * Android build number. Must be incremented for each release.
*/ */
const ANDROID_VERSION_CODE = 49 const ANDROID_VERSION_CODE = 50
/** /**
* Uses built-in Expo env vars * Uses built-in Expo env vars
@@ -43,7 +43,7 @@ module.exports = function () {
icon: './assets/icon.png', icon: './assets/icon.png',
userInterfaceStyle: 'automatic', userInterfaceStyle: 'automatic',
splash: { splash: {
image: './assets/cloud-splash.png', image: './assets/splash.png',
resizeMode: 'cover', resizeMode: 'cover',
backgroundColor: '#ffffff', backgroundColor: '#ffffff',
}, },
@@ -73,9 +73,12 @@ module.exports = function () {
}, },
android: { android: {
versionCode: ANDROID_VERSION_CODE, versionCode: ANDROID_VERSION_CODE,
icon: './assets/icon.png',
adaptiveIcon: { adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png', foregroundImage: './assets/icon-android-foreground.png',
backgroundColor: '#ffffff', monochromeImage: './assets/icon-android-foreground.png',
backgroundImage: './assets/icon-android-background.png',
backgroundColor: '#1185FE',
}, },
googleServicesFile: './google-services.json', googleServicesFile: './google-services.json',
package: 'xyz.blueskyweb.app', package: 'xyz.blueskyweb.app',
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 452 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

+1 -1
View File
@@ -42,4 +42,4 @@ check: ## Compile everything, checking syntax (does not output binaries)
.PHONY: run-dev-bskyweb .PHONY: run-dev-bskyweb
run-dev-bskyweb: .env ## Runs 'bskyweb' for local dev run-dev-bskyweb: .env ## Runs 'bskyweb' for local dev
GOLOG_LOG_LEVEL=info go run ./cmd/bskyweb serve --debug GOLOG_LOG_LEVEL=info go run ./cmd/bskyweb serve
+99
View File
@@ -0,0 +1,99 @@
package main
import (
"fmt"
"net/http"
appbsky "github.com/bluesky-social/indigo/api/bsky"
"github.com/bluesky-social/indigo/atproto/syntax"
"github.com/labstack/echo/v4"
)
// We don't actually populate the title for "posts".
// Some background: https://book.micro.blog/rss-for-microblogs/
type Item struct {
Title string `xml:"title,omitempty"`
Link string `xml:"link,omitempty"`
Description string `xml:"description,omitempty"`
PubDate string `xml:"pubDate,omitempty"`
Author string `xml:"author,omitempty"`
GUID string `xml:"guid,omitempty"`
}
type rss struct {
Version string `xml:"version,attr"`
Description string `xml:"channel>description,omitempty"`
Link string `xml:"channel>link"`
Title string `xml:"channel>title"`
Item []Item `xml:"channel>item"`
}
func (srv *Server) WebProfileRSS(c echo.Context) error {
ctx := c.Request().Context()
didParam := c.Param("did")
did, err := syntax.ParseDID(didParam)
if err != nil {
return echo.NewHTTPError(400, fmt.Sprintf("not a valid DID: %s", didParam))
}
// check that public view is Ok
pv, err := appbsky.ActorGetProfile(ctx, srv.xrpcc, did.String())
if err != nil {
return echo.NewHTTPError(404, fmt.Sprintf("account not found: %s", did))
}
for _, label := range pv.Labels {
if label.Src == pv.Did && label.Val == "!no-unauthenticated" {
return echo.NewHTTPError(403, fmt.Sprintf("account does not allow public views: %s", did))
}
}
af, err := appbsky.FeedGetAuthorFeed(ctx, srv.xrpcc, did.String(), "", "", 30)
if err != nil {
log.Warn("failed to fetch author feed", "did", did, "err", err)
return err
}
posts := []Item{}
for _, p := range af.Feed {
// only include author's own posts in RSS
if p.Post.Author.Did != pv.Did {
continue
}
aturi, err := syntax.ParseATURI(p.Post.Uri)
if err != nil {
return err
}
rec := p.Post.Record.Val.(*appbsky.FeedPost)
// only top-level posts in RSS (no replies)
if rec.Reply != nil {
continue
}
posts = append(posts, Item{
Link: fmt.Sprintf("https://bsky.app/profile/%s/post/%s", pv.Handle, aturi.RecordKey().String()),
Description: rec.Text,
PubDate: rec.CreatedAt,
Author: "@" + pv.Handle,
GUID: aturi.String(),
})
}
title := "@" + pv.Handle
if pv.DisplayName != nil {
title = title + " - " + *pv.DisplayName
}
desc := ""
if pv.Description != nil {
desc = *pv.Description
}
feed := &rss{
Version: "2.0",
Description: desc,
Link: fmt.Sprintf("https://bsky.app/profile/%s", pv.Handle),
Title: title,
Item: posts,
}
return c.XML(http.StatusOK, feed)
}
+45 -27
View File
@@ -15,7 +15,8 @@ import (
"time" "time"
appbsky "github.com/bluesky-social/indigo/api/bsky" appbsky "github.com/bluesky-social/indigo/api/bsky"
cliutil "github.com/bluesky-social/indigo/cmd/gosky/util" "github.com/bluesky-social/indigo/atproto/syntax"
"github.com/bluesky-social/indigo/util/cliutil"
"github.com/bluesky-social/indigo/xrpc" "github.com/bluesky-social/indigo/xrpc"
"github.com/bluesky-social/social-app/bskyweb" "github.com/bluesky-social/social-app/bskyweb"
@@ -208,6 +209,9 @@ func serve(cctx *cli.Context) error {
e.GET("/profile/:handle/feed/:rkey", server.WebGeneric) e.GET("/profile/:handle/feed/:rkey", server.WebGeneric)
e.GET("/profile/:handle/feed/:rkey/liked-by", server.WebGeneric) e.GET("/profile/:handle/feed/:rkey/liked-by", server.WebGeneric)
// profile RSS feed (DID not handle)
e.GET("/profile/:did/rss", server.WebProfileRSS)
// post endpoints; only first populates info // post endpoints; only first populates info
e.GET("/profile/:handle/post/:rkey", server.WebPost) e.GET("/profile/:handle/post/:rkey", server.WebPost)
e.GET("/profile/:handle/post/:rkey/liked-by", server.WebGeneric) e.GET("/profile/:handle/post/:rkey/liked-by", server.WebGeneric)
@@ -285,17 +289,28 @@ func (srv *Server) WebHome(c echo.Context) error {
} }
func (srv *Server) WebPost(c echo.Context) error { func (srv *Server) WebPost(c echo.Context) error {
data := pongo2.Context{}
handle := c.Param("handle")
rkey := c.Param("rkey")
// sanity check argument
if len(handle) > 4 && len(handle) < 128 && len(rkey) > 0 {
ctx := c.Request().Context() ctx := c.Request().Context()
data := pongo2.Context{}
// sanity check arguments. don't 4xx, just let app handle if not expected format
rkeyParam := c.Param("rkey")
rkey, err := syntax.ParseRecordKey(rkeyParam)
if err != nil {
return c.Render(http.StatusOK, "post.html", data)
}
handleParam := c.Param("handle")
handle, err := syntax.ParseHandle(handleParam)
if err != nil {
return c.Render(http.StatusOK, "post.html", data)
}
handle = handle.Normalize()
// requires two fetches: first fetch profile (!) // requires two fetches: first fetch profile (!)
pv, err := appbsky.ActorGetProfile(ctx, srv.xrpcc, handle) pv, err := appbsky.ActorGetProfile(ctx, srv.xrpcc, handle.String())
if err != nil { if err != nil {
log.Warnf("failed to fetch handle: %s\t%v", handle, err) log.Warnf("failed to fetch handle: %s\t%v", handle, err)
} else { return c.Render(http.StatusOK, "post.html", data)
}
unauthedViewingOkay := true unauthedViewingOkay := true
for _, label := range pv.Labels { for _, label := range pv.Labels {
if label.Src == pv.Did && label.Val == "!no-unauthenticated" { if label.Src == pv.Did && label.Val == "!no-unauthenticated" {
@@ -303,16 +318,19 @@ func (srv *Server) WebPost(c echo.Context) error {
} }
} }
if unauthedViewingOkay { if !unauthedViewingOkay {
return c.Render(http.StatusOK, "post.html", data)
}
did := pv.Did did := pv.Did
data["did"] = did data["did"] = did
// then fetch the post thread (with extra context) // then fetch the post thread (with extra context)
uri := fmt.Sprintf("at://%s/app.bsky.feed.post/%s", did, rkey) uri := fmt.Sprintf("at://%s/app.bsky.feed.post/%s", did, rkey)
tpv, err := appbsky.FeedGetPostThread(ctx, srv.xrpcc, 1, uri) tpv, err := appbsky.FeedGetPostThread(ctx, srv.xrpcc, 1, 0, uri)
if err != nil { if err != nil {
log.Warnf("failed to fetch post: %s\t%v", uri, err) log.Warnf("failed to fetch post: %s\t%v", uri, err)
} else { return c.Render(http.StatusOK, "post.html", data)
}
req := c.Request() req := c.Request()
postView := tpv.Thread.FeedDefs_ThreadViewPost.Post postView := tpv.Thread.FeedDefs_ThreadViewPost.Post
data["postView"] = postView data["postView"] = postView
@@ -320,38 +338,38 @@ func (srv *Server) WebPost(c echo.Context) error {
if postView.Embed != nil && postView.Embed.EmbedImages_View != nil { if postView.Embed != nil && postView.Embed.EmbedImages_View != nil {
data["imgThumbUrl"] = postView.Embed.EmbedImages_View.Images[0].Thumb data["imgThumbUrl"] = postView.Embed.EmbedImages_View.Images[0].Thumb
} }
}
}
}
}
return c.Render(http.StatusOK, "post.html", data) return c.Render(http.StatusOK, "post.html", data)
} }
func (srv *Server) WebProfile(c echo.Context) error { func (srv *Server) WebProfile(c echo.Context) error {
data := pongo2.Context{}
handle := c.Param("handle")
// sanity check argument
if len(handle) > 4 && len(handle) < 128 {
ctx := c.Request().Context() ctx := c.Request().Context()
pv, err := appbsky.ActorGetProfile(ctx, srv.xrpcc, handle) data := pongo2.Context{}
// sanity check arguments. don't 4xx, just let app handle if not expected format
handleParam := c.Param("handle")
handle, err := syntax.ParseHandle(handleParam)
if err != nil {
return c.Render(http.StatusOK, "profile.html", data)
}
handle = handle.Normalize()
pv, err := appbsky.ActorGetProfile(ctx, srv.xrpcc, handle.String())
if err != nil { if err != nil {
log.Warnf("failed to fetch handle: %s\t%v", handle, err) log.Warnf("failed to fetch handle: %s\t%v", handle, err)
} else { return c.Render(http.StatusOK, "profile.html", data)
}
unauthedViewingOkay := true unauthedViewingOkay := true
for _, label := range pv.Labels { for _, label := range pv.Labels {
if label.Src == pv.Did && label.Val == "!no-unauthenticated" { if label.Src == pv.Did && label.Val == "!no-unauthenticated" {
unauthedViewingOkay = false unauthedViewingOkay = false
} }
} }
if unauthedViewingOkay { if !unauthedViewingOkay {
return c.Render(http.StatusOK, "profile.html", data)
}
req := c.Request() req := c.Request()
data["profileView"] = pv data["profileView"] = pv
data["requestURI"] = fmt.Sprintf("https://%s%s", req.Host, req.URL.Path) data["requestURI"] = fmt.Sprintf("https://%s%s", req.Host, req.URL.Path)
}
}
}
return c.Render(http.StatusOK, "profile.html", data) return c.Render(http.StatusOK, "profile.html", data)
} }
+1 -1
View File
@@ -1,2 +1,2 @@
GOLOG_LOG_LEVEL=info GOLOG_LOG_LEVEL=info
ATP_APPVIEW_HOST=https://api.bsky.app ATP_APPVIEW_HOST=https://public.api.bsky.app
+55 -39
View File
@@ -3,88 +3,104 @@ module github.com/bluesky-social/social-app/bskyweb
go 1.21 go 1.21
require ( require (
github.com/bluesky-social/indigo v0.0.0-20230504025040-8915cccc3319 github.com/bluesky-social/indigo v0.0.0-20231216010655-ad730a7da4f5
github.com/flosch/pongo2/v6 v6.0.0 github.com/flosch/pongo2/v6 v6.0.0
github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-log v1.0.5
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.16.5 github.com/klauspost/compress v1.17.3
github.com/labstack/echo/v4 v4.10.2 github.com/labstack/echo/v4 v4.11.3
github.com/urfave/cli/v2 v2.25.3 github.com/urfave/cli/v2 v2.25.7
) )
require ( require (
github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/carlmjohnson/versioninfo v0.22.5 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.4.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/arc/v2 v2.0.6 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/go-block-format v0.1.2 // indirect github.com/ipfs/go-block-format v0.2.0 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect
github.com/ipfs/go-ipfs-blockstore v1.3.0 // indirect github.com/ipfs/go-ipfs-blockstore v1.3.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.2 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect
github.com/ipfs/go-ipld-cbor v0.0.7-0.20230126201833-a73d038d90bc // indirect github.com/ipfs/go-ipld-cbor v0.1.0 // indirect
github.com/ipfs/go-ipld-format v0.4.0 // indirect github.com/ipfs/go-ipld-format v0.6.0 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jackc/pgx/v5 v5.5.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/labstack/gommon v0.4.0 // indirect github.com/labstack/gommon v0.4.1 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.0.9 // indirect github.com/lestrrat-go/jwx/v2 v2.0.12 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/mattn/go-sqlite3 v1.14.18 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multihash v0.2.1 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiformats/go-varint v0.0.7 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20230418232409-daab9ece03a0 // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20230923211252-36a87e1ba72f // indirect
github.com/whyrusleeping/go-did v0.0.0-20230301193428-2146016fc220 // indirect github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opentelemetry.io/otel v1.15.1 // indirect gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
go.opentelemetry.io/otel/trace v1.15.1 // indirect gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.8.0 // indirect golang.org/x/crypto v0.15.0 // indirect
golang.org/x/net v0.9.0 // indirect golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.7.0 // indirect golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gorm.io/driver/postgres v1.5.0 // indirect gorm.io/driver/postgres v1.5.0 // indirect
gorm.io/driver/sqlite v1.5.0 // indirect gorm.io/driver/sqlite v1.5.4 // indirect
gorm.io/gorm v1.25.0 // indirect gorm.io/gorm v1.25.5 // indirect
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.2.1 // indirect
) )
+132 -116
View File
@@ -1,25 +1,30 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluesky-social/indigo v0.0.0-20230504025040-8915cccc3319 h1:VCNXRXpgyK3xkaQ8fzL5WzswerwLycke4B9ggLs1uOA= github.com/bluesky-social/indigo v0.0.0-20231216010655-ad730a7da4f5 h1:Zk1c+mxCYH6G/vLL0+9lO2Eci4OT3AFy73qPWa9auDM=
github.com/bluesky-social/indigo v0.0.0-20230504025040-8915cccc3319/go.mod h1:Hc09SUJXAIujaAvq7JXxi8ZQQI887grzPkHgn4JyE1Q= github.com/bluesky-social/indigo v0.0.0-20231216010655-ad730a7da4f5/go.mod h1:a8cPbqDkRX+aPwJnXF7kAi3PF26hYiR4w5H8624MB7k=
github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU= github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU=
github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU= github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
@@ -29,53 +34,49 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/arc/v2 v2.0.6 h1:4NU7uP5vSoK6TbaMj3NtY478TTAWLso/vL1gpNrInHg=
github.com/hashicorp/golang-lru/arc/v2 v2.0.6/go.mod h1:cfdDIX05DWvYV6/shsxDfa/OVcRieOt+q4FnM8x+Xno=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12XwJyvYvMM= github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw=
github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo=
github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0=
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs=
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs=
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk=
github.com/ipfs/go-ipld-cbor v0.0.7-0.20230126201833-a73d038d90bc h1:eUEo764smNy0EVRuMTSmirmuh552Mf2aBjfpDcLnDa8= github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U=
github.com/ipfs/go-ipld-cbor v0.0.7-0.20230126201833-a73d038d90bc/go.mod h1:X7SgEIwC4COC5OWfcepZBWafO5kA1Rmt9ZsLLbhihQk= github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg=
github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ=
github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM=
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
@@ -83,16 +84,16 @@ github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c=
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
@@ -106,25 +107,23 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
@@ -133,26 +132,25 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.0.9 h1:TRX4Q630UXxPVLvP5vGaqVJO7S+0PE6msRZUsFSBoC8= github.com/lestrrat-go/jwx/v2 v2.0.12 h1:3d589+5w/b9b7S3DneICPW16AqTyYXB7VRjgluSDWeA=
github.com/lestrrat-go/jwx/v2 v2.0.9/go.mod h1:K68euYaR95FnL0hIQB8VvzL70vB7pSifbJUydCTPmgM= github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G/0y2qUjAQuQ=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
@@ -165,32 +163,39 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
@@ -209,39 +214,46 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/cbor-gen v0.0.0-20230418232409-daab9ece03a0 h1:XYEgH2nJgsrcrj32p+SAbx6T3s/6QknOXezXtz7kzbg= github.com/whyrusleeping/cbor-gen v0.0.0-20230923211252-36a87e1ba72f h1:SBuSxXJL0/ZJMtTxbXZgHZkThl9dNrzyaNhlyaqscRo=
github.com/whyrusleeping/cbor-gen v0.0.0-20230418232409-daab9ece03a0/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20230923211252-36a87e1ba72f/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
github.com/whyrusleeping/go-did v0.0.0-20230301193428-2146016fc220 h1:EO/9z3yDvx1van1/0esdcqhalZZQGRj3I1BPTWr5k3A= github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 h1:yJ9/LwIGIk/c0CdoavpC9RNSGSruIspSZtxG3Nnldic=
github.com/whyrusleeping/go-did v0.0.0-20230301193428-2146016fc220/go.mod h1:qPtRyexGM5XMHFIfjH+EiA/A/1n2JakWEdMPC53pJAE= github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6/go.mod h1:39U9RRVr4CKbXpXYopWn+FSH5s+vWu6+RmguSPWAq5s=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -249,9 +261,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -259,9 +270,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -278,17 +289,18 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -296,27 +308,29 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -335,11 +349,13 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -351,11 +367,11 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c= gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I= gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+1
View File
@@ -8,6 +8,7 @@
<meta property="og:title" content="Bluesky Social"> <meta property="og:title" content="Bluesky Social">
<meta property="og:description" content="See what's next."> <meta property="og:description" content="See what's next.">
<meta property="og:image" content="/static/social-card-default.png"> <meta property="og:image" content="/static/social-card-default.png">
<meta property="og:site_name" content="Bluesky Social">
<meta name="twitter:card" content="summary"> <meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@bluesky"> <meta name="twitter:site" content="@bluesky">
{%- endblock %} {%- endblock %}
+7 -3
View File
@@ -10,8 +10,9 @@
{% block html_head_extra -%} {% block html_head_extra -%}
{%- if postView -%} {%- if postView -%}
<meta property="og:type" content="website">
<meta property="og:site_name" content="Bluesky Social"> <meta property="og:site_name" content="Bluesky Social">
<meta property="og:type" content="article">
<meta property="profile:username" content="{{ profileView.Handle }}">
{%- if requestURI %} {%- if requestURI %}
<meta property="og:url" content="{{ requestURI }}"> <meta property="og:url" content="{{ requestURI }}">
{% endif -%} {% endif -%}
@@ -32,17 +33,20 @@
<meta name="twitter:card" content="summary"> <meta name="twitter:card" content="summary">
{% endif %} {% endif %}
<meta name="twitter:label1" content="Posted At"> <meta name="twitter:label1" content="Posted At">
<meta name="twitter:value1" content="{{ postView.CreatedAt }}"> <meta name="twitter:value1" content="{{ postView.IndexedAt }}">
<meta name="twitter:site" content="@bluesky"> <meta name="article:published_time" content="{{ postView.IndexedAt }}">
{% endif -%} {% endif -%}
{%- endblock %} {%- endblock %}
{% block noscript_extra -%} {% block noscript_extra -%}
{%- if postView -%}
<div id="bsky_post_summary"> <div id="bsky_post_summary">
<h3>Post</h3> <h3>Post</h3>
<p id="bsky_display_name">{{ postView.Author.DisplayName }}</p> <p id="bsky_display_name">{{ postView.Author.DisplayName }}</p>
<p id="bsky_handle">{{ postView.Author.Handle }}</p> <p id="bsky_handle">{{ postView.Author.Handle }}</p>
<p id="bsky_did">{{ postView.Author.Did }}</p> <p id="bsky_did">{{ postView.Author.Did }}</p>
<p id="bsky_post_text">{{ postView.Record.Val.Text }}</p> <p id="bsky_post_text">{{ postView.Record.Val.Text }}</p>
<p id="bsky_post_indexedat">{{ postView.IndexedAt }}</p>
</div> </div>
{% endif -%}
{%- endblock %} {%- endblock %}
+5 -2
View File
@@ -10,8 +10,9 @@
{% block html_head_extra -%} {% block html_head_extra -%}
{%- if profileView -%} {%- if profileView -%}
<meta property="og:type" content="website">
<meta property="og:site_name" content="Bluesky Social"> <meta property="og:site_name" content="Bluesky Social">
<meta property="og:type" content="profile">
<meta property="profile:username" content="{{ profileView.Handle }}">
{%- if requestURI %} {%- if requestURI %}
<meta property="og:url" content="{{ requestURI }}"> <meta property="og:url" content="{{ requestURI }}">
{% endif -%} {% endif -%}
@@ -33,11 +34,12 @@
{% endif %} {% endif %}
<meta name="twitter:label1" content="Account DID"> <meta name="twitter:label1" content="Account DID">
<meta name="twitter:value1" content="{{ profileView.Did }}"> <meta name="twitter:value1" content="{{ profileView.Did }}">
<meta name="twitter:site" content="@bluesky"> <link rel="alternate" type="application/rss+xml" href="/profile/{{ profileView.Did }}/rss">
{% endif -%} {% endif -%}
{%- endblock %} {%- endblock %}
{% block noscript_extra -%} {% block noscript_extra -%}
{%- if profileView -%}
<div id="bsky_profile_summary"> <div id="bsky_profile_summary">
<h3>Profile</h3> <h3>Profile</h3>
<p id="bsky_display_name">{{ profileView.DisplayName }}</p> <p id="bsky_display_name">{{ profileView.DisplayName }}</p>
@@ -45,4 +47,5 @@
<p id="bsky_did">{{ profileView.Did }}</p> <p id="bsky_did">{{ profileView.Did }}</p>
<p id="bsky_profile_description">{{ profileView.Description }}</p> <p id="bsky_profile_description">{{ profileView.Description }}</p>
</div> </div>
{% endif -%}
{%- endblock %} {%- endblock %}
+1
View File
@@ -10,6 +10,7 @@
- After initial setup: - After initial setup:
- Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required) - Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required)
- `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change - `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change
- `yarn intl:build` -> you will also need to run this anytime `./src/locale/{locale}/messages.po` change
- Start the dev servers - Start the dev servers
- `git clone git@github.com:bluesky-social/atproto.git` - `git clone git@github.com:bluesky-social/atproto.git`
- `cd atproto` - `cd atproto`
@@ -111,3 +111,9 @@ export function Welcome() {
return <div>{welcome}</div>; return <div>{welcome}</div>;
} }
``` ```
### Credits
Please check each individual `messages.po` file for the credits of the translators. We are very grateful for their help!
If you would like to translate the Bluesky app into your language, please open a PR or issue on this repo.
+1 -1
View File
@@ -78,7 +78,7 @@ export async function createServer(
}) })
const pic = fs.readFileSync( const pic = fs.readFileSync(
path.join(__dirname, '..', 'assets', 'default-avatar.jpg'), path.join(__dirname, '..', 'assets', 'default-avatar.png'),
) )
return { return {
+3 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "bsky.app", "name": "bsky.app",
"version": "1.59.0", "version": "1.60.0",
"private": true, "private": true,
"scripts": { "scripts": {
"prepare": "is-ci || husky install", "prepare": "is-ci || husky install",
@@ -35,7 +35,7 @@
"intl:compile": "lingui compile" "intl:compile": "lingui compile"
}, },
"dependencies": { "dependencies": {
"@atproto/api": "^0.7.3", "@atproto/api": "^0.7.4",
"@bam.tech/react-native-image-resizer": "^3.0.4", "@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2", "@braintree/sanitize-url": "^6.0.2",
"@emoji-mart/react": "^1.1.1", "@emoji-mart/react": "^1.1.1",
@@ -54,6 +54,7 @@
"@react-native-clipboard/clipboard": "^1.10.0", "@react-native-clipboard/clipboard": "^1.10.0",
"@react-native-community/blur": "^4.3.0", "@react-native-community/blur": "^4.3.0",
"@react-native-community/datetimepicker": "7.2.0", "@react-native-community/datetimepicker": "7.2.0",
"@react-native-masked-view/masked-view": "^0.3.1",
"@react-native-menu/menu": "^0.8.0", "@react-native-menu/menu": "^0.8.0",
"@react-native-picker/picker": "2.4.10", "@react-native-picker/picker": "2.4.10",
"@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/bottom-tabs": "^6.5.7",
+9 -3
View File
@@ -6,6 +6,10 @@ import {RootSiblingParent} from 'react-native-root-siblings'
import * as SplashScreen from 'expo-splash-screen' import * as SplashScreen from 'expo-splash-screen'
import {GestureHandlerRootView} from 'react-native-gesture-handler' import {GestureHandlerRootView} from 'react-native-gesture-handler'
import {QueryClientProvider} from '@tanstack/react-query' import {QueryClientProvider} from '@tanstack/react-query'
import {
SafeAreaProvider,
initialWindowMetrics,
} from 'react-native-safe-area-context'
import 'view/icons' import 'view/icons'
@@ -34,6 +38,7 @@ import {
} from 'state/session' } from 'state/session'
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread' import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
import {Splash} from '#/Splash'
SplashScreen.preventAutoHideAsync() SplashScreen.preventAutoHideAsync()
@@ -53,10 +58,9 @@ function InnerApp() {
resumeSession(account) resumeSession(account)
}, [resumeSession]) }, [resumeSession])
// wait for session to resume
if (isInitialLoad) return null
return ( return (
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<Splash isReady={!isInitialLoad}>
<React.Fragment <React.Fragment
// Resets the entire tree below when it changes: // Resets the entire tree below when it changes:
key={currentAccount?.did}> key={currentAccount?.did}>
@@ -74,6 +78,8 @@ function InnerApp() {
</UnreadNotifsProvider> </UnreadNotifsProvider>
</LoggedOutViewProvider> </LoggedOutViewProvider>
</React.Fragment> </React.Fragment>
</Splash>
</SafeAreaProvider>
) )
} }
+13 -7
View File
@@ -1,6 +1,5 @@
import * as React from 'react' import * as React from 'react'
import {StyleSheet} from 'react-native' import {StyleSheet} from 'react-native'
import * as SplashScreen from 'expo-splash-screen'
import { import {
NavigationContainer, NavigationContainer,
createNavigationContainerRef, createNavigationContainerRef,
@@ -182,7 +181,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
<Stack.Screen <Stack.Screen
name="ProfileFeed" name="ProfileFeed"
getComponent={() => ProfileFeedScreen} getComponent={() => ProfileFeedScreen}
options={{title: title('Feed')}} options={{title: title('Feed'), requireAuth: true}}
/> />
<Stack.Screen <Stack.Screen
name="ProfileFeedLikedBy" name="ProfileFeedLikedBy"
@@ -293,7 +292,11 @@ function HomeTabNavigator() {
animationDuration: 250, animationDuration: 250,
contentStyle, contentStyle,
}}> }}>
<HomeTab.Screen name="Home" getComponent={() => HomeScreen} /> <HomeTab.Screen
name="Home"
getComponent={() => HomeScreen}
options={{requireAuth: true}}
/>
{commonScreens(HomeTab)} {commonScreens(HomeTab)}
</HomeTab.Navigator> </HomeTab.Navigator>
) )
@@ -327,7 +330,11 @@ function FeedsTabNavigator() {
animationDuration: 250, animationDuration: 250,
contentStyle, contentStyle,
}}> }}>
<FeedsTab.Screen name="Feeds" getComponent={() => FeedsScreen} /> <FeedsTab.Screen
name="Feeds"
getComponent={() => FeedsScreen}
options={{requireAuth: true}}
/>
{commonScreens(FeedsTab as typeof HomeTab)} {commonScreens(FeedsTab as typeof HomeTab)}
</FeedsTab.Navigator> </FeedsTab.Navigator>
) )
@@ -399,7 +406,7 @@ const FlatNavigator = () => {
<Flat.Screen <Flat.Screen
name="Home" name="Home"
getComponent={() => HomeScreen} getComponent={() => HomeScreen}
options={{title: title('Home')}} options={{title: title('Home'), requireAuth: true}}
/> />
<Flat.Screen <Flat.Screen
name="Search" name="Search"
@@ -409,7 +416,7 @@ const FlatNavigator = () => {
<Flat.Screen <Flat.Screen
name="Feeds" name="Feeds"
getComponent={() => FeedsScreen} getComponent={() => FeedsScreen}
options={{title: title('Feeds')}} options={{title: title('Feeds'), requireAuth: true}}
/> />
<Flat.Screen <Flat.Screen
name="Notifications" name="Notifications"
@@ -489,7 +496,6 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
linking={LINKING} linking={LINKING}
theme={theme} theme={theme}
onReady={() => { onReady={() => {
SplashScreen.hideAsync()
logModuleInitTime() logModuleInitTime()
onReady() onReady()
}}> }}>
+164
View File
@@ -0,0 +1,164 @@
import React, {useCallback, useEffect} from 'react'
import {View, StyleSheet, Image as RNImage} from 'react-native'
import * as SplashScreen from 'expo-splash-screen'
import {Image} from 'expo-image'
import Animated, {
interpolate,
runOnJS,
useAnimatedStyle,
useSharedValue,
withTiming,
Easing,
} from 'react-native-reanimated'
import MaskedView from '@react-native-masked-view/masked-view'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import Svg, {Path, SvgProps} from 'react-native-svg'
// @ts-ignore
import splashImagePointer from '../assets/splash.png'
const splashImageUri = RNImage.resolveAssetSource(splashImagePointer).uri
export const Logo = React.forwardRef(function LogoImpl(props: SvgProps, ref) {
const width = 1000
const height = width * (67 / 64)
return (
<Svg
fill="none"
// @ts-ignore it's fiiiiine
ref={ref}
viewBox="0 0 64 66"
style={{width, height}}>
<Path
fill="#fff"
d="M13.873 3.77C21.21 9.243 29.103 20.342 32 26.3v15.732c0-.335-.13.043-.41.858-1.512 4.414-7.418 21.642-20.923 7.87-7.111-7.252-3.819-14.503 9.125-16.692-7.405 1.252-15.73-.817-18.014-8.93C1.12 22.804 0 8.431 0 6.488 0-3.237 8.579-.18 13.873 3.77ZM50.127 3.77C42.79 9.243 34.897 20.342 32 26.3v15.732c0-.335.13.043.41.858 1.512 4.414 7.418 21.642 20.923 7.87 7.111-7.252 3.819-14.503-9.125-16.692 7.405 1.252 15.73-.817 18.014-8.93C62.88 22.804 64 8.431 64 6.488 64-3.237 55.422-.18 50.127 3.77Z"
/>
</Svg>
)
})
type Props = {
isReady: boolean
}
SplashScreen.preventAutoHideAsync().catch(() => {})
const AnimatedLogo = Animated.createAnimatedComponent(Logo)
export function Splash(props: React.PropsWithChildren<Props>) {
const insets = useSafeAreaInsets()
const intro = useSharedValue(0)
const outroLogo = useSharedValue(0)
const outroApp = useSharedValue(0)
const [isAnimationComplete, setIsAnimationComplete] = React.useState(false)
const [isImageLoaded, setIsImageLoaded] = React.useState(false)
const isReady = props.isReady && isImageLoaded
const logoAnimations = useAnimatedStyle(() => {
return {
transform: [
{
scale: interpolate(intro.value, [0, 1], [0.8, 1], 'clamp'),
},
{
scale: interpolate(
outroLogo.value,
[0, 0.06, 0.08, 1],
[1, 0.8, 0.8, 400],
'clamp',
),
},
],
opacity: interpolate(intro.value, [0, 1], [0, 1], 'clamp'),
}
})
const appAnimation = useAnimatedStyle(() => {
return {
transform: [
{
scale: interpolate(outroApp.value, [0, 1], [1.1, 1], 'clamp'),
},
],
opacity: interpolate(outroApp.value, [0, 0.9, 1], [0, 1, 1], 'clamp'),
}
})
const onFinish = useCallback(() => setIsAnimationComplete(true), [])
useEffect(() => {
if (isReady) {
// hide on mount
SplashScreen.hideAsync().catch(() => {})
intro.value = withTiming(
1,
{duration: 200, easing: Easing.out(Easing.cubic)},
async () => {
// set these values to check animation at specific point
// outroLogo.value = 0.1
// outroApp.value = 0.1
outroLogo.value = withTiming(
1,
{duration: 1000, easing: Easing.in(Easing.cubic)},
() => {
runOnJS(onFinish)()
},
)
outroApp.value = withTiming(
1,
{duration: 1000, easing: Easing.inOut(Easing.cubic)},
() => {
runOnJS(onFinish)()
},
)
},
)
}
}, [onFinish, intro, outroLogo, outroApp, isReady])
const onLoadEnd = useCallback(() => {
setIsImageLoaded(true)
}, [setIsImageLoaded])
return (
<View style={{flex: 1}}>
{!isAnimationComplete && (
<Image
accessibilityIgnoresInvertColors
onLoadEnd={onLoadEnd}
source={{uri: splashImageUri}}
style={StyleSheet.absoluteFillObject}
/>
)}
<MaskedView
style={[StyleSheet.absoluteFillObject]}
maskElement={
<Animated.View
style={[
StyleSheet.absoluteFillObject,
{
// Transparent background because mask is based off alpha channel.
backgroundColor: 'transparent',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
transform: [{translateY: -(insets.top / 2)}, {scale: 0.1}], // scale from 1000px to 100px
},
]}>
<AnimatedLogo style={[logoAnimations]} />
</Animated.View>
}>
{!isAnimationComplete && (
<View
style={[StyleSheet.absoluteFillObject, {backgroundColor: 'white'}]}
/>
)}
<Animated.View style={[{flex: 1}, appAnimation]}>
{props.children}
</Animated.View>
</MaskedView>
</View>
)
}
+35
View File
@@ -0,0 +1,35 @@
import React, {createContext, useContext, useMemo} from 'react'
import {ScrollHandlers} from 'react-native-reanimated'
const ScrollContext = createContext<ScrollHandlers<any>>({
onBeginDrag: undefined,
onEndDrag: undefined,
onScroll: undefined,
})
export function useScrollHandlers(): ScrollHandlers<any> {
return useContext(ScrollContext)
}
type ProviderProps = {children: React.ReactNode} & ScrollHandlers<any>
// Note: this completely *overrides* the parent handlers.
// It's up to you to compose them with the parent ones via useScrollHandlers() if needed.
export function ScrollProvider({
children,
onBeginDrag,
onEndDrag,
onScroll,
}: ProviderProps) {
const handlers = useMemo(
() => ({
onBeginDrag,
onEndDrag,
onScroll,
}),
[onBeginDrag, onEndDrag, onScroll],
)
return (
<ScrollContext.Provider value={handlers}>{children}</ScrollContext.Provider>
)
}
+6
View File
@@ -104,12 +104,18 @@ export async function post(agent: BskyAgent, opts: PostOpts) {
// add image embed if present // add image embed if present
if (opts.images?.length) { if (opts.images?.length) {
logger.info(`Uploading images`, {
count: opts.images.length,
})
const images: AppBskyEmbedImages.Image[] = [] const images: AppBskyEmbedImages.Image[] = []
for (const image of opts.images) { for (const image of opts.images) {
opts.onStateChange?.(`Uploading image #${images.length + 1}...`) opts.onStateChange?.(`Uploading image #${images.length + 1}...`)
logger.info(`Compressing image`)
await image.compress() await image.compress()
const path = image.compressed?.path ?? image.path const path = image.compressed?.path ?? image.path
const {width, height} = image.compressed || image const {width, height} = image.compressed || image
logger.info(`Uploading image`)
const res = await uploadBlob(agent, path, 'image/jpeg') const res = await uploadBlob(agent, path, 'image/jpeg')
images.push({ images.push({
image: res.data.blob, image: res.data.blob,
+2 -3
View File
@@ -1,5 +1,4 @@
import {ImageRequireSource} from 'react-native' import {ImageRequireSource} from 'react-native'
export const DEF_AVATAR: ImageRequireSource = require('../../assets/default-avatar.jpg') export const DEF_AVATAR: ImageRequireSource = require('../../assets/default-avatar.png')
export const TABS_EXPLAINER: ImageRequireSource = require('../../assets/tabs-explainer.jpg') export const CLOUD_SPLASH: ImageRequireSource = require('../../assets/splash.png')
export const CLOUD_SPLASH: ImageRequireSource = require('../../assets/cloud-splash.png')
+2 -6
View File
@@ -1,10 +1,6 @@
import {ImageRequireSource} from 'react-native' import {ImageRequireSource} from 'react-native'
// @ts-ignore we need to pretend -prf // @ts-ignore we need to pretend -prf
export const DEF_AVATAR: ImageRequireSource = {uri: '/img/default-avatar.jpg'} export const DEF_AVATAR: ImageRequireSource = {uri: '/img/default-avatar.png'}
// @ts-ignore we need to pretend -prf // @ts-ignore we need to pretend -prf
export const TABS_EXPLAINER: ImageRequireSource = { export const CLOUD_SPLASH: ImageRequireSource = {uri: '/img/splash.png'}
uri: '/img/tabs-explainer.jpg',
}
// @ts-ignore we need to pretend -prf
export const CLOUD_SPLASH: ImageRequireSource = {uri: '/img/cloud-splash.png'}
+1 -1
View File
@@ -1,2 +1,2 @@
export const LOGIN_INCLUDE_DEV_SERVERS = true export const LOGIN_INCLUDE_DEV_SERVERS = true
export const PWI_ENABLED = false export const PWI_ENABLED = true
+181 -127
View File
@@ -47,7 +47,7 @@ msgstr ""
msgid "{invitesAvailable} invite codes available" msgid "{invitesAvailable} invite codes available"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:87 #: src/view/screens/Search/Search.tsx:88
msgid "{message}" msgid "{message}"
msgstr "" msgstr ""
@@ -95,7 +95,7 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:193 #: src/view/com/modals/UserAddRemoveLists.tsx:193
#: src/view/screens/ProfileList.tsx:783 #: src/view/screens/ProfileList.tsx:754
msgid "Add" msgid "Add"
msgstr "" msgstr ""
@@ -103,7 +103,7 @@ msgstr ""
msgid "Add a content warning" msgid "Add a content warning"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:773 #: src/view/screens/ProfileList.tsx:744
msgid "Add a user to this list" msgid "Add a user to this list"
msgstr "" msgstr ""
@@ -126,11 +126,11 @@ msgstr ""
msgid "Add details to report" msgid "Add details to report"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:432 #: src/view/com/composer/Composer.tsx:438
msgid "Add link card" msgid "Add link card"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:435 #: src/view/com/composer/Composer.tsx:441
msgid "Add link card:" msgid "Add link card:"
msgstr "" msgstr ""
@@ -142,7 +142,7 @@ msgstr ""
msgid "Add to Lists" msgid "Add to Lists"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:280 #: src/view/screens/ProfileFeed.tsx:270
msgid "Add to my feeds" msgid "Add to my feeds"
msgstr "" msgstr ""
@@ -224,11 +224,11 @@ msgstr ""
msgid "Are you sure you want to delete the app password \"{name}\"?" msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:141 #: src/view/com/composer/Composer.tsx:142
msgid "Are you sure you'd like to discard this draft?" msgid "Are you sure you'd like to discard this draft?"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:375 #: src/view/screens/ProfileList.tsx:352
msgid "Are you sure?" msgid "Are you sure?"
msgstr "" msgstr ""
@@ -250,9 +250,9 @@ msgstr ""
#: src/view/com/auth/login/LoginForm.tsx:249 #: src/view/com/auth/login/LoginForm.tsx:249
#: src/view/com/auth/login/SetNewPasswordForm.tsx:148 #: src/view/com/auth/login/SetNewPasswordForm.tsx:148
#: src/view/com/modals/report/InputIssueDetails.tsx:45 #: src/view/com/modals/report/InputIssueDetails.tsx:45
#: src/view/com/post-thread/PostThread.tsx:392 #: src/view/com/post-thread/PostThread.tsx:395
#: src/view/com/post-thread/PostThread.tsx:442 #: src/view/com/post-thread/PostThread.tsx:445
#: src/view/com/post-thread/PostThread.tsx:450 #: src/view/com/post-thread/PostThread.tsx:453
#: src/view/com/profile/ProfileHeader.tsx:672 #: src/view/com/profile/ProfileHeader.tsx:672
msgid "Back" msgid "Back"
msgstr "" msgstr ""
@@ -275,15 +275,15 @@ msgstr ""
msgid "Block Account" msgid "Block Account"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:545 #: src/view/screens/ProfileList.tsx:522
msgid "Block accounts" msgid "Block accounts"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:495 #: src/view/screens/ProfileList.tsx:472
msgid "Block list" msgid "Block list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:330 #: src/view/screens/ProfileList.tsx:307
msgid "Block these accounts?" msgid "Block these accounts?"
msgstr "" msgstr ""
@@ -303,15 +303,19 @@ msgstr ""
msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours." msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours."
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:248 #: src/view/com/post-thread/PostThread.tsx:251
msgid "Blocked post." msgid "Blocked post."
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:332 #: src/view/screens/ProfileList.tsx:309
msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:26 #: src/view/com/auth/HomeLoggedOutCTA.tsx:93
msgid "Blog"
msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:31
msgid "Bluesky" msgid "Bluesky"
msgstr "" msgstr ""
@@ -343,6 +347,10 @@ msgstr ""
msgid "Build version {0} {1}" msgid "Build version {0} {1}"
msgstr "" msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:87
msgid "Business"
msgstr ""
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60 #: src/view/com/composer/photos/OpenCameraBtn.tsx:60
#: src/view/com/util/UserAvatar.tsx:221 #: src/view/com/util/UserAvatar.tsx:221
#: src/view/com/util/UserBanner.tsx:38 #: src/view/com/util/UserBanner.tsx:38
@@ -353,8 +361,8 @@ msgstr ""
msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long."
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:279 #: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Composer.tsx:282 #: src/view/com/composer/Composer.tsx:288
#: src/view/com/modals/AltImage.tsx:127 #: src/view/com/modals/AltImage.tsx:127
#: src/view/com/modals/ChangeEmail.tsx:218 #: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220 #: src/view/com/modals/ChangeEmail.tsx:220
@@ -368,7 +376,7 @@ msgstr ""
#: src/view/com/modals/LinkWarning.tsx:85 #: src/view/com/modals/LinkWarning.tsx:85
#: src/view/com/modals/Repost.tsx:73 #: src/view/com/modals/Repost.tsx:73
#: src/view/com/modals/Waitlist.tsx:136 #: src/view/com/modals/Waitlist.tsx:136
#: src/view/screens/Search/Search.tsx:558 #: src/view/screens/Search/Search.tsx:592
#: src/view/shell/desktop/Search.tsx:182 #: src/view/shell/desktop/Search.tsx:182
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
@@ -473,7 +481,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "" msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:73 #: src/view/com/util/forms/SearchInput.tsx:73
#: src/view/screens/Search/Search.tsx:543 #: src/view/screens/Search/Search.tsx:577
msgid "Clear search query" msgid "Clear search query"
msgstr "" msgstr ""
@@ -551,7 +559,7 @@ msgstr ""
msgid "Content Languages" msgid "Content Languages"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:69 #: src/view/com/util/moderation/ScreenHider.tsx:78
msgid "Content Warning" msgid "Content Warning"
msgstr "" msgstr ""
@@ -573,7 +581,7 @@ msgstr ""
msgid "Copy" msgid "Copy"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:407 #: src/view/screens/ProfileList.tsx:384
msgid "Copy link to list" msgid "Copy link to list"
msgstr "" msgstr ""
@@ -593,15 +601,16 @@ msgstr ""
msgid "Copyright Policy" msgid "Copyright Policy"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:103 #: src/view/screens/ProfileFeed.tsx:94
msgid "Could not load feed" msgid "Could not load feed"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:860 #: src/view/screens/ProfileList.tsx:830
msgid "Could not load list" msgid "Could not load list"
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:41 #: src/view/com/auth/HomeLoggedOutCTA.tsx:62
#: src/view/com/auth/SplashScreen.tsx:46
msgid "Create a new account" msgid "Create a new account"
msgstr "" msgstr ""
@@ -609,7 +618,8 @@ msgstr ""
msgid "Create Account" msgid "Create Account"
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:38 #: src/view/com/auth/HomeLoggedOutCTA.tsx:54
#: src/view/com/auth/SplashScreen.tsx:43
msgid "Create new account" msgid "Create new account"
msgstr "" msgstr ""
@@ -643,8 +653,8 @@ msgstr ""
msgid "Delete app password" msgid "Delete app password"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:374 #: src/view/screens/ProfileList.tsx:351
#: src/view/screens/ProfileList.tsx:434 #: src/view/screens/ProfileList.tsx:411
msgid "Delete List" msgid "Delete List"
msgstr "" msgstr ""
@@ -664,7 +674,7 @@ msgstr ""
msgid "Delete this post?" msgid "Delete this post?"
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:240 #: src/view/com/post-thread/PostThread.tsx:243
msgid "Deleted post." msgid "Deleted post."
msgstr "" msgstr ""
@@ -683,11 +693,11 @@ msgstr ""
msgid "Developer Tools" msgid "Developer Tools"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:142 #: src/view/com/composer/Composer.tsx:143
msgid "Discard" msgid "Discard"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:136 #: src/view/com/composer/Composer.tsx:137
msgid "Discard draft" msgid "Discard draft"
msgstr "" msgstr ""
@@ -739,7 +749,7 @@ msgstr ""
msgid "Edit image" msgid "Edit image"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:422 #: src/view/screens/ProfileList.tsx:399
msgid "Edit list details" msgid "Edit list details"
msgstr "" msgstr ""
@@ -787,7 +797,7 @@ msgstr ""
msgid "Enable this setting to only see replies between people you follow." msgid "Enable this setting to only see replies between people you follow."
msgstr "" msgstr ""
#: src/view/screens/Profile.tsx:471 #: src/view/screens/Profile.tsx:425
msgid "End of feed" msgid "End of feed"
msgstr "" msgstr ""
@@ -815,7 +825,7 @@ msgstr ""
msgid "Enter your username and password" msgid "Enter your username and password"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:105 #: src/view/screens/Search/Search.tsx:106
msgid "Error:" msgid "Error:"
msgstr "" msgstr ""
@@ -836,7 +846,7 @@ msgstr ""
msgid "Feed offline" msgid "Feed offline"
msgstr "" msgstr ""
#: src/view/com/feeds/FeedPage.tsx:140 #: src/view/com/feeds/FeedPage.tsx:143
msgid "Feed Preferences" msgid "Feed Preferences"
msgstr "" msgstr ""
@@ -847,8 +857,8 @@ msgstr ""
#: src/view/screens/Feeds.tsx:475 #: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164 #: src/view/screens/Profile.tsx:164
#: src/view/shell/bottom-bar/BottomBar.tsx:160 #: src/view/shell/bottom-bar/BottomBar.tsx:181
#: src/view/shell/desktop/LeftNav.tsx:333 #: src/view/shell/desktop/LeftNav.tsx:339
#: src/view/shell/Drawer.tsx:455 #: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:456 #: src/view/shell/Drawer.tsx:456
msgid "Feeds" msgid "Feeds"
@@ -862,6 +872,14 @@ msgstr ""
msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information." msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information."
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:422
msgid "Find users on Bluesky"
msgstr ""
#: src/view/screens/Search/Search.tsx:420
msgid "Find users with the search tool on the right"
msgstr ""
#: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150 #: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150
msgid "Finding similar accounts..." msgid "Finding similar accounts..."
msgstr "" msgstr ""
@@ -940,17 +958,17 @@ msgstr ""
msgid "Get Started" msgid "Get Started"
msgstr "" msgstr ""
#: src/view/com/auth/LoggedOut.tsx:68 #: src/view/com/auth/LoggedOut.tsx:70
#: src/view/com/auth/LoggedOut.tsx:69 #: src/view/com/auth/LoggedOut.tsx:71
#: src/view/com/util/moderation/ScreenHider.tsx:105 #: src/view/com/util/moderation/ScreenHider.tsx:123
#: src/view/shell/desktop/LeftNav.tsx:103 #: src/view/shell/desktop/LeftNav.tsx:103
msgid "Go back" msgid "Go back"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:112 #: src/view/screens/ProfileFeed.tsx:103
#: src/view/screens/ProfileFeed.tsx:117 #: src/view/screens/ProfileFeed.tsx:108
#: src/view/screens/ProfileList.tsx:869 #: src/view/screens/ProfileList.tsx:839
#: src/view/screens/ProfileList.tsx:874 #: src/view/screens/ProfileList.tsx:844
msgid "Go Back" msgid "Go Back"
msgstr "" msgstr ""
@@ -974,6 +992,7 @@ msgid "Here is your app password."
msgstr "" msgstr ""
#: src/view/com/notifications/FeedItem.tsx:316 #: src/view/com/notifications/FeedItem.tsx:316
#: src/view/com/util/moderation/ContentHider.tsx:103
msgid "Hide" msgid "Hide"
msgstr "" msgstr ""
@@ -1009,14 +1028,14 @@ msgstr ""
#~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted." #~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
#~ msgstr "" #~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:116 #: src/view/shell/bottom-bar/BottomBar.tsx:137
#: src/view/shell/desktop/LeftNav.tsx:297 #: src/view/shell/desktop/LeftNav.tsx:303
#: src/view/shell/Drawer.tsx:379 #: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:380 #: src/view/shell/Drawer.tsx:380
msgid "Home" msgid "Home"
msgstr "" msgstr ""
#: src/view/com/pager/FeedsTabBarMobile.tsx:99 #: src/view/com/pager/FeedsTabBarMobile.tsx:96
#: src/view/screens/PreferencesHomeFeed.tsx:95 #: src/view/screens/PreferencesHomeFeed.tsx:95
#: src/view/screens/Settings.tsx:481 #: src/view/screens/Settings.tsx:481
msgid "Home Feed Preferences" msgid "Home Feed Preferences"
@@ -1082,6 +1101,10 @@ msgstr ""
msgid "Invite codes: {invitesAvailable} available" msgid "Invite codes: {invitesAvailable} available"
msgstr "" msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:99
msgid "Jobs"
msgstr ""
#: src/view/com/modals/Waitlist.tsx:67 #: src/view/com/modals/Waitlist.tsx:67
msgid "Join the waitlist" msgid "Join the waitlist"
msgstr "" msgstr ""
@@ -1107,9 +1130,13 @@ msgstr ""
msgid "Languages" msgid "Languages"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ContentHider.tsx:101
msgid "Learn more"
msgstr ""
#: src/view/com/util/moderation/PostAlerts.tsx:47 #: src/view/com/util/moderation/PostAlerts.tsx:47
#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:65 #: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:65
#: src/view/com/util/moderation/ScreenHider.tsx:88 #: src/view/com/util/moderation/ScreenHider.tsx:104
msgid "Learn More" msgid "Learn More"
msgstr "" msgstr ""
@@ -1117,7 +1144,7 @@ msgstr ""
#: src/view/com/util/moderation/PostAlerts.tsx:40 #: src/view/com/util/moderation/PostAlerts.tsx:40
#: src/view/com/util/moderation/PostHider.tsx:76 #: src/view/com/util/moderation/PostHider.tsx:76
#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:49 #: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:49
#: src/view/com/util/moderation/ScreenHider.tsx:85 #: src/view/com/util/moderation/ScreenHider.tsx:101
msgid "Learn more about this warning" msgid "Learn more about this warning"
msgstr "" msgstr ""
@@ -1147,7 +1174,7 @@ msgstr ""
#~ msgid "Light" #~ msgid "Light"
#~ msgstr "" #~ msgstr ""
#: src/view/screens/ProfileFeed.tsx:643 #: src/view/screens/ProfileFeed.tsx:577
msgid "Like this feed" msgid "Like this feed"
msgstr "" msgstr ""
@@ -1177,22 +1204,22 @@ msgid "List Name"
msgstr "" msgstr ""
#: src/view/screens/Profile.tsx:165 #: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:373 #: src/view/shell/desktop/LeftNav.tsx:376
#: src/view/shell/Drawer.tsx:471 #: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:472 #: src/view/shell/Drawer.tsx:472
msgid "Lists" msgid "Lists"
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:257 #: src/view/com/post-thread/PostThread.tsx:260
#: src/view/com/post-thread/PostThread.tsx:265 #: src/view/com/post-thread/PostThread.tsx:268
msgid "Load more posts" msgid "Load more posts"
msgstr "" msgstr ""
#: src/view/screens/Notifications.tsx:141 #: src/view/screens/Notifications.tsx:144
msgid "Load new notifications" msgid "Load new notifications"
msgstr "" msgstr ""
#: src/view/com/feeds/FeedPage.tsx:185 #: src/view/com/feeds/FeedPage.tsx:189
msgid "Load new posts" msgid "Load new posts"
msgstr "" msgstr ""
@@ -1216,9 +1243,9 @@ msgstr ""
msgid "Login to account that is not listed" msgid "Login to account that is not listed"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:482 #: src/view/screens/ProfileFeed.tsx:472
msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!" #~ msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
msgstr "" #~ msgstr ""
#: src/view/com/modals/LinkWarning.tsx:63 #: src/view/com/modals/LinkWarning.tsx:63
msgid "Make sure this is where you intend to go!" msgid "Make sure this is where you intend to go!"
@@ -1236,18 +1263,17 @@ msgstr ""
msgid "Mentioned users" msgid "Mentioned users"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:503 #: src/view/screens/Search/Search.tsx:537
msgid "Menu" msgid "Menu"
msgstr "" msgstr ""
#: src/view/com/posts/FeedErrorMessage.tsx:194 #: src/view/com/posts/FeedErrorMessage.tsx:194
#: src/view/screens/ProfileFeed.tsx:490
msgid "Message from server" msgid "Message from server"
msgstr "" msgstr ""
#: src/view/screens/Moderation.tsx:64 #: src/view/screens/Moderation.tsx:64
#: src/view/screens/Settings.tsx:563 #: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:391 #: src/view/shell/desktop/LeftNav.tsx:394
#: src/view/shell/Drawer.tsx:490 #: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:491 #: src/view/shell/Drawer.tsx:491
msgid "Moderation" msgid "Moderation"
@@ -1266,8 +1292,8 @@ msgid "More feeds"
msgstr "" msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:548 #: src/view/com/profile/ProfileHeader.tsx:548
#: src/view/screens/ProfileFeed.tsx:370 #: src/view/screens/ProfileFeed.tsx:360
#: src/view/screens/ProfileList.tsx:606 #: src/view/screens/ProfileList.tsx:583
msgid "More options" msgid "More options"
msgstr "" msgstr ""
@@ -1279,15 +1305,15 @@ msgstr ""
msgid "Mute Account" msgid "Mute Account"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:533 #: src/view/screens/ProfileList.tsx:510
msgid "Mute accounts" msgid "Mute accounts"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:480 #: src/view/screens/ProfileList.tsx:457
msgid "Mute list" msgid "Mute list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:293 #: src/view/screens/ProfileList.tsx:270
msgid "Mute these accounts?" msgid "Mute these accounts?"
msgstr "" msgstr ""
@@ -1307,7 +1333,7 @@ msgstr ""
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private." msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:295 #: src/view/screens/ProfileList.tsx:272
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "" msgstr ""
@@ -1345,12 +1371,12 @@ msgstr ""
msgid "New" msgid "New"
msgstr "" msgstr ""
#: src/view/com/feeds/FeedPage.tsx:196 #: src/view/com/feeds/FeedPage.tsx:200
#: src/view/screens/Feeds.tsx:510 #: src/view/screens/Feeds.tsx:510
#: src/view/screens/Profile.tsx:389 #: src/view/screens/Profile.tsx:353
#: src/view/screens/ProfileFeed.tsx:451 #: src/view/screens/ProfileFeed.tsx:430
#: src/view/screens/ProfileList.tsx:212 #: src/view/screens/ProfileList.tsx:193
#: src/view/screens/ProfileList.tsx:244 #: src/view/screens/ProfileList.tsx:221
#: src/view/shell/desktop/LeftNav.tsx:246 #: src/view/shell/desktop/LeftNav.tsx:246
msgid "New post" msgid "New post"
msgstr "" msgstr ""
@@ -1379,8 +1405,8 @@ msgstr ""
msgid "No" msgid "No"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:636 #: src/view/screens/ProfileFeed.tsx:570
#: src/view/screens/ProfileList.tsx:740 #: src/view/screens/ProfileList.tsx:711
msgid "No description" msgid "No description"
msgstr "" msgstr ""
@@ -1398,9 +1424,9 @@ msgstr ""
#~ msgstr "" #~ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:127 #: src/view/com/modals/ListAddRemoveUsers.tsx:127
#: src/view/screens/Search/Search.tsx:270 #: src/view/screens/Search/Search.tsx:271
#: src/view/screens/Search/Search.tsx:298 #: src/view/screens/Search/Search.tsx:299
#: src/view/screens/Search/Search.tsx:581 #: src/view/screens/Search/Search.tsx:615
#: src/view/shell/desktop/Search.tsx:210 #: src/view/shell/desktop/Search.tsx:210
msgid "No results found for {query}" msgid "No results found for {query}"
msgstr "" msgstr ""
@@ -1429,10 +1455,10 @@ msgstr ""
#~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting." #~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Notifications.tsx:108 #: src/view/screens/Notifications.tsx:109
#: src/view/screens/Notifications.tsx:132 #: src/view/screens/Notifications.tsx:133
#: src/view/shell/bottom-bar/BottomBar.tsx:187 #: src/view/shell/bottom-bar/BottomBar.tsx:205
#: src/view/shell/desktop/LeftNav.tsx:355 #: src/view/shell/desktop/LeftNav.tsx:358
#: src/view/shell/Drawer.tsx:416 #: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:417 #: src/view/shell/Drawer.tsx:417
msgid "Notifications" msgid "Notifications"
@@ -1446,7 +1472,7 @@ msgstr ""
msgid "Okay" msgid "Okay"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:348 #: src/view/com/composer/Composer.tsx:354
msgid "One or more images is missing alt text." msgid "One or more images is missing alt text."
msgstr "" msgstr ""
@@ -1454,7 +1480,7 @@ msgstr ""
msgid "Only {0} can reply." msgid "Only {0} can reply."
msgstr "" msgstr ""
#: src/view/com/pager/FeedsTabBarMobile.tsx:79 #: src/view/com/pager/FeedsTabBarMobile.tsx:76
msgid "Open navigation" msgid "Open navigation"
msgstr "" msgstr ""
@@ -1569,13 +1595,13 @@ msgstr ""
msgid "Please tell us why you think this decision was incorrect." msgid "Please tell us why you think this decision was incorrect."
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:331 #: src/view/com/composer/Composer.tsx:337
#: src/view/com/post-thread/PostThread.tsx:223 #: src/view/com/post-thread/PostThread.tsx:226
#: src/view/screens/PostThread.tsx:78 #: src/view/screens/PostThread.tsx:80
msgid "Post" msgid "Post"
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:382 #: src/view/com/post-thread/PostThread.tsx:385
msgid "Post hidden" msgid "Post hidden"
msgstr "" msgstr ""
@@ -1587,7 +1613,7 @@ msgstr ""
msgid "Post Languages" msgid "Post Languages"
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:434 #: src/view/com/post-thread/PostThread.tsx:437
msgid "Post not found" msgid "Post not found"
msgstr "" msgstr ""
@@ -1623,7 +1649,8 @@ msgstr ""
msgid "Processing..." msgid "Processing..."
msgstr "" msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:229 #: src/view/shell/bottom-bar/BottomBar.tsx:247
#: src/view/shell/desktop/LeftNav.tsx:412
#: src/view/shell/Drawer.tsx:69 #: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:525 #: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:526 #: src/view/shell/Drawer.tsx:526
@@ -1690,7 +1717,7 @@ msgstr ""
#: src/view/com/feeds/FeedSourceCard.tsx:105 #: src/view/com/feeds/FeedSourceCard.tsx:105
#: src/view/com/feeds/FeedSourceCard.tsx:172 #: src/view/com/feeds/FeedSourceCard.tsx:172
#: src/view/screens/ProfileFeed.tsx:280 #: src/view/screens/ProfileFeed.tsx:270
msgid "Remove from my feeds" msgid "Remove from my feeds"
msgstr "" msgstr ""
@@ -1735,11 +1762,11 @@ msgstr ""
msgid "Report Account" msgid "Report Account"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:300 #: src/view/screens/ProfileFeed.tsx:290
msgid "Report feed" msgid "Report feed"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:448 #: src/view/screens/ProfileList.tsx:425
msgid "Report List" msgid "Report List"
msgstr "" msgstr ""
@@ -1851,10 +1878,10 @@ msgstr ""
#: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:64 #: src/view/com/util/forms/SearchInput.tsx:64
#: src/view/screens/Search/Search.tsx:381 #: src/view/screens/Search/Search.tsx:401
#: src/view/screens/Search/Search.tsx:533 #: src/view/screens/Search/Search.tsx:567
#: src/view/shell/bottom-bar/BottomBar.tsx:138 #: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:315 #: src/view/shell/desktop/LeftNav.tsx:321
#: src/view/shell/desktop/Search.tsx:161 #: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170 #: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:343 #: src/view/shell/Drawer.tsx:343
@@ -1863,14 +1890,14 @@ msgid "Search"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:390 #: src/view/screens/Search/Search.tsx:390
msgid "Search for posts and users." #~ msgid "Search for posts and users."
msgstr "" #~ msgstr ""
#: src/view/com/modals/ChangeEmail.tsx:110 #: src/view/com/modals/ChangeEmail.tsx:110
msgid "Security Step Required" msgid "Security Step Required"
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:29 #: src/view/com/auth/HomeLoggedOutCTA.tsx:39
msgid "See what's next" msgid "See what's next"
msgstr "" msgstr ""
@@ -1944,7 +1971,7 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:277 #: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:427 #: src/view/shell/desktop/LeftNav.tsx:430
#: src/view/shell/Drawer.tsx:546 #: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:547 #: src/view/shell/Drawer.tsx:547
msgid "Settings" msgid "Settings"
@@ -1956,11 +1983,11 @@ msgstr ""
#: src/view/com/profile/ProfileHeader.tsx:338 #: src/view/com/profile/ProfileHeader.tsx:338
#: src/view/com/util/forms/PostDropdownBtn.tsx:129 #: src/view/com/util/forms/PostDropdownBtn.tsx:129
#: src/view/screens/ProfileList.tsx:407 #: src/view/screens/ProfileList.tsx:384
msgid "Share" msgid "Share"
msgstr "" msgstr ""
#: src/view/screens/ProfileFeed.tsx:312 #: src/view/screens/ProfileFeed.tsx:302
msgid "Share feed" msgid "Share feed"
msgstr "" msgstr ""
@@ -1968,11 +1995,12 @@ msgstr ""
#~ msgid "Share link" #~ msgid "Share link"
#~ msgstr "" #~ msgstr ""
#: src/view/com/util/moderation/ContentHider.tsx:105
#: src/view/screens/Settings.tsx:316 #: src/view/screens/Settings.tsx:316
msgid "Show" msgid "Show"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:114 #: src/view/com/util/moderation/ScreenHider.tsx:132
msgid "Show anyway" msgid "Show anyway"
msgstr "" msgstr ""
@@ -2000,15 +2028,23 @@ msgstr ""
msgid "Show users" msgid "Show users"
msgstr "" msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:70
#: src/view/com/auth/login/Login.tsx:98 #: src/view/com/auth/login/Login.tsx:98
#: src/view/com/auth/SplashScreen.tsx:49 #: src/view/com/auth/SplashScreen.tsx:54
#: src/view/shell/NavSignupCard.tsx:52 #: src/view/shell/bottom-bar/BottomBar.tsx:285
#: src/view/shell/NavSignupCard.tsx:53 #: src/view/shell/bottom-bar/BottomBar.tsx:286
#: src/view/shell/bottom-bar/BottomBar.tsx:288
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:177
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:178
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:180
#: src/view/shell/NavSignupCard.tsx:58
#: src/view/shell/NavSignupCard.tsx:59
msgid "Sign in" msgid "Sign in"
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:52 #: src/view/com/auth/HomeLoggedOutCTA.tsx:78
#: src/view/com/auth/SplashScreen.web.tsx:84 #: src/view/com/auth/SplashScreen.tsx:57
#: src/view/com/auth/SplashScreen.web.tsx:87
msgid "Sign In" msgid "Sign In"
msgstr "" msgstr ""
@@ -2030,16 +2066,26 @@ msgstr ""
msgid "Sign out" msgid "Sign out"
msgstr "" msgstr ""
#: src/view/shell/NavSignupCard.tsx:43 #: src/view/shell/bottom-bar/BottomBar.tsx:275
#: src/view/shell/NavSignupCard.tsx:44 #: src/view/shell/bottom-bar/BottomBar.tsx:276
#: src/view/shell/NavSignupCard.tsx:46 #: src/view/shell/bottom-bar/BottomBar.tsx:278
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:167
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:168
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:170
#: src/view/shell/NavSignupCard.tsx:49
#: src/view/shell/NavSignupCard.tsx:50
#: src/view/shell/NavSignupCard.tsx:52
msgid "Sign up" msgid "Sign up"
msgstr "" msgstr ""
#: src/view/shell/NavSignupCard.tsx:36 #: src/view/shell/NavSignupCard.tsx:42
msgid "Sign up or sign in to join the conversation" msgid "Sign up or sign in to join the conversation"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:76
msgid "Sign-in Required"
msgstr ""
#: src/view/screens/Settings.tsx:327 #: src/view/screens/Settings.tsx:327
msgid "Signed in as" msgid "Signed in as"
msgstr "" msgstr ""
@@ -2077,15 +2123,15 @@ msgstr ""
msgid "Submit" msgid "Submit"
msgstr "Submit" msgstr "Submit"
#: src/view/screens/ProfileList.tsx:597 #: src/view/screens/ProfileList.tsx:574
msgid "Subscribe" msgid "Subscribe"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:593 #: src/view/screens/ProfileList.tsx:570
msgid "Subscribe to this list" msgid "Subscribe to this list"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:354 #: src/view/screens/Search/Search.tsx:357
msgid "Suggested Follows" msgid "Suggested Follows"
msgstr "" msgstr ""
@@ -2135,7 +2181,7 @@ msgstr ""
msgid "The Copyright Policy has been moved to <0/>" msgid "The Copyright Policy has been moved to <0/>"
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:437 #: src/view/com/post-thread/PostThread.tsx:440
msgid "The post may have been deleted." msgid "The post may have been deleted."
msgstr "" msgstr ""
@@ -2159,10 +2205,14 @@ msgstr ""
msgid "This {0} has been labeled." msgid "This {0} has been labeled."
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:72 #: src/view/com/util/moderation/ScreenHider.tsx:88
msgid "This {screenDescription} has been flagged:" msgid "This {screenDescription} has been flagged:"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:83
msgid "This account has requested that users sign in to view their profile."
msgstr ""
#: src/view/com/posts/FeedErrorMessage.tsx:107 #: src/view/com/posts/FeedErrorMessage.tsx:107
msgid "This content is not viewable without a Bluesky account." msgid "This content is not viewable without a Bluesky account."
msgstr "" msgstr ""
@@ -2222,11 +2272,11 @@ msgstr ""
msgid "Try again" msgid "Try again"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:495 #: src/view/screens/ProfileList.tsx:472
msgid "Un-block list" msgid "Un-block list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:480 #: src/view/screens/ProfileList.tsx:457
msgid "Un-mute list" msgid "Un-mute list"
msgstr "" msgstr ""
@@ -2262,7 +2312,7 @@ msgstr ""
msgid "Unmute thread" msgid "Unmute thread"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:463 #: src/view/screens/ProfileList.tsx:440
msgid "Unpin moderation list" msgid "Unpin moderation list"
msgstr "" msgstr ""
@@ -2311,7 +2361,7 @@ msgstr ""
msgid "Username or email address" msgid "Username or email address"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:767 #: src/view/screens/ProfileList.tsx:738
msgid "Users" msgid "Users"
msgstr "" msgstr ""
@@ -2368,7 +2418,7 @@ msgstr ""
#~ msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later." #~ msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Search/Search.tsx:237 #: src/view/screens/Search/Search.tsx:238
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "" msgstr ""
@@ -2384,6 +2434,10 @@ msgstr ""
msgid "What is the issue with this {collectionName}?" msgid "What is the issue with this {collectionName}?"
msgstr "" msgstr ""
#: src/view/com/auth/SplashScreen.tsx:34
msgid "What's up?"
msgstr ""
#: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:78 #: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:78
msgid "Which languages are used in this post?" msgid "Which languages are used in this post?"
msgstr "" msgstr ""
@@ -2405,7 +2459,7 @@ msgstr ""
msgid "Wide" msgid "Wide"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:403 #: src/view/com/composer/Composer.tsx:409
msgid "Write post" msgid "Write post"
msgstr "" msgstr ""
@@ -2444,16 +2498,16 @@ msgstr ""
msgid "You don't have any saved feeds." msgid "You don't have any saved feeds."
msgstr "" msgstr ""
#: src/view/com/post-thread/PostThread.tsx:385 #: src/view/com/post-thread/PostThread.tsx:388
msgid "You have blocked the author or you have been blocked by the author." msgid "You have blocked the author or you have been blocked by the author."
msgstr "" msgstr ""
#: src/view/com/feeds/ProfileFeedgens.tsx:154 #: src/view/com/feeds/ProfileFeedgens.tsx:141
msgid "You have no feeds." msgid "You have no feeds."
msgstr "" msgstr ""
#: src/view/com/lists/MyLists.tsx:89 #: src/view/com/lists/MyLists.tsx:89
#: src/view/com/lists/ProfileLists.tsx:158 #: src/view/com/lists/ProfileLists.tsx:145
msgid "You have no lists." msgid "You have no lists."
msgstr "" msgstr ""
+181 -127
View File
@@ -47,7 +47,7 @@ msgstr ""
msgid "{invitesAvailable} invite codes available" msgid "{invitesAvailable} invite codes available"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:87 #: src/view/screens/Search/Search.tsx:88
msgid "{message}" msgid "{message}"
msgstr "" msgstr ""
@@ -95,7 +95,7 @@ msgstr "अकाउंट के विकल्प"
#: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
#: src/view/com/modals/UserAddRemoveLists.tsx:193 #: src/view/com/modals/UserAddRemoveLists.tsx:193
#: src/view/screens/ProfileList.tsx:783 #: src/view/screens/ProfileList.tsx:754
msgid "Add" msgid "Add"
msgstr "ऐड करो" msgstr "ऐड करो"
@@ -103,7 +103,7 @@ msgstr "ऐड करो"
msgid "Add a content warning" msgid "Add a content warning"
msgstr "सामग्री चेतावनी जोड़ें" msgstr "सामग्री चेतावनी जोड़ें"
#: src/view/screens/ProfileList.tsx:773 #: src/view/screens/ProfileList.tsx:744
msgid "Add a user to this list" msgid "Add a user to this list"
msgstr "इस सूची में किसी को जोड़ें" msgstr "इस सूची में किसी को जोड़ें"
@@ -126,11 +126,11 @@ msgstr "विवरण जोड़ें"
msgid "Add details to report" msgid "Add details to report"
msgstr "रिपोर्ट करने के लिए विवरण जोड़ें" msgstr "रिपोर्ट करने के लिए विवरण जोड़ें"
#: src/view/com/composer/Composer.tsx:432 #: src/view/com/composer/Composer.tsx:438
msgid "Add link card" msgid "Add link card"
msgstr "लिंक कार्ड जोड़ें" msgstr "लिंक कार्ड जोड़ें"
#: src/view/com/composer/Composer.tsx:435 #: src/view/com/composer/Composer.tsx:441
msgid "Add link card:" msgid "Add link card:"
msgstr "लिंक कार्ड जोड़ें:" msgstr "लिंक कार्ड जोड़ें:"
@@ -142,7 +142,7 @@ msgstr "अपने डोमेन में निम्नलिखित DN
msgid "Add to Lists" msgid "Add to Lists"
msgstr "सूचियों में जोड़ें" msgstr "सूचियों में जोड़ें"
#: src/view/screens/ProfileFeed.tsx:280 #: src/view/screens/ProfileFeed.tsx:270
msgid "Add to my feeds" msgid "Add to my feeds"
msgstr "इस फ़ीड को सहेजें" msgstr "इस फ़ीड को सहेजें"
@@ -224,11 +224,11 @@ msgstr "दिखावट"
msgid "Are you sure you want to delete the app password \"{name}\"?" msgid "Are you sure you want to delete the app password \"{name}\"?"
msgstr "क्या आप वाकई ऐप पासवर्ड \"{name}\" हटाना चाहते हैं?" msgstr "क्या आप वाकई ऐप पासवर्ड \"{name}\" हटाना चाहते हैं?"
#: src/view/com/composer/Composer.tsx:141 #: src/view/com/composer/Composer.tsx:142
msgid "Are you sure you'd like to discard this draft?" msgid "Are you sure you'd like to discard this draft?"
msgstr "क्या आप वाकई इस ड्राफ्ट को हटाना करना चाहेंगे?" msgstr "क्या आप वाकई इस ड्राफ्ट को हटाना करना चाहेंगे?"
#: src/view/screens/ProfileList.tsx:375 #: src/view/screens/ProfileList.tsx:352
msgid "Are you sure?" msgid "Are you sure?"
msgstr "क्या आप वास्तव में इसे करना चाहते हैं?" msgstr "क्या आप वास्तव में इसे करना चाहते हैं?"
@@ -250,9 +250,9 @@ msgstr "कलात्मक या गैर-कामुक नग्नत
#: src/view/com/auth/login/LoginForm.tsx:249 #: src/view/com/auth/login/LoginForm.tsx:249
#: src/view/com/auth/login/SetNewPasswordForm.tsx:148 #: src/view/com/auth/login/SetNewPasswordForm.tsx:148
#: src/view/com/modals/report/InputIssueDetails.tsx:45 #: src/view/com/modals/report/InputIssueDetails.tsx:45
#: src/view/com/post-thread/PostThread.tsx:392 #: src/view/com/post-thread/PostThread.tsx:395
#: src/view/com/post-thread/PostThread.tsx:442 #: src/view/com/post-thread/PostThread.tsx:445
#: src/view/com/post-thread/PostThread.tsx:450 #: src/view/com/post-thread/PostThread.tsx:453
#: src/view/com/profile/ProfileHeader.tsx:672 #: src/view/com/profile/ProfileHeader.tsx:672
msgid "Back" msgid "Back"
msgstr "वापस" msgstr "वापस"
@@ -275,15 +275,15 @@ msgstr "जन्मदिन:"
msgid "Block Account" msgid "Block Account"
msgstr "खाता ब्लॉक करें" msgstr "खाता ब्लॉक करें"
#: src/view/screens/ProfileList.tsx:545 #: src/view/screens/ProfileList.tsx:522
msgid "Block accounts" msgid "Block accounts"
msgstr "खाता ब्लॉक करें" msgstr "खाता ब्लॉक करें"
#: src/view/screens/ProfileList.tsx:495 #: src/view/screens/ProfileList.tsx:472
msgid "Block list" msgid "Block list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:330 #: src/view/screens/ProfileList.tsx:307
msgid "Block these accounts?" msgid "Block these accounts?"
msgstr "खाता ब्लॉक करें?" msgstr "खाता ब्लॉक करें?"
@@ -303,15 +303,19 @@ msgstr "अवरुद्ध खाते आपके थ्रेड्स
msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours." msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours."
msgstr "अवरुद्ध खाते आपके थ्रेड्स में उत्तर नहीं दे सकते, आपका उल्लेख नहीं कर सकते, या अन्यथा आपके साथ बातचीत नहीं कर सकते। आप उनकी सामग्री नहीं देख पाएंगे और उन्हें आपकी सामग्री देखने से रोका जाएगा।" msgstr "अवरुद्ध खाते आपके थ्रेड्स में उत्तर नहीं दे सकते, आपका उल्लेख नहीं कर सकते, या अन्यथा आपके साथ बातचीत नहीं कर सकते। आप उनकी सामग्री नहीं देख पाएंगे और उन्हें आपकी सामग्री देखने से रोका जाएगा।"
#: src/view/com/post-thread/PostThread.tsx:248 #: src/view/com/post-thread/PostThread.tsx:251
msgid "Blocked post." msgid "Blocked post."
msgstr "ब्लॉक पोस्ट।" msgstr "ब्लॉक पोस्ट।"
#: src/view/screens/ProfileList.tsx:332 #: src/view/screens/ProfileList.tsx:309
msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
msgstr "अवरोधन सार्वजनिक है. अवरुद्ध खाते आपके थ्रेड्स में उत्तर नहीं दे सकते, आपका उल्लेख नहीं कर सकते, या अन्यथा आपके साथ बातचीत नहीं कर सकते।" msgstr "अवरोधन सार्वजनिक है. अवरुद्ध खाते आपके थ्रेड्स में उत्तर नहीं दे सकते, आपका उल्लेख नहीं कर सकते, या अन्यथा आपके साथ बातचीत नहीं कर सकते।"
#: src/view/com/auth/SplashScreen.tsx:26 #: src/view/com/auth/HomeLoggedOutCTA.tsx:93
msgid "Blog"
msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:31
msgid "Bluesky" msgid "Bluesky"
msgstr "Bluesky" msgstr "Bluesky"
@@ -343,6 +347,10 @@ msgstr "Bluesky.Social"
msgid "Build version {0} {1}" msgid "Build version {0} {1}"
msgstr "Build version {0} {1}" msgstr "Build version {0} {1}"
#: src/view/com/auth/HomeLoggedOutCTA.tsx:87
msgid "Business"
msgstr ""
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60 #: src/view/com/composer/photos/OpenCameraBtn.tsx:60
#: src/view/com/util/UserAvatar.tsx:221 #: src/view/com/util/UserAvatar.tsx:221
#: src/view/com/util/UserBanner.tsx:38 #: src/view/com/util/UserBanner.tsx:38
@@ -353,8 +361,8 @@ msgstr "कैमरा"
msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long."
msgstr "केवल अक्षर, संख्या, रिक्त स्थान, डैश और अंडरस्कोर हो सकते हैं। कम से कम 4 अक्षर लंबा होना चाहिए, लेकिन 32 अक्षरों से अधिक लंबा नहीं होना चाहिए।।" msgstr "केवल अक्षर, संख्या, रिक्त स्थान, डैश और अंडरस्कोर हो सकते हैं। कम से कम 4 अक्षर लंबा होना चाहिए, लेकिन 32 अक्षरों से अधिक लंबा नहीं होना चाहिए।।"
#: src/view/com/composer/Composer.tsx:279 #: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Composer.tsx:282 #: src/view/com/composer/Composer.tsx:288
#: src/view/com/modals/AltImage.tsx:127 #: src/view/com/modals/AltImage.tsx:127
#: src/view/com/modals/ChangeEmail.tsx:218 #: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220 #: src/view/com/modals/ChangeEmail.tsx:220
@@ -368,7 +376,7 @@ msgstr "केवल अक्षर, संख्या, रिक्त स्
#: src/view/com/modals/LinkWarning.tsx:85 #: src/view/com/modals/LinkWarning.tsx:85
#: src/view/com/modals/Repost.tsx:73 #: src/view/com/modals/Repost.tsx:73
#: src/view/com/modals/Waitlist.tsx:136 #: src/view/com/modals/Waitlist.tsx:136
#: src/view/screens/Search/Search.tsx:558 #: src/view/screens/Search/Search.tsx:592
#: src/view/shell/desktop/Search.tsx:182 #: src/view/shell/desktop/Search.tsx:182
msgid "Cancel" msgid "Cancel"
msgstr "कैंसिल" msgstr "कैंसिल"
@@ -469,7 +477,7 @@ msgid "Clear all storage data (restart after this)"
msgstr "" msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:73 #: src/view/com/util/forms/SearchInput.tsx:73
#: src/view/screens/Search/Search.tsx:543 #: src/view/screens/Search/Search.tsx:577
msgid "Clear search query" msgid "Clear search query"
msgstr "खोज क्वेरी साफ़ करें" msgstr "खोज क्वेरी साफ़ करें"
@@ -547,7 +555,7 @@ msgstr "सामग्री फ़िल्टरिंग"
msgid "Content Languages" msgid "Content Languages"
msgstr "सामग्री भाषा" msgstr "सामग्री भाषा"
#: src/view/com/util/moderation/ScreenHider.tsx:69 #: src/view/com/util/moderation/ScreenHider.tsx:78
msgid "Content Warning" msgid "Content Warning"
msgstr "सामग्री चेतावनी" msgstr "सामग्री चेतावनी"
@@ -569,7 +577,7 @@ msgstr "कॉपी कर ली"
msgid "Copy" msgid "Copy"
msgstr "कॉपी" msgstr "कॉपी"
#: src/view/screens/ProfileList.tsx:407 #: src/view/screens/ProfileList.tsx:384
msgid "Copy link to list" msgid "Copy link to list"
msgstr "" msgstr ""
@@ -589,15 +597,16 @@ msgstr "पोस्ट टेक्स्ट कॉपी करें"
msgid "Copyright Policy" msgid "Copyright Policy"
msgstr "कॉपीराइट नीति" msgstr "कॉपीराइट नीति"
#: src/view/screens/ProfileFeed.tsx:103 #: src/view/screens/ProfileFeed.tsx:94
msgid "Could not load feed" msgid "Could not load feed"
msgstr "फ़ीड लोड नहीं कर सकता" msgstr "फ़ीड लोड नहीं कर सकता"
#: src/view/screens/ProfileList.tsx:860 #: src/view/screens/ProfileList.tsx:830
msgid "Could not load list" msgid "Could not load list"
msgstr "सूची लोड नहीं कर सकता" msgstr "सूची लोड नहीं कर सकता"
#: src/view/com/auth/SplashScreen.tsx:41 #: src/view/com/auth/HomeLoggedOutCTA.tsx:62
#: src/view/com/auth/SplashScreen.tsx:46
msgid "Create a new account" msgid "Create a new account"
msgstr "नया खाता बनाएं" msgstr "नया खाता बनाएं"
@@ -605,7 +614,8 @@ msgstr "नया खाता बनाएं"
msgid "Create Account" msgid "Create Account"
msgstr "खाता बनाएँ" msgstr "खाता बनाएँ"
#: src/view/com/auth/SplashScreen.tsx:38 #: src/view/com/auth/HomeLoggedOutCTA.tsx:54
#: src/view/com/auth/SplashScreen.tsx:43
msgid "Create new account" msgid "Create new account"
msgstr "नया खाता बनाएं" msgstr "नया खाता बनाएं"
@@ -639,8 +649,8 @@ msgstr "खाता हटाएं"
msgid "Delete app password" msgid "Delete app password"
msgstr "अप्प पासवर्ड हटाएं" msgstr "अप्प पासवर्ड हटाएं"
#: src/view/screens/ProfileList.tsx:374 #: src/view/screens/ProfileList.tsx:351
#: src/view/screens/ProfileList.tsx:434 #: src/view/screens/ProfileList.tsx:411
msgid "Delete List" msgid "Delete List"
msgstr "सूची हटाएँ" msgstr "सूची हटाएँ"
@@ -660,7 +670,7 @@ msgstr "पोस्ट को हटाएं"
msgid "Delete this post?" msgid "Delete this post?"
msgstr "इस पोस्ट को डीलीट करें?" msgstr "इस पोस्ट को डीलीट करें?"
#: src/view/com/post-thread/PostThread.tsx:240 #: src/view/com/post-thread/PostThread.tsx:243
msgid "Deleted post." msgid "Deleted post."
msgstr "यह पोस्ट मिटाई जा चुकी है" msgstr "यह पोस्ट मिटाई जा चुकी है"
@@ -679,11 +689,11 @@ msgstr "देव सर्वर"
msgid "Developer Tools" msgid "Developer Tools"
msgstr "डेवलपर उपकरण" msgstr "डेवलपर उपकरण"
#: src/view/com/composer/Composer.tsx:142 #: src/view/com/composer/Composer.tsx:143
msgid "Discard" msgid "Discard"
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:136 #: src/view/com/composer/Composer.tsx:137
msgid "Discard draft" msgid "Discard draft"
msgstr "ड्राफ्ट हटाएं" msgstr "ड्राफ्ट हटाएं"
@@ -735,7 +745,7 @@ msgstr "प्रत्येक कोड एक बार काम करत
msgid "Edit image" msgid "Edit image"
msgstr "छवि संपादित करें" msgstr "छवि संपादित करें"
#: src/view/screens/ProfileList.tsx:422 #: src/view/screens/ProfileList.tsx:399
msgid "Edit list details" msgid "Edit list details"
msgstr "सूची विवरण संपादित करें" msgstr "सूची विवरण संपादित करें"
@@ -783,7 +793,7 @@ msgstr "ईमेल:"
msgid "Enable this setting to only see replies between people you follow." msgid "Enable this setting to only see replies between people you follow."
msgstr "इस सेटिंग को केवल उन लोगों के बीच जवाब देखने में सक्षम करें जिन्हें आप फॉलो करते हैं।।" msgstr "इस सेटिंग को केवल उन लोगों के बीच जवाब देखने में सक्षम करें जिन्हें आप फॉलो करते हैं।।"
#: src/view/screens/Profile.tsx:471 #: src/view/screens/Profile.tsx:425
msgid "End of feed" msgid "End of feed"
msgstr "" msgstr ""
@@ -811,7 +821,7 @@ msgstr "नीचे अपना नया ईमेल पता दर्ज
msgid "Enter your username and password" msgid "Enter your username and password"
msgstr "अपने यूज़रनेम और पासवर्ड दर्ज करें" msgstr "अपने यूज़रनेम और पासवर्ड दर्ज करें"
#: src/view/screens/Search/Search.tsx:105 #: src/view/screens/Search/Search.tsx:106
msgid "Error:" msgid "Error:"
msgstr "" msgstr ""
@@ -832,7 +842,7 @@ msgstr "अनुशंसित फ़ीड लोड करने में
msgid "Feed offline" msgid "Feed offline"
msgstr "फ़ीड ऑफ़लाइन है" msgstr "फ़ीड ऑफ़लाइन है"
#: src/view/com/feeds/FeedPage.tsx:140 #: src/view/com/feeds/FeedPage.tsx:143
msgid "Feed Preferences" msgid "Feed Preferences"
msgstr "फ़ीड प्राथमिकता" msgstr "फ़ीड प्राथमिकता"
@@ -843,8 +853,8 @@ msgstr "प्रतिक्रिया"
#: src/view/screens/Feeds.tsx:475 #: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164 #: src/view/screens/Profile.tsx:164
#: src/view/shell/bottom-bar/BottomBar.tsx:160 #: src/view/shell/bottom-bar/BottomBar.tsx:181
#: src/view/shell/desktop/LeftNav.tsx:333 #: src/view/shell/desktop/LeftNav.tsx:339
#: src/view/shell/Drawer.tsx:455 #: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:456 #: src/view/shell/Drawer.tsx:456
msgid "Feeds" msgid "Feeds"
@@ -858,6 +868,14 @@ msgstr "सामग्री को व्यवस्थित करने
msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information." msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information."
msgstr "फ़ीड कस्टम एल्गोरिदम हैं जिन्हें उपयोगकर्ता थोड़ी कोडिंग विशेषज्ञता के साथ बनाते हैं। <0/> अधिक जानकारी के लिए." msgstr "फ़ीड कस्टम एल्गोरिदम हैं जिन्हें उपयोगकर्ता थोड़ी कोडिंग विशेषज्ञता के साथ बनाते हैं। <0/> अधिक जानकारी के लिए."
#: src/view/screens/Search/Search.tsx:422
msgid "Find users on Bluesky"
msgstr ""
#: src/view/screens/Search/Search.tsx:420
msgid "Find users with the search tool on the right"
msgstr ""
#: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150 #: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150
msgid "Finding similar accounts..." msgid "Finding similar accounts..."
msgstr "मिलते-जुलते खाते ढूँढना" msgstr "मिलते-जुलते खाते ढूँढना"
@@ -932,17 +950,17 @@ msgstr "गैलरी"
msgid "Get Started" msgid "Get Started"
msgstr "प्रारंभ करें" msgstr "प्रारंभ करें"
#: src/view/com/auth/LoggedOut.tsx:68 #: src/view/com/auth/LoggedOut.tsx:70
#: src/view/com/auth/LoggedOut.tsx:69 #: src/view/com/auth/LoggedOut.tsx:71
#: src/view/com/util/moderation/ScreenHider.tsx:105 #: src/view/com/util/moderation/ScreenHider.tsx:123
#: src/view/shell/desktop/LeftNav.tsx:103 #: src/view/shell/desktop/LeftNav.tsx:103
msgid "Go back" msgid "Go back"
msgstr "वापस जाओ" msgstr "वापस जाओ"
#: src/view/screens/ProfileFeed.tsx:112 #: src/view/screens/ProfileFeed.tsx:103
#: src/view/screens/ProfileFeed.tsx:117 #: src/view/screens/ProfileFeed.tsx:108
#: src/view/screens/ProfileList.tsx:869 #: src/view/screens/ProfileList.tsx:839
#: src/view/screens/ProfileList.tsx:874 #: src/view/screens/ProfileList.tsx:844
msgid "Go Back" msgid "Go Back"
msgstr "वापस जाओ" msgstr "वापस जाओ"
@@ -966,6 +984,7 @@ msgid "Here is your app password."
msgstr "यहां आपका ऐप पासवर्ड है." msgstr "यहां आपका ऐप पासवर्ड है."
#: src/view/com/notifications/FeedItem.tsx:316 #: src/view/com/notifications/FeedItem.tsx:316
#: src/view/com/util/moderation/ContentHider.tsx:103
msgid "Hide" msgid "Hide"
msgstr "इसे छिपाएं" msgstr "इसे छिपाएं"
@@ -1001,14 +1020,14 @@ msgstr ""
#~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted." #~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
#~ msgstr "" #~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:116 #: src/view/shell/bottom-bar/BottomBar.tsx:137
#: src/view/shell/desktop/LeftNav.tsx:297 #: src/view/shell/desktop/LeftNav.tsx:303
#: src/view/shell/Drawer.tsx:379 #: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:380 #: src/view/shell/Drawer.tsx:380
msgid "Home" msgid "Home"
msgstr "होम फीड" msgstr "होम फीड"
#: src/view/com/pager/FeedsTabBarMobile.tsx:99 #: src/view/com/pager/FeedsTabBarMobile.tsx:96
#: src/view/screens/PreferencesHomeFeed.tsx:95 #: src/view/screens/PreferencesHomeFeed.tsx:95
#: src/view/screens/Settings.tsx:481 #: src/view/screens/Settings.tsx:481
msgid "Home Feed Preferences" msgid "Home Feed Preferences"
@@ -1074,6 +1093,10 @@ msgstr ""
msgid "Invite codes: {invitesAvailable} available" msgid "Invite codes: {invitesAvailable} available"
msgstr "" msgstr ""
#: src/view/com/auth/HomeLoggedOutCTA.tsx:99
msgid "Jobs"
msgstr ""
#: src/view/com/modals/Waitlist.tsx:67 #: src/view/com/modals/Waitlist.tsx:67
msgid "Join the waitlist" msgid "Join the waitlist"
msgstr "प्रतीक्षा सूची में शामिल हों" msgstr "प्रतीक्षा सूची में शामिल हों"
@@ -1099,9 +1122,13 @@ msgstr "भाषा सेटिंग्स"
msgid "Languages" msgid "Languages"
msgstr "भाषा" msgstr "भाषा"
#: src/view/com/util/moderation/ContentHider.tsx:101
msgid "Learn more"
msgstr ""
#: src/view/com/util/moderation/PostAlerts.tsx:47 #: src/view/com/util/moderation/PostAlerts.tsx:47
#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:65 #: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:65
#: src/view/com/util/moderation/ScreenHider.tsx:88 #: src/view/com/util/moderation/ScreenHider.tsx:104
msgid "Learn More" msgid "Learn More"
msgstr "अधिक जानें" msgstr "अधिक जानें"
@@ -1109,7 +1136,7 @@ msgstr "अधिक जानें"
#: src/view/com/util/moderation/PostAlerts.tsx:40 #: src/view/com/util/moderation/PostAlerts.tsx:40
#: src/view/com/util/moderation/PostHider.tsx:76 #: src/view/com/util/moderation/PostHider.tsx:76
#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:49 #: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:49
#: src/view/com/util/moderation/ScreenHider.tsx:85 #: src/view/com/util/moderation/ScreenHider.tsx:101
msgid "Learn more about this warning" msgid "Learn more about this warning"
msgstr "इस चेतावनी के बारे में अधिक जानें" msgstr "इस चेतावनी के बारे में अधिक जानें"
@@ -1139,7 +1166,7 @@ msgstr "चित्र पुस्तकालय"
#~ msgid "Light" #~ msgid "Light"
#~ msgstr "लाइट मोड" #~ msgstr "लाइट मोड"
#: src/view/screens/ProfileFeed.tsx:643 #: src/view/screens/ProfileFeed.tsx:577
msgid "Like this feed" msgid "Like this feed"
msgstr "इस फ़ीड को लाइक करो" msgstr "इस फ़ीड को लाइक करो"
@@ -1169,22 +1196,22 @@ msgid "List Name"
msgstr "सूची का नाम" msgstr "सूची का नाम"
#: src/view/screens/Profile.tsx:165 #: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:373 #: src/view/shell/desktop/LeftNav.tsx:376
#: src/view/shell/Drawer.tsx:471 #: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:472 #: src/view/shell/Drawer.tsx:472
msgid "Lists" msgid "Lists"
msgstr "सूची" msgstr "सूची"
#: src/view/com/post-thread/PostThread.tsx:257 #: src/view/com/post-thread/PostThread.tsx:260
#: src/view/com/post-thread/PostThread.tsx:265 #: src/view/com/post-thread/PostThread.tsx:268
msgid "Load more posts" msgid "Load more posts"
msgstr "अधिक पोस्ट लोड करें" msgstr "अधिक पोस्ट लोड करें"
#: src/view/screens/Notifications.tsx:141 #: src/view/screens/Notifications.tsx:144
msgid "Load new notifications" msgid "Load new notifications"
msgstr "नई सूचनाएं लोड करें" msgstr "नई सूचनाएं लोड करें"
#: src/view/com/feeds/FeedPage.tsx:185 #: src/view/com/feeds/FeedPage.tsx:189
msgid "Load new posts" msgid "Load new posts"
msgstr "नई पोस्ट लोड करें" msgstr "नई पोस्ट लोड करें"
@@ -1208,9 +1235,9 @@ msgstr ""
msgid "Login to account that is not listed" msgid "Login to account that is not listed"
msgstr "उस खाते में लॉग इन करें जो सूचीबद्ध नहीं है" msgstr "उस खाते में लॉग इन करें जो सूचीबद्ध नहीं है"
#: src/view/screens/ProfileFeed.tsx:482 #: src/view/screens/ProfileFeed.tsx:472
msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!" #~ msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
msgstr "" #~ msgstr ""
#: src/view/com/modals/LinkWarning.tsx:63 #: src/view/com/modals/LinkWarning.tsx:63
msgid "Make sure this is where you intend to go!" msgid "Make sure this is where you intend to go!"
@@ -1228,18 +1255,17 @@ msgstr ""
msgid "Mentioned users" msgid "Mentioned users"
msgstr "" msgstr ""
#: src/view/screens/Search/Search.tsx:503 #: src/view/screens/Search/Search.tsx:537
msgid "Menu" msgid "Menu"
msgstr "मेनू" msgstr "मेनू"
#: src/view/com/posts/FeedErrorMessage.tsx:194 #: src/view/com/posts/FeedErrorMessage.tsx:194
#: src/view/screens/ProfileFeed.tsx:490
msgid "Message from server" msgid "Message from server"
msgstr "" msgstr ""
#: src/view/screens/Moderation.tsx:64 #: src/view/screens/Moderation.tsx:64
#: src/view/screens/Settings.tsx:563 #: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:391 #: src/view/shell/desktop/LeftNav.tsx:394
#: src/view/shell/Drawer.tsx:490 #: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:491 #: src/view/shell/Drawer.tsx:491
msgid "Moderation" msgid "Moderation"
@@ -1258,8 +1284,8 @@ msgid "More feeds"
msgstr "अधिक फ़ीड" msgstr "अधिक फ़ीड"
#: src/view/com/profile/ProfileHeader.tsx:548 #: src/view/com/profile/ProfileHeader.tsx:548
#: src/view/screens/ProfileFeed.tsx:370 #: src/view/screens/ProfileFeed.tsx:360
#: src/view/screens/ProfileList.tsx:606 #: src/view/screens/ProfileList.tsx:583
msgid "More options" msgid "More options"
msgstr "अधिक विकल्प" msgstr "अधिक विकल्प"
@@ -1271,15 +1297,15 @@ msgstr "अधिक विकल्प"
msgid "Mute Account" msgid "Mute Account"
msgstr "खाता म्यूट करें" msgstr "खाता म्यूट करें"
#: src/view/screens/ProfileList.tsx:533 #: src/view/screens/ProfileList.tsx:510
msgid "Mute accounts" msgid "Mute accounts"
msgstr "खातों को म्यूट करें" msgstr "खातों को म्यूट करें"
#: src/view/screens/ProfileList.tsx:480 #: src/view/screens/ProfileList.tsx:457
msgid "Mute list" msgid "Mute list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:293 #: src/view/screens/ProfileList.tsx:270
msgid "Mute these accounts?" msgid "Mute these accounts?"
msgstr "इन खातों को म्यूट करें?" msgstr "इन खातों को म्यूट करें?"
@@ -1299,7 +1325,7 @@ msgstr "म्यूट किए गए खाते"
msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private." msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
msgstr "म्यूट किए गए खातों की पोस्ट आपके फ़ीड और आपकी सूचनाओं से हटा दी जाती हैं। म्यूट पूरी तरह से निजी हैं." msgstr "म्यूट किए गए खातों की पोस्ट आपके फ़ीड और आपकी सूचनाओं से हटा दी जाती हैं। म्यूट पूरी तरह से निजी हैं."
#: src/view/screens/ProfileList.tsx:295 #: src/view/screens/ProfileList.tsx:272
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr "म्यूट करना निजी है. म्यूट किए गए खाते आपके साथ इंटरैक्ट कर सकते हैं, लेकिन आप उनकी पोस्ट नहीं देखेंगे या उनसे सूचनाएं प्राप्त नहीं करेंगे।" msgstr "म्यूट करना निजी है. म्यूट किए गए खाते आपके साथ इंटरैक्ट कर सकते हैं, लेकिन आप उनकी पोस्ट नहीं देखेंगे या उनसे सूचनाएं प्राप्त नहीं करेंगे।"
@@ -1337,12 +1363,12 @@ msgstr "अपने फ़ॉलोअर्स और डेटा तक प
msgid "New" msgid "New"
msgstr "नया" msgstr "नया"
#: src/view/com/feeds/FeedPage.tsx:196 #: src/view/com/feeds/FeedPage.tsx:200
#: src/view/screens/Feeds.tsx:510 #: src/view/screens/Feeds.tsx:510
#: src/view/screens/Profile.tsx:389 #: src/view/screens/Profile.tsx:353
#: src/view/screens/ProfileFeed.tsx:451 #: src/view/screens/ProfileFeed.tsx:430
#: src/view/screens/ProfileList.tsx:212 #: src/view/screens/ProfileList.tsx:193
#: src/view/screens/ProfileList.tsx:244 #: src/view/screens/ProfileList.tsx:221
#: src/view/shell/desktop/LeftNav.tsx:246 #: src/view/shell/desktop/LeftNav.tsx:246
msgid "New post" msgid "New post"
msgstr "नई पोस्ट" msgstr "नई पोस्ट"
@@ -1371,8 +1397,8 @@ msgstr "अगली फोटो"
msgid "No" msgid "No"
msgstr "नहीं" msgstr "नहीं"
#: src/view/screens/ProfileFeed.tsx:636 #: src/view/screens/ProfileFeed.tsx:570
#: src/view/screens/ProfileList.tsx:740 #: src/view/screens/ProfileList.tsx:711
msgid "No description" msgid "No description"
msgstr "कोई विवरण नहीं" msgstr "कोई विवरण नहीं"
@@ -1390,9 +1416,9 @@ msgstr "\"{query}\" के लिए कोई परिणाम नहीं
#~ msgstr "{0} के लिए कोई परिणाम नहीं मिला" #~ msgstr "{0} के लिए कोई परिणाम नहीं मिला"
#: src/view/com/modals/ListAddRemoveUsers.tsx:127 #: src/view/com/modals/ListAddRemoveUsers.tsx:127
#: src/view/screens/Search/Search.tsx:270 #: src/view/screens/Search/Search.tsx:271
#: src/view/screens/Search/Search.tsx:298 #: src/view/screens/Search/Search.tsx:299
#: src/view/screens/Search/Search.tsx:581 #: src/view/screens/Search/Search.tsx:615
#: src/view/shell/desktop/Search.tsx:210 #: src/view/shell/desktop/Search.tsx:210
msgid "No results found for {query}" msgid "No results found for {query}"
msgstr "" msgstr ""
@@ -1421,10 +1447,10 @@ msgstr ""
#~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting." #~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Notifications.tsx:108 #: src/view/screens/Notifications.tsx:109
#: src/view/screens/Notifications.tsx:132 #: src/view/screens/Notifications.tsx:133
#: src/view/shell/bottom-bar/BottomBar.tsx:187 #: src/view/shell/bottom-bar/BottomBar.tsx:205
#: src/view/shell/desktop/LeftNav.tsx:355 #: src/view/shell/desktop/LeftNav.tsx:358
#: src/view/shell/Drawer.tsx:416 #: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:417 #: src/view/shell/Drawer.tsx:417
msgid "Notifications" msgid "Notifications"
@@ -1438,7 +1464,7 @@ msgstr "अरे नहीं!"
msgid "Okay" msgid "Okay"
msgstr "ठीक है" msgstr "ठीक है"
#: src/view/com/composer/Composer.tsx:348 #: src/view/com/composer/Composer.tsx:354
msgid "One or more images is missing alt text." msgid "One or more images is missing alt text."
msgstr "एक या अधिक छवियाँ alt पाठ याद आती हैं।।" msgstr "एक या अधिक छवियाँ alt पाठ याद आती हैं।।"
@@ -1446,7 +1472,7 @@ msgstr "एक या अधिक छवियाँ alt पाठ याद
msgid "Only {0} can reply." msgid "Only {0} can reply."
msgstr "" msgstr ""
#: src/view/com/pager/FeedsTabBarMobile.tsx:79 #: src/view/com/pager/FeedsTabBarMobile.tsx:76
msgid "Open navigation" msgid "Open navigation"
msgstr "ओपन नेविगेशन" msgstr "ओपन नेविगेशन"
@@ -1561,13 +1587,13 @@ msgstr "कृपया अपना पासवर्ड भी दर्ज
msgid "Please tell us why you think this decision was incorrect." msgid "Please tell us why you think this decision was incorrect."
msgstr "" msgstr ""
#: src/view/com/composer/Composer.tsx:331 #: src/view/com/composer/Composer.tsx:337
#: src/view/com/post-thread/PostThread.tsx:223 #: src/view/com/post-thread/PostThread.tsx:226
#: src/view/screens/PostThread.tsx:78 #: src/view/screens/PostThread.tsx:80
msgid "Post" msgid "Post"
msgstr "पोस्ट" msgstr "पोस्ट"
#: src/view/com/post-thread/PostThread.tsx:382 #: src/view/com/post-thread/PostThread.tsx:385
msgid "Post hidden" msgid "Post hidden"
msgstr "छुपा पोस्ट" msgstr "छुपा पोस्ट"
@@ -1579,7 +1605,7 @@ msgstr "पोस्ट भाषा"
msgid "Post Languages" msgid "Post Languages"
msgstr "पोस्ट भाषा" msgstr "पोस्ट भाषा"
#: src/view/com/post-thread/PostThread.tsx:434 #: src/view/com/post-thread/PostThread.tsx:437
msgid "Post not found" msgid "Post not found"
msgstr "पोस्ट नहीं मिला" msgstr "पोस्ट नहीं मिला"
@@ -1615,7 +1641,8 @@ msgstr "गोपनीयता नीति"
msgid "Processing..." msgid "Processing..."
msgstr "प्रसंस्करण..." msgstr "प्रसंस्करण..."
#: src/view/shell/bottom-bar/BottomBar.tsx:229 #: src/view/shell/bottom-bar/BottomBar.tsx:247
#: src/view/shell/desktop/LeftNav.tsx:412
#: src/view/shell/Drawer.tsx:69 #: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:525 #: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:526 #: src/view/shell/Drawer.tsx:526
@@ -1682,7 +1709,7 @@ msgstr "फ़ीड हटाएँ"
#: src/view/com/feeds/FeedSourceCard.tsx:105 #: src/view/com/feeds/FeedSourceCard.tsx:105
#: src/view/com/feeds/FeedSourceCard.tsx:172 #: src/view/com/feeds/FeedSourceCard.tsx:172
#: src/view/screens/ProfileFeed.tsx:280 #: src/view/screens/ProfileFeed.tsx:270
msgid "Remove from my feeds" msgid "Remove from my feeds"
msgstr "मेरे फ़ीड से हटाएँ" msgstr "मेरे फ़ीड से हटाएँ"
@@ -1727,11 +1754,11 @@ msgstr "रिपोर्ट {collectionName}"
msgid "Report Account" msgid "Report Account"
msgstr "रिपोर्ट" msgstr "रिपोर्ट"
#: src/view/screens/ProfileFeed.tsx:300 #: src/view/screens/ProfileFeed.tsx:290
msgid "Report feed" msgid "Report feed"
msgstr "रिपोर्ट फ़ीड" msgstr "रिपोर्ट फ़ीड"
#: src/view/screens/ProfileList.tsx:448 #: src/view/screens/ProfileList.tsx:425
msgid "Report List" msgid "Report List"
msgstr "रिपोर्ट सूची" msgstr "रिपोर्ट सूची"
@@ -1843,10 +1870,10 @@ msgstr "सहेजे गए फ़ीड"
#: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/modals/ListAddRemoveUsers.tsx:75
#: src/view/com/util/forms/SearchInput.tsx:64 #: src/view/com/util/forms/SearchInput.tsx:64
#: src/view/screens/Search/Search.tsx:381 #: src/view/screens/Search/Search.tsx:401
#: src/view/screens/Search/Search.tsx:533 #: src/view/screens/Search/Search.tsx:567
#: src/view/shell/bottom-bar/BottomBar.tsx:138 #: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:315 #: src/view/shell/desktop/LeftNav.tsx:321
#: src/view/shell/desktop/Search.tsx:161 #: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170 #: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:343 #: src/view/shell/Drawer.tsx:343
@@ -1855,14 +1882,14 @@ msgid "Search"
msgstr "खोज" msgstr "खोज"
#: src/view/screens/Search/Search.tsx:390 #: src/view/screens/Search/Search.tsx:390
msgid "Search for posts and users." #~ msgid "Search for posts and users."
msgstr "" #~ msgstr ""
#: src/view/com/modals/ChangeEmail.tsx:110 #: src/view/com/modals/ChangeEmail.tsx:110
msgid "Security Step Required" msgid "Security Step Required"
msgstr "सुरक्षा चरण आवश्यक" msgstr "सुरक्षा चरण आवश्यक"
#: src/view/com/auth/SplashScreen.tsx:29 #: src/view/com/auth/HomeLoggedOutCTA.tsx:39
msgid "See what's next" msgid "See what's next"
msgstr "आगे क्या है" msgstr "आगे क्या है"
@@ -1936,7 +1963,7 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "इस सेटिंग को अपने निम्नलिखित फ़ीड में अपने सहेजे गए फ़ीड के नमूने दिखाने के लिए \"हाँ\" पर सेट करें। यह एक प्रयोगात्मक विशेषता है।।" msgstr "इस सेटिंग को अपने निम्नलिखित फ़ीड में अपने सहेजे गए फ़ीड के नमूने दिखाने के लिए \"हाँ\" पर सेट करें। यह एक प्रयोगात्मक विशेषता है।।"
#: src/view/screens/Settings.tsx:277 #: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:427 #: src/view/shell/desktop/LeftNav.tsx:430
#: src/view/shell/Drawer.tsx:546 #: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:547 #: src/view/shell/Drawer.tsx:547
msgid "Settings" msgid "Settings"
@@ -1948,11 +1975,11 @@ msgstr "यौन गतिविधि या कामुक नग्नत
#: src/view/com/profile/ProfileHeader.tsx:338 #: src/view/com/profile/ProfileHeader.tsx:338
#: src/view/com/util/forms/PostDropdownBtn.tsx:129 #: src/view/com/util/forms/PostDropdownBtn.tsx:129
#: src/view/screens/ProfileList.tsx:407 #: src/view/screens/ProfileList.tsx:384
msgid "Share" msgid "Share"
msgstr "शेयर" msgstr "शेयर"
#: src/view/screens/ProfileFeed.tsx:312 #: src/view/screens/ProfileFeed.tsx:302
msgid "Share feed" msgid "Share feed"
msgstr "" msgstr ""
@@ -1960,11 +1987,12 @@ msgstr ""
#~ msgid "Share link" #~ msgid "Share link"
#~ msgstr "लिंक शेयर करें" #~ msgstr "लिंक शेयर करें"
#: src/view/com/util/moderation/ContentHider.tsx:105
#: src/view/screens/Settings.tsx:316 #: src/view/screens/Settings.tsx:316
msgid "Show" msgid "Show"
msgstr "दिखाओ" msgstr "दिखाओ"
#: src/view/com/util/moderation/ScreenHider.tsx:114 #: src/view/com/util/moderation/ScreenHider.tsx:132
msgid "Show anyway" msgid "Show anyway"
msgstr "दिखाओ" msgstr "दिखाओ"
@@ -1992,15 +2020,23 @@ msgstr "रीपोस्ट दिखाएँ"
msgid "Show users" msgid "Show users"
msgstr "लोग दिखाएँ" msgstr "लोग दिखाएँ"
#: src/view/com/auth/HomeLoggedOutCTA.tsx:70
#: src/view/com/auth/login/Login.tsx:98 #: src/view/com/auth/login/Login.tsx:98
#: src/view/com/auth/SplashScreen.tsx:49 #: src/view/com/auth/SplashScreen.tsx:54
#: src/view/shell/NavSignupCard.tsx:52 #: src/view/shell/bottom-bar/BottomBar.tsx:285
#: src/view/shell/NavSignupCard.tsx:53 #: src/view/shell/bottom-bar/BottomBar.tsx:286
#: src/view/shell/bottom-bar/BottomBar.tsx:288
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:177
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:178
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:180
#: src/view/shell/NavSignupCard.tsx:58
#: src/view/shell/NavSignupCard.tsx:59
msgid "Sign in" msgid "Sign in"
msgstr "साइन इन करें" msgstr "साइन इन करें"
#: src/view/com/auth/SplashScreen.tsx:52 #: src/view/com/auth/HomeLoggedOutCTA.tsx:78
#: src/view/com/auth/SplashScreen.web.tsx:84 #: src/view/com/auth/SplashScreen.tsx:57
#: src/view/com/auth/SplashScreen.web.tsx:87
msgid "Sign In" msgid "Sign In"
msgstr "साइन इन करें" msgstr "साइन इन करें"
@@ -2022,16 +2058,26 @@ msgstr "साइन इन करें"
msgid "Sign out" msgid "Sign out"
msgstr "साइन आउट" msgstr "साइन आउट"
#: src/view/shell/NavSignupCard.tsx:43 #: src/view/shell/bottom-bar/BottomBar.tsx:275
#: src/view/shell/NavSignupCard.tsx:44 #: src/view/shell/bottom-bar/BottomBar.tsx:276
#: src/view/shell/NavSignupCard.tsx:46 #: src/view/shell/bottom-bar/BottomBar.tsx:278
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:167
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:168
#: src/view/shell/bottom-bar/BottomBarWeb.tsx:170
#: src/view/shell/NavSignupCard.tsx:49
#: src/view/shell/NavSignupCard.tsx:50
#: src/view/shell/NavSignupCard.tsx:52
msgid "Sign up" msgid "Sign up"
msgstr "" msgstr ""
#: src/view/shell/NavSignupCard.tsx:36 #: src/view/shell/NavSignupCard.tsx:42
msgid "Sign up or sign in to join the conversation" msgid "Sign up or sign in to join the conversation"
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:76
msgid "Sign-in Required"
msgstr ""
#: src/view/screens/Settings.tsx:327 #: src/view/screens/Settings.tsx:327
msgid "Signed in as" msgid "Signed in as"
msgstr "आपने इस रूप में साइन इन करा है:" msgstr "आपने इस रूप में साइन इन करा है:"
@@ -2069,15 +2115,15 @@ msgstr "Storybook"
msgid "Submit" msgid "Submit"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:597 #: src/view/screens/ProfileList.tsx:574
msgid "Subscribe" msgid "Subscribe"
msgstr "सब्सक्राइब" msgstr "सब्सक्राइब"
#: src/view/screens/ProfileList.tsx:593 #: src/view/screens/ProfileList.tsx:570
msgid "Subscribe to this list" msgid "Subscribe to this list"
msgstr "इस सूची को सब्सक्राइब करें" msgstr "इस सूची को सब्सक्राइब करें"
#: src/view/screens/Search/Search.tsx:354 #: src/view/screens/Search/Search.tsx:357
msgid "Suggested Follows" msgid "Suggested Follows"
msgstr "अनुशंसित लोग" msgstr "अनुशंसित लोग"
@@ -2127,7 +2173,7 @@ msgstr "सामुदायिक दिशानिर्देशों क
msgid "The Copyright Policy has been moved to <0/>" msgid "The Copyright Policy has been moved to <0/>"
msgstr "कॉपीराइट नीति को <0/> पर स्थानांतरित कर दिया गया है" msgstr "कॉपीराइट नीति को <0/> पर स्थानांतरित कर दिया गया है"
#: src/view/com/post-thread/PostThread.tsx:437 #: src/view/com/post-thread/PostThread.tsx:440
msgid "The post may have been deleted." msgid "The post may have been deleted."
msgstr "हो सकता है कि यह पोस्ट हटा दी गई हो।" msgstr "हो सकता है कि यह पोस्ट हटा दी गई हो।"
@@ -2151,10 +2197,14 @@ msgstr "एप्लिकेशन में एक अप्रत्याश
msgid "This {0} has been labeled." msgid "This {0} has been labeled."
msgstr "" msgstr ""
#: src/view/com/util/moderation/ScreenHider.tsx:72 #: src/view/com/util/moderation/ScreenHider.tsx:88
msgid "This {screenDescription} has been flagged:" msgid "This {screenDescription} has been flagged:"
msgstr "यह {screenDescription} फ्लैग किया गया है:" msgstr "यह {screenDescription} फ्लैग किया गया है:"
#: src/view/com/util/moderation/ScreenHider.tsx:83
msgid "This account has requested that users sign in to view their profile."
msgstr ""
#: src/view/com/posts/FeedErrorMessage.tsx:107 #: src/view/com/posts/FeedErrorMessage.tsx:107
msgid "This content is not viewable without a Bluesky account." msgid "This content is not viewable without a Bluesky account."
msgstr "" msgstr ""
@@ -2214,11 +2264,11 @@ msgstr "अनुवाद"
msgid "Try again" msgid "Try again"
msgstr "फिर से कोशिश करो" msgstr "फिर से कोशिश करो"
#: src/view/screens/ProfileList.tsx:495 #: src/view/screens/ProfileList.tsx:472
msgid "Un-block list" msgid "Un-block list"
msgstr "" msgstr ""
#: src/view/screens/ProfileList.tsx:480 #: src/view/screens/ProfileList.tsx:457
msgid "Un-mute list" msgid "Un-mute list"
msgstr "" msgstr ""
@@ -2254,7 +2304,7 @@ msgstr "अनम्यूट खाता"
msgid "Unmute thread" msgid "Unmute thread"
msgstr "थ्रेड को अनम्यूट करें" msgstr "थ्रेड को अनम्यूट करें"
#: src/view/screens/ProfileList.tsx:463 #: src/view/screens/ProfileList.tsx:440
msgid "Unpin moderation list" msgid "Unpin moderation list"
msgstr "" msgstr ""
@@ -2303,7 +2353,7 @@ msgstr "लोग सूचियाँ"
msgid "Username or email address" msgid "Username or email address"
msgstr "यूजर नाम या ईमेल पता" msgstr "यूजर नाम या ईमेल पता"
#: src/view/screens/ProfileList.tsx:767 #: src/view/screens/ProfileList.tsx:738
msgid "Users" msgid "Users"
msgstr "यूजर लोग" msgstr "यूजर लोग"
@@ -2360,7 +2410,7 @@ msgstr "हम आपके हमारी सेवा में शामि
#~ msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later." #~ msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Search/Search.tsx:237 #: src/view/screens/Search/Search.tsx:238
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
msgstr "" msgstr ""
@@ -2376,6 +2426,10 @@ msgstr "<0>Bluesky</0> में आपका स्वागत है"
msgid "What is the issue with this {collectionName}?" msgid "What is the issue with this {collectionName}?"
msgstr "इस {collectionName} के साथ क्या मुद्दा है?" msgstr "इस {collectionName} के साथ क्या मुद्दा है?"
#: src/view/com/auth/SplashScreen.tsx:34
msgid "What's up?"
msgstr ""
#: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:78 #: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:78
msgid "Which languages are used in this post?" msgid "Which languages are used in this post?"
msgstr "इस पोस्ट में किस भाषा का उपयोग किया जाता है?" msgstr "इस पोस्ट में किस भाषा का उपयोग किया जाता है?"
@@ -2397,7 +2451,7 @@ msgstr ""
msgid "Wide" msgid "Wide"
msgstr "चौड़ा" msgstr "चौड़ा"
#: src/view/com/composer/Composer.tsx:403 #: src/view/com/composer/Composer.tsx:409
msgid "Write post" msgid "Write post"
msgstr "पोस्ट लिखो" msgstr "पोस्ट लिखो"
@@ -2436,16 +2490,16 @@ msgstr ""
msgid "You don't have any saved feeds." msgid "You don't have any saved feeds."
msgstr "आपके पास कोई सहेजी गई फ़ीड नहीं है." msgstr "आपके पास कोई सहेजी गई फ़ीड नहीं है."
#: src/view/com/post-thread/PostThread.tsx:385 #: src/view/com/post-thread/PostThread.tsx:388
msgid "You have blocked the author or you have been blocked by the author." msgid "You have blocked the author or you have been blocked by the author."
msgstr "आपने लेखक को अवरुद्ध किया है या आपने लेखक द्वारा अवरुद्ध किया है।।" msgstr "आपने लेखक को अवरुद्ध किया है या आपने लेखक द्वारा अवरुद्ध किया है।।"
#: src/view/com/feeds/ProfileFeedgens.tsx:154 #: src/view/com/feeds/ProfileFeedgens.tsx:141
msgid "You have no feeds." msgid "You have no feeds."
msgstr "" msgstr ""
#: src/view/com/lists/MyLists.tsx:89 #: src/view/com/lists/MyLists.tsx:89
#: src/view/com/lists/ProfileLists.tsx:158 #: src/view/com/lists/ProfileLists.tsx:145
msgid "You have no lists." msgid "You have no lists."
msgstr "आपके पास कोई सूची नहीं है।।" msgstr "आपके पास कोई सूची नहीं है।।"
File diff suppressed because it is too large Load Diff
+38 -5
View File
@@ -1,16 +1,27 @@
import React from 'react' import React from 'react'
import {AppBskyActorDefs} from '@atproto/api' import {AppBskyActorDefs, ModerationOpts, moderateProfile} from '@atproto/api'
import {useQuery, useQueryClient} from '@tanstack/react-query' import {useQuery, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger' import {logger} from '#/logger'
import {getAgent} from '#/state/session' import {getAgent} from '#/state/session'
import {useMyFollowsQuery} from '#/state/queries/my-follows' import {useMyFollowsQuery} from '#/state/queries/my-follows'
import {STALE} from '#/state/queries' import {STALE} from '#/state/queries'
import {
DEFAULT_LOGGED_OUT_PREFERENCES,
getModerationOpts,
useModerationOpts,
} from './preferences'
const DEFAULT_MOD_OPTS = getModerationOpts({
userDid: '',
preferences: DEFAULT_LOGGED_OUT_PREFERENCES,
})
export const RQKEY = (prefix: string) => ['actor-autocomplete', prefix] export const RQKEY = (prefix: string) => ['actor-autocomplete', prefix]
export function useActorAutocompleteQuery(prefix: string) { export function useActorAutocompleteQuery(prefix: string) {
const {data: follows, isFetching} = useMyFollowsQuery() const {data: follows, isFetching} = useMyFollowsQuery()
const moderationOpts = useModerationOpts()
return useQuery<AppBskyActorDefs.ProfileViewBasic[]>({ return useQuery<AppBskyActorDefs.ProfileViewBasic[]>({
staleTime: STALE.MINUTES.ONE, staleTime: STALE.MINUTES.ONE,
@@ -22,9 +33,20 @@ export function useActorAutocompleteQuery(prefix: string) {
limit: 8, limit: 8,
}) })
: undefined : undefined
return computeSuggestions(prefix, follows, res?.data.actors) return res?.data.actors || []
}, },
enabled: !isFetching, enabled: !isFetching,
select: React.useCallback(
(data: AppBskyActorDefs.ProfileViewBasic[]) => {
return computeSuggestions(
prefix,
follows,
data,
moderationOpts || DEFAULT_MOD_OPTS,
)
},
[prefix, follows, moderationOpts],
),
}) })
} }
@@ -32,6 +54,7 @@ export type ActorAutocompleteFn = ReturnType<typeof useActorAutocompleteFn>
export function useActorAutocompleteFn() { export function useActorAutocompleteFn() {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {data: follows} = useMyFollowsQuery() const {data: follows} = useMyFollowsQuery()
const moderationOpts = useModerationOpts()
return React.useCallback( return React.useCallback(
async ({query, limit = 8}: {query: string; limit?: number}) => { async ({query, limit = 8}: {query: string; limit?: number}) => {
@@ -54,9 +77,14 @@ export function useActorAutocompleteFn() {
} }
} }
return computeSuggestions(query, follows, res?.data.actors) return computeSuggestions(
query,
follows,
res?.data.actors,
moderationOpts || DEFAULT_MOD_OPTS,
)
}, },
[follows, queryClient], [follows, queryClient, moderationOpts],
) )
} }
@@ -64,6 +92,7 @@ function computeSuggestions(
prefix: string, prefix: string,
follows: AppBskyActorDefs.ProfileViewBasic[] | undefined, follows: AppBskyActorDefs.ProfileViewBasic[] | undefined,
searched: AppBskyActorDefs.ProfileViewBasic[] = [], searched: AppBskyActorDefs.ProfileViewBasic[] = [],
moderationOpts: ModerationOpts,
) { ) {
let items: AppBskyActorDefs.ProfileViewBasic[] = [] let items: AppBskyActorDefs.ProfileViewBasic[] = []
if (follows) { if (follows) {
@@ -76,10 +105,14 @@ function computeSuggestions(
handle: item.handle, handle: item.handle,
displayName: item.displayName, displayName: item.displayName,
avatar: item.avatar, avatar: item.avatar,
labels: item.labels,
}) })
} }
} }
return items return items.filter(profile => {
const mod = moderateProfile(profile, moderationOpts)
return !mod.account.filter
})
} }
function prefixMatch( function prefixMatch(
-45
View File
@@ -161,51 +161,6 @@ export function useFeedSourceInfoQuery({uri}: {uri: string}) {
}) })
} }
export const isFeedPublicQueryKey = ({uri}: {uri: string}) => [
'isFeedPublic',
uri,
]
export function useIsFeedPublicQuery({uri}: {uri: string}) {
return useQuery({
queryKey: isFeedPublicQueryKey({uri}),
queryFn: async ({queryKey}) => {
const [, uri] = queryKey
try {
const res = await getAgent().app.bsky.feed.getFeed({
feed: uri,
limit: 1,
})
return {
isPublic: Boolean(res.data.feed),
error: undefined,
}
} catch (e: any) {
/**
* This should be an `XRPCError`, but I can't safely import from
* `@atproto/xrpc` due to a depdency on node's `crypto` module.
*
* @see https://github.com/bluesky-social/atproto/blob/c17971a2d8e424cc7f10c071d97c07c08aa319cf/packages/xrpc/src/client.ts#L126
*/
if (e?.status === 401) {
return {
isPublic: false,
error: e,
}
}
/*
* Non-401 response means something else went wrong on the server
*/
return {
isPublic: true,
error: e,
}
}
},
})
}
export const useGetPopularFeedsQueryKey = ['getPopularFeeds'] export const useGetPopularFeedsQueryKey = ['getPopularFeeds']
export function useGetPopularFeedsQuery() { export function useGetPopularFeedsQuery() {
+18 -15
View File
@@ -16,7 +16,7 @@
* 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead. * 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
*/ */
import {useEffect} from 'react' import {useEffect, useRef} from 'react'
import {AppBskyFeedDefs} from '@atproto/api' import {AppBskyFeedDefs} from '@atproto/api'
import { import {
useInfiniteQuery, useInfiniteQuery,
@@ -49,6 +49,7 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
const threadMutes = useMutedThreads() const threadMutes = useMutedThreads()
const unreads = useUnreadNotificationsApi() const unreads = useUnreadNotificationsApi()
const enabled = opts?.enabled !== false const enabled = opts?.enabled !== false
const lastPageCountRef = useRef(0)
const query = useInfiniteQuery< const query = useInfiniteQuery<
FeedPage, FeedPage,
@@ -104,24 +105,26 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
useEffect(() => { useEffect(() => {
const {isFetching, hasNextPage, data} = query const {isFetching, hasNextPage, data} = query
if (isFetching || !hasNextPage) {
let count = 0 return
let numEmpties = 0
for (const page of data?.pages || []) {
if (!page.items.length) {
numEmpties++
} }
// avoid double-fires of fetchNextPage()
if (
lastPageCountRef.current !== 0 &&
lastPageCountRef.current === data?.pages?.length
) {
return
}
// fetch next page if we haven't gotten a full page of content
let count = 0
for (const page of data?.pages || []) {
count += page.items.length count += page.items.length
} }
if (count < PAGE_SIZE && (data?.pages.length || 0) < 6) {
if (
!isFetching &&
hasNextPage &&
count < PAGE_SIZE &&
numEmpties < 3 &&
(data?.pages.length || 0) < 6
) {
query.fetchNextPage() query.fetchNextPage()
lastPageCountRef.current = data?.pages?.length || 0
} }
}, [query]) }, [query])
+26 -16
View File
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect} from 'react' import React, {useCallback, useEffect, useRef} from 'react'
import { import {
AppBskyFeedDefs, AppBskyFeedDefs,
AppBskyFeedPost, AppBskyFeedPost,
@@ -78,6 +78,7 @@ export interface FeedPageUnselected {
api: FeedAPI api: FeedAPI
cursor: string | undefined cursor: string | undefined
feed: AppBskyFeedDefs.FeedViewPost[] feed: AppBskyFeedDefs.FeedViewPost[]
fetchedAt: number
} }
export interface FeedPage { export interface FeedPage {
@@ -85,6 +86,7 @@ export interface FeedPage {
tuner: FeedTuner | NoopFeedTuner tuner: FeedTuner | NoopFeedTuner
cursor: string | undefined cursor: string | undefined
slices: FeedPostSlice[] slices: FeedPostSlice[]
fetchedAt: number
} }
const PAGE_SIZE = 30 const PAGE_SIZE = 30
@@ -98,11 +100,12 @@ export function usePostFeedQuery(
const feedTuners = useFeedTuners(feedDesc) const feedTuners = useFeedTuners(feedDesc)
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const enabled = opts?.enabled !== false && Boolean(moderationOpts) const enabled = opts?.enabled !== false && Boolean(moderationOpts)
const lastRun = React.useRef<{ const lastRun = useRef<{
data: InfiniteData<FeedPageUnselected> data: InfiniteData<FeedPageUnselected>
args: typeof selectArgs args: typeof selectArgs
result: InfiniteData<FeedPage> result: InfiniteData<FeedPage>
} | null>(null) } | null>(null)
const lastPageCountRef = useRef(0)
// Make sure this doesn't invalidate unless really needed. // Make sure this doesn't invalidate unless really needed.
const selectArgs = React.useMemo( const selectArgs = React.useMemo(
@@ -152,6 +155,7 @@ export function usePostFeedQuery(
api, api,
cursor: res.cursor, cursor: res.cursor,
feed: res.feed, feed: res.feed,
fetchedAt: Date.now(),
} }
}, },
initialPageParam: undefined, initialPageParam: undefined,
@@ -214,6 +218,7 @@ export function usePostFeedQuery(
api: page.api, api: page.api,
tuner, tuner,
cursor: page.cursor, cursor: page.cursor,
fetchedAt: page.fetchedAt,
slices: tuner slices: tuner
.tune(page.feed) .tune(page.feed)
.map(slice => { .map(slice => {
@@ -279,26 +284,28 @@ export function usePostFeedQuery(
useEffect(() => { useEffect(() => {
const {isFetching, hasNextPage, data} = query const {isFetching, hasNextPage, data} = query
if (isFetching || !hasNextPage) {
let count = 0 return
let numEmpties = 0
for (const page of data?.pages || []) {
if (page.slices.length === 0) {
numEmpties++
} }
// avoid double-fires of fetchNextPage()
if (
lastPageCountRef.current !== 0 &&
lastPageCountRef.current === data?.pages?.length
) {
return
}
// fetch next page if we haven't gotten a full page of content
let count = 0
for (const page of data?.pages || []) {
for (const slice of page.slices) { for (const slice of page.slices) {
count += slice.items.length count += slice.items.length
} }
} }
if (count < PAGE_SIZE && (data?.pages.length || 0) < 6) {
if (
!isFetching &&
hasNextPage &&
count < PAGE_SIZE &&
numEmpties < 3 &&
(data?.pages.length || 0) < 6
) {
query.fetchNextPage() query.fetchNextPage()
lastPageCountRef.current = data?.pages?.length || 0
} }
}, [query]) }, [query])
@@ -409,6 +416,9 @@ export function* findAllPostsInQueryData(
} }
function assertSomePostsPassModeration(feed: AppBskyFeedDefs.FeedViewPost[]) { function assertSomePostsPassModeration(feed: AppBskyFeedDefs.FeedViewPost[]) {
// no posts in this feed
if (feed.length === 0) return true
// assume false // assume false
let somePostsPassModeration = false let somePostsPassModeration = false
+1 -3
View File
@@ -35,9 +35,7 @@ export function useProfileQuery({did}: {did: string | undefined}) {
// if you remove it, the UI infinite-loops // if you remove it, the UI infinite-loops
// -prf // -prf
staleTime: isCurrentAccount ? STALE.SECONDS.THIRTY : STALE.MINUTES.FIVE, staleTime: isCurrentAccount ? STALE.SECONDS.THIRTY : STALE.MINUTES.FIVE,
refetchInterval: isCurrentAccount refetchInterval: STALE.MINUTES.FIVE,
? STALE.SECONDS.THIRTY
: STALE.MINUTES.FIVE,
queryKey: RQKEY(did || ''), queryKey: RQKEY(did || ''),
queryFn: async () => { queryFn: async () => {
const res = await getAgent().getProfile({actor: did || ''}) const res = await getAgent().getProfile({actor: did || ''})
+1 -1
View File
@@ -22,7 +22,7 @@ type Controls = {
/** /**
* The did of the account to populate the login form with. * The did of the account to populate the login form with.
*/ */
requestedAccount?: string requestedAccount?: string | 'none' | 'new'
}) => void }) => void
/** /**
* Clears the requested account so that next time the logged out view is * Clears the requested account so that next time the logged out view is
+165
View File
@@ -0,0 +1,165 @@
import React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {useLingui} from '@lingui/react'
import {Trans, msg} from '@lingui/macro'
import {ScrollView} from '../util/Views'
import {Text} from '../util/text/Text'
import {usePalette} from '#/lib/hooks/usePalette'
import {colors, s} from '#/lib/styles'
import {TextLink} from '../util/Link'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
export function HomeLoggedOutCTA() {
const pal = usePalette('default')
const {_} = useLingui()
const {isMobile} = useWebMediaQueries()
const {requestSwitchToAccount} = useLoggedOutViewControls()
const showCreateAccount = React.useCallback(() => {
requestSwitchToAccount({requestedAccount: 'new'})
}, [requestSwitchToAccount])
const showSignIn = React.useCallback(() => {
requestSwitchToAccount({requestedAccount: 'none'})
}, [requestSwitchToAccount])
return (
<ScrollView style={styles.container} testID="loggedOutCTA">
<View style={[styles.hero, isMobile && styles.heroMobile]}>
<Text style={[styles.title, pal.link]}>
<Trans>Bluesky</Trans>
</Text>
<Text
style={[
styles.subtitle,
isMobile && styles.subtitleMobile,
pal.textLight,
]}>
<Trans>See what's next</Trans>
</Text>
</View>
<View
testID="signinOrCreateAccount"
style={isMobile ? undefined : styles.btnsDesktop}>
<TouchableOpacity
testID="createAccountButton"
style={[
styles.btn,
isMobile && styles.btnMobile,
{backgroundColor: colors.blue3},
]}
onPress={showCreateAccount}
accessibilityRole="button"
accessibilityLabel={_(msg`Create new account`)}
accessibilityHint="Opens flow to create a new Bluesky account">
<Text
style={[
s.white,
styles.btnLabel,
isMobile && styles.btnLabelMobile,
]}>
<Trans>Create a new account</Trans>
</Text>
</TouchableOpacity>
<TouchableOpacity
testID="signInButton"
style={[styles.btn, isMobile && styles.btnMobile, pal.btn]}
onPress={showSignIn}
accessibilityRole="button"
accessibilityLabel={_(msg`Sign in`)}
accessibilityHint="Opens flow to sign into your existing Bluesky account">
<Text
style={[
pal.text,
styles.btnLabel,
isMobile && styles.btnLabelMobile,
]}>
<Trans>Sign In</Trans>
</Text>
</TouchableOpacity>
</View>
<View style={[styles.footer, pal.view, pal.border]}>
<TextLink
type="2xl"
href="https://blueskyweb.xyz"
text={_(msg`Business`)}
style={[styles.footerLink, pal.link]}
/>
<TextLink
type="2xl"
href="https://blueskyweb.xyz/blog"
text={_(msg`Blog`)}
style={[styles.footerLink, pal.link]}
/>
<TextLink
type="2xl"
href="https://blueskyweb.xyz/join"
text={_(msg`Jobs`)}
style={[styles.footerLink, pal.link]}
/>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container: {
height: '100%',
},
hero: {
justifyContent: 'center',
paddingTop: 100,
paddingBottom: 30,
},
heroMobile: {
paddingBottom: 50,
},
title: {
textAlign: 'center',
fontSize: 68,
fontWeight: 'bold',
},
subtitle: {
textAlign: 'center',
fontSize: 48,
fontWeight: 'bold',
},
subtitleMobile: {
fontSize: 42,
},
btnsDesktop: {
flexDirection: 'row',
justifyContent: 'center',
gap: 20,
marginHorizontal: 20,
},
btn: {
borderRadius: 32,
width: 230,
paddingVertical: 12,
marginBottom: 20,
},
btnMobile: {
flex: 1,
width: 'auto',
marginHorizontal: 20,
paddingVertical: 16,
},
btnLabel: {
textAlign: 'center',
fontSize: 18,
},
btnLabelMobile: {
textAlign: 'center',
fontSize: 21,
},
footer: {
flexDirection: 'row',
gap: 20,
justifyContent: 'center',
},
footerLink: {},
})
+3 -1
View File
@@ -33,7 +33,9 @@ export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
const {requestedAccountSwitchTo} = useLoggedOutView() const {requestedAccountSwitchTo} = useLoggedOutView()
const [screenState, setScreenState] = React.useState<ScreenState>( const [screenState, setScreenState] = React.useState<ScreenState>(
requestedAccountSwitchTo requestedAccountSwitchTo
? ScreenState.S_Login ? requestedAccountSwitchTo === 'new'
? ScreenState.S_CreateAccount
: ScreenState.S_Login
: ScreenState.S_LoginOrCreateAccount, : ScreenState.S_LoginOrCreateAccount,
) )
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
+11 -5
View File
@@ -7,6 +7,8 @@ import {usePalette} from 'lib/hooks/usePalette'
import {CenteredView} from '../util/Views' import {CenteredView} from '../util/Views'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
export const SplashScreen = ({ export const SplashScreen = ({
onPressSignin, onPressSignin,
@@ -22,11 +24,14 @@ export const SplashScreen = ({
<CenteredView style={[styles.container, pal.view]}> <CenteredView style={[styles.container, pal.view]}>
<ErrorBoundary> <ErrorBoundary>
<View style={styles.hero}> <View style={styles.hero}>
<Text style={[styles.title, pal.link]}> <Logo width={92} fill="sky" />
<Trans>Bluesky</Trans>
</Text> <View style={{paddingTop: 40, paddingBottom: 6}}>
<Text style={[styles.subtitle, pal.textLight]}> <Logotype width={161} fill={pal.text.color} />
<Trans>See what's next</Trans> </View>
<Text type="lg-medium" style={[pal.textLight]}>
<Trans>What's up?</Trans>
</Text> </Text>
</View> </View>
<View testID="signinOrCreateAccount" style={styles.btns}> <View testID="signinOrCreateAccount" style={styles.btns}>
@@ -65,6 +70,7 @@ const styles = StyleSheet.create({
hero: { hero: {
flex: 2, flex: 2,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center',
}, },
btns: { btns: {
paddingBottom: 40, paddingBottom: 40,
+10 -10
View File
@@ -10,6 +10,8 @@ import {CenteredView} from '../util/Views'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
export const SplashScreen = ({ export const SplashScreen = ({
onDismiss, onDismiss,
@@ -55,14 +57,15 @@ export const SplashScreen = ({
styles.containerInner, styles.containerInner,
isMobileWeb && styles.containerInnerMobile, isMobileWeb && styles.containerInnerMobile,
pal.border, pal.border,
{alignItems: 'center'},
]}> ]}>
<ErrorBoundary> <ErrorBoundary>
<Text style={isMobileWeb ? styles.titleMobile : styles.title}> <Logo width={92} fill="sky" />
Bluesky
</Text> <View style={{paddingTop: 40, paddingBottom: 20}}>
<Text style={isMobileWeb ? styles.subtitleMobile : styles.subtitle}> <Logotype width={161} fill={pal.text.color} />
See what's next </View>
</Text>
<View testID="signinOrCreateAccount" style={styles.btns}> <View testID="signinOrCreateAccount" style={styles.btns}>
<TouchableOpacity <TouchableOpacity
testID="createAccountButton" testID="createAccountButton"
@@ -117,8 +120,6 @@ function Footer({styles}: {styles: ReturnType<typeof useStyles>}) {
) )
} }
const useStyles = () => { const useStyles = () => {
const {isTabletOrMobile} = useWebMediaQueries()
const isMobileWeb = isWeb && isTabletOrMobile
return StyleSheet.create({ return StyleSheet.create({
container: { container: {
height: '100%', height: '100%',
@@ -161,8 +162,7 @@ const useStyles = () => {
paddingBottom: 30, paddingBottom: 30,
}, },
btns: { btns: {
flexDirection: isMobileWeb ? 'column' : 'row', gap: 10,
gap: 20,
justifyContent: 'center', justifyContent: 'center',
paddingBottom: 40, paddingBottom: 40,
}, },
+6
View File
@@ -62,6 +62,7 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {emitPostCreated} from '#/state/events' import {emitPostCreated} from '#/state/events'
import {ThreadgateSetting} from '#/state/queries/threadgate' import {ThreadgateSetting} from '#/state/queries/threadgate'
import {logger} from '#/logger'
type Props = ComposerOpts type Props = ComposerOpts
export const ComposePost = observer(function ComposePost({ export const ComposePost = observer(function ComposePost({
@@ -228,6 +229,11 @@ export const ComposePost = observer(function ComposePost({
}) })
).uri ).uri
} catch (e: any) { } catch (e: any) {
logger.error(e, {
message: `Composer: create post failed`,
hasImages: gallery.size > 0,
})
if (extLink) { if (extLink) {
setExtLink({ setExtLink({
...extLink, ...extLink,
+13 -9
View File
@@ -7,13 +7,15 @@ import {useNavigation} from '@react-navigation/native'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {MainScrollProvider} from '../util/MainScrollProvider'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useSetMinimalShellMode} from '#/state/shell'
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
import {ComposeIcon2} from 'lib/icons' import {ComposeIcon2} from 'lib/icons'
import {colors, s} from 'lib/styles' import {colors, s} from 'lib/styles'
import {FlatList, View, useWindowDimensions} from 'react-native' import {View, useWindowDimensions} from 'react-native'
import {ListMethods} from '../util/List'
import {Feed} from '../posts/Feed' import {Feed} from '../posts/Feed'
import {TextLink} from '../util/Link' import {TextLink} from '../util/Link'
import {FAB} from '../util/fab/FAB' import {FAB} from '../util/fab/FAB'
@@ -27,7 +29,7 @@ import {truncateAndInvalidate} from '#/state/queries/util'
import {TabState, getTabState, getRootNavigation} from '#/lib/routes/helpers' import {TabState, getTabState, getRootNavigation} from '#/lib/routes/helpers'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
const POLL_FREQ = 30e3 // 30sec const POLL_FREQ = 60e3 // 60sec
export function FeedPage({ export function FeedPage({
testID, testID,
@@ -51,10 +53,11 @@ export function FeedPage({
const {isDesktop} = useWebMediaQueries() const {isDesktop} = useWebMediaQueries()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const setMinimalShellMode = useSetMinimalShellMode()
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
const headerOffset = useHeaderOffset() const headerOffset = useHeaderOffset()
const scrollElRef = React.useRef<FlatList>(null) const scrollElRef = React.useRef<ListMethods>(null)
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const scrollToTop = React.useCallback(() => { const scrollToTop = React.useCallback(() => {
@@ -62,8 +65,8 @@ export function FeedPage({
animated: isNative, animated: isNative,
offset: -headerOffset, offset: -headerOffset,
}) })
resetMainScroll() setMinimalShellMode(false)
}, [headerOffset, resetMainScroll]) }, [headerOffset, setMinimalShellMode])
const onSoftReset = React.useCallback(() => { const onSoftReset = React.useCallback(() => {
const isScreenFocused = const isScreenFocused =
@@ -164,6 +167,7 @@ export function FeedPage({
return ( return (
<View testID={testID} style={s.h100pct}> <View testID={testID} style={s.h100pct}>
<MainScrollProvider>
<Feed <Feed
testID={testID ? `${testID}-feed` : undefined} testID={testID ? `${testID}-feed` : undefined}
enabled={isPageFocused} enabled={isPageFocused}
@@ -171,14 +175,14 @@ export function FeedPage({
feedParams={feedParams} feedParams={feedParams}
pollInterval={POLL_FREQ} pollInterval={POLL_FREQ}
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onScroll={onMainScroll} onScrolledDownChange={setIsScrolledDown}
onHasNew={setHasNew} onHasNew={setHasNew}
scrollEventThrottle={1}
renderEmptyState={renderEmptyState} renderEmptyState={renderEmptyState}
renderEndOfFeed={renderEndOfFeed} renderEndOfFeed={renderEndOfFeed}
ListHeaderComponent={ListHeaderComponent} ListHeaderComponent={ListHeaderComponent}
headerOffset={headerOffset} headerOffset={headerOffset}
/> />
</MainScrollProvider>
{(isScrolledDown || hasNew) && ( {(isScrolledDown || hasNew) && (
<LoadLatestBtn <LoadLatestBtn
onPress={onPressLoadLatest} onPress={onPressLoadLatest}
+5 -21
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
Dimensions, Dimensions,
RefreshControl, RefreshControl,
@@ -8,18 +8,16 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {FeedSourceCardLoaded} from './FeedSourceCard' import {FeedSourceCardLoaded} from './FeedSourceCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens' import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens'
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
import {logger} from '#/logger' import {logger} from '#/logger'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {useTheme} from '#/lib/ThemeContext' import {useTheme} from '#/lib/ThemeContext'
import {usePreferencesQuery} from '#/state/queries/preferences' import {usePreferencesQuery} from '#/state/queries/preferences'
import {hydrateFeedGenerator} from '#/state/queries/feed' import {hydrateFeedGenerator} from '#/state/queries/feed'
@@ -37,9 +35,7 @@ interface SectionRef {
interface ProfileFeedgensProps { interface ProfileFeedgensProps {
did: string did: string
scrollElRef: MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
onScroll?: OnScrollHandler
scrollEventThrottle?: number
headerOffset: number headerOffset: number
enabled?: boolean enabled?: boolean
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
@@ -50,16 +46,7 @@ export const ProfileFeedgens = React.forwardRef<
SectionRef, SectionRef,
ProfileFeedgensProps ProfileFeedgensProps
>(function ProfileFeedgensImpl( >(function ProfileFeedgensImpl(
{ {did, scrollElRef, headerOffset, enabled, style, testID},
did,
scrollElRef,
onScroll,
scrollEventThrottle,
headerOffset,
enabled,
style,
testID,
},
ref, ref,
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
@@ -185,10 +172,9 @@ export const ProfileFeedgens = React.forwardRef<
[error, refetch, onPressRetryLoadMore, pal, preferences], [error, refetch, onPressRetryLoadMore, pal, preferences],
) )
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
@@ -207,8 +193,6 @@ export const ProfileFeedgens = React.forwardRef<
minHeight: Dimensions.get('window').height * 1.5, minHeight: Dimensions.get('window').height * 1.5,
}} }}
style={{paddingTop: headerOffset}} style={{paddingTop: headerOffset}}
onScroll={onScroll != null ? scrollHandler : undefined}
scrollEventThrottle={scrollEventThrottle}
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
removeClippedSubviews={true} removeClippedSubviews={true}
contentOffset={{x: 0, y: headerOffset * -1}} contentOffset={{x: 0, y: headerOffset * -1}}
+7 -13
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
ActivityIndicator, ActivityIndicator,
Dimensions, Dimensions,
@@ -8,7 +8,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api' import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -18,10 +18,8 @@ import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useListMembersQuery} from '#/state/queries/list-members' import {useListMembersQuery} from '#/state/queries/list-members'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
@@ -34,24 +32,22 @@ export function ListMembers({
list, list,
style, style,
scrollElRef, scrollElRef,
onScroll, onScrolledDownChange,
onPressTryAgain, onPressTryAgain,
renderHeader, renderHeader,
renderEmptyState, renderEmptyState,
testID, testID,
scrollEventThrottle,
headerOffset = 0, headerOffset = 0,
desktopFixedHeightOffset, desktopFixedHeightOffset,
}: { }: {
list: string list: string
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onScroll: OnScrollHandler onScrolledDownChange: (isScrolledDown: boolean) => void
onPressTryAgain?: () => void onPressTryAgain?: () => void
renderHeader: () => JSX.Element renderHeader: () => JSX.Element
renderEmptyState: () => JSX.Element renderEmptyState: () => JSX.Element
testID?: string testID?: string
scrollEventThrottle?: number
headerOffset?: number headerOffset?: number
desktopFixedHeightOffset?: number desktopFixedHeightOffset?: number
}) { }) {
@@ -209,10 +205,9 @@ export function ListMembers({
[isFetching], [isFetching],
) )
const scrollHandler = useAnimatedScrollHandler(onScroll)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
@@ -233,10 +228,9 @@ export function ListMembers({
minHeight: Dimensions.get('window').height * 1.5, minHeight: Dimensions.get('window').height * 1.5,
}} }}
style={{paddingTop: headerOffset}} style={{paddingTop: headerOffset}}
onScroll={scrollHandler} onScrolledDownChange={onScrolledDownChange}
onEndReached={onEndReached} onEndReached={onEndReached}
onEndReachedThreshold={0.6} onEndReachedThreshold={0.6}
scrollEventThrottle={scrollEventThrottle}
removeClippedSubviews={true} removeClippedSubviews={true}
contentOffset={{x: 0, y: headerOffset * -1}} contentOffset={{x: 0, y: headerOffset * -1}}
// @ts-ignore our .web version only -prf // @ts-ignore our .web version only -prf
+2 -2
View File
@@ -15,7 +15,7 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {FlatList} from '../util/Views' import {List} from '../util/List'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {logger} from '#/logger' import {logger} from '#/logger'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
@@ -119,7 +119,7 @@ export function MyLists({
[error, onRefresh, renderItem, pal], [error, onRefresh, renderItem, pal],
) )
const FlatListCom = inline ? RNFlatList : FlatList const FlatListCom = inline ? RNFlatList : List
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
{items.length > 0 && ( {items.length > 0 && (
+5 -21
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
Dimensions, Dimensions,
RefreshControl, RefreshControl,
@@ -8,7 +8,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {ListCard} from './ListCard' import {ListCard} from './ListCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -16,11 +16,9 @@ import {Text} from '../util/text/Text'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists' import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists'
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
import {logger} from '#/logger' import {logger} from '#/logger'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {useTheme} from '#/lib/ThemeContext' import {useTheme} from '#/lib/ThemeContext'
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
@@ -36,9 +34,7 @@ interface SectionRef {
interface ProfileListsProps { interface ProfileListsProps {
did: string did: string
scrollElRef: MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
onScroll?: OnScrollHandler
scrollEventThrottle?: number
headerOffset: number headerOffset: number
enabled?: boolean enabled?: boolean
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
@@ -47,16 +43,7 @@ interface ProfileListsProps {
export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
function ProfileListsImpl( function ProfileListsImpl(
{ {did, scrollElRef, headerOffset, enabled, style, testID},
did,
scrollElRef,
onScroll,
scrollEventThrottle,
headerOffset,
enabled,
style,
testID,
},
ref, ref,
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
@@ -187,10 +174,9 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
[error, refetch, onPressRetryLoadMore, pal], [error, refetch, onPressRetryLoadMore, pal],
) )
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
@@ -209,8 +195,6 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
minHeight: Dimensions.get('window').height * 1.5, minHeight: Dimensions.get('window').height * 1.5,
}} }}
style={{paddingTop: headerOffset}} style={{paddingTop: headerOffset}}
onScroll={onScroll != null ? scrollHandler : undefined}
scrollEventThrottle={scrollEventThrottle}
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
removeClippedSubviews={true} removeClippedSubviews={true}
contentOffset={{x: 0, y: headerOffset * -1}} contentOffset={{x: 0, y: headerOffset * -1}}
+8 -11
View File
@@ -1,13 +1,11 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {FeedItem} from './FeedItem' import {FeedItem} from './FeedItem'
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
import {EmptyState} from '../util/EmptyState' import {EmptyState} from '../util/EmptyState'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed' import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
@@ -15,6 +13,7 @@ import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread'
import {logger} from '#/logger' import {logger} from '#/logger'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {useModerationOpts} from '#/state/queries/preferences' import {useModerationOpts} from '#/state/queries/preferences'
import {List, ListRef} from '../util/List'
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -23,12 +22,12 @@ const LOADING_ITEM = {_reactKey: '__loading__'}
export function Feed({ export function Feed({
scrollElRef, scrollElRef,
onPressTryAgain, onPressTryAgain,
onScroll, onScrolledDownChange,
ListHeaderComponent, ListHeaderComponent,
}: { }: {
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onPressTryAgain?: () => void onPressTryAgain?: () => void
onScroll?: OnScrollHandler onScrolledDownChange: (isScrolledDown: boolean) => void
ListHeaderComponent?: () => JSX.Element ListHeaderComponent?: () => JSX.Element
}) { }) {
const pal = usePalette('default') const pal = usePalette('default')
@@ -135,7 +134,6 @@ export function Feed({
[isFetchingNextPage], [isFetchingNextPage],
) )
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View style={s.hContentRegion}> <View style={s.hContentRegion}>
{error && ( {error && (
@@ -146,7 +144,7 @@ export function Feed({
/> />
</CenteredView> </CenteredView>
)} )}
<FlatList <List
testID="notifsFeed" testID="notifsFeed"
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
@@ -164,8 +162,7 @@ export function Feed({
} }
onEndReached={onEndReached} onEndReached={onEndReached}
onEndReachedThreshold={0.6} onEndReachedThreshold={0.6}
onScroll={scrollHandler} onScrolledDownChange={onScrolledDownChange}
scrollEventThrottle={1}
contentContainerStyle={s.contentContainer} contentContainerStyle={s.contentContainer}
// @ts-ignore our .web version only -prf // @ts-ignore our .web version only -prf
desktopFixedHeight desktopFixedHeight
+5 -8
View File
@@ -3,12 +3,9 @@ import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {TabBar} from 'view/com/pager/TabBar' import {TabBar} from 'view/com/pager/TabBar'
import {RenderTabBarFnProps} from 'view/com/pager/Pager' import {RenderTabBarFnProps} from 'view/com/pager/Pager'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {Link} from '../util/Link' import {Link} from '../util/Link'
import {Text} from '../util/text/Text'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
import {s} from 'lib/styles'
import {HITSLOP_10} from 'lib/constants' import {HITSLOP_10} from 'lib/constants'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
@@ -21,17 +18,17 @@ import {usePinnedFeedsInfos} from '#/state/queries/feed'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
import {Logo} from '#/view/icons/Logo'
export function FeedsTabBar( export function FeedsTabBar(
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
const {isSandbox, hasSession} = useSession() const {hasSession} = useSession()
const {_} = useLingui() const {_} = useLingui()
const setDrawerOpen = useSetDrawerOpen() const setDrawerOpen = useSetDrawerOpen()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const {feeds, hasPinnedCustom} = usePinnedFeedsInfos() const {feeds, hasPinnedCustom} = usePinnedFeedsInfos()
const brandBlue = useColorSchemeStyle(s.brandBlue, s.blue3)
const {headerHeight} = useShellLayout() const {headerHeight} = useShellLayout()
const {headerMinimalShellTransform} = useMinimalShellMode() const {headerMinimalShellTransform} = useMinimalShellMode()
const pinnedDisplayNames = hasSession ? feeds.map(f => f.displayName) : [] const pinnedDisplayNames = hasSession ? feeds.map(f => f.displayName) : []
@@ -86,9 +83,9 @@ export function FeedsTabBar(
/> />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<Text style={[brandBlue, s.bold, styles.title]}> <View>
{isSandbox ? 'SANDBOX' : 'Bluesky'} <Logo width={30} />
</Text> </View>
<View style={[pal.view, {width: 18}]}> <View style={[pal.view, {width: 18}]}>
{hasSession && ( {hasSession && (
<Link <Link
+10 -29
View File
@@ -1,7 +1,6 @@
import * as React from 'react' import * as React from 'react'
import { import {
LayoutChangeEvent, LayoutChangeEvent,
FlatList,
ScrollView, ScrollView,
StyleSheet, StyleSheet,
View, View,
@@ -20,17 +19,14 @@ import Animated, {
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager' import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
import {TabBar} from './TabBar' import {TabBar} from './TabBar'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {ListMethods} from '../util/List'
const SCROLLED_DOWN_LIMIT = 200 import {ScrollProvider} from '#/lib/ScrollContext'
export interface PagerWithHeaderChildParams { export interface PagerWithHeaderChildParams {
headerHeight: number headerHeight: number
isFocused: boolean isFocused: boolean
onScroll: OnScrollHandler scrollElRef: React.MutableRefObject<ListMethods | ScrollView | null>
isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null>
} }
export interface PagerWithHeaderProps { export interface PagerWithHeaderProps {
@@ -62,7 +58,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
const [currentPage, setCurrentPage] = React.useState(0) const [currentPage, setCurrentPage] = React.useState(0)
const [tabBarHeight, setTabBarHeight] = React.useState(0) const [tabBarHeight, setTabBarHeight] = React.useState(0)
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0) const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const headerHeight = headerOnlyHeight + tabBarHeight const headerHeight = headerOnlyHeight + tabBarHeight
@@ -155,15 +150,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
if (!throttleTimeout.current) { if (!throttleTimeout.current) {
throttleTimeout.current = setTimeout(() => { throttleTimeout.current = setTimeout(() => {
throttleTimeout.current = null throttleTimeout.current = null
runOnUI(adjustScrollForOtherPages)() runOnUI(adjustScrollForOtherPages)()
const nextIsScrolledDown = scrollY.value > SCROLLED_DOWN_LIMIT
if (isScrolledDown !== nextIsScrolledDown) {
React.startTransition(() => {
setIsScrolledDown(nextIsScrolledDown)
})
}
}, 80 /* Sync often enough you're unlikely to catch it unsynced */) }, 80 /* Sync often enough you're unlikely to catch it unsynced */)
} }
}) })
@@ -211,7 +198,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
index={i} index={i}
isReady={isReady} isReady={isReady}
isFocused={i === currentPage} isFocused={i === currentPage}
isScrolledDown={isScrolledDown}
onScrollWorklet={i === currentPage ? onScrollWorklet : noop} onScrollWorklet={i === currentPage ? onScrollWorklet : noop}
registerRef={registerRef} registerRef={registerRef}
renderTab={child} renderTab={child}
@@ -293,7 +279,6 @@ function PagerItem({
index, index,
isReady, isReady,
isFocused, isFocused,
isScrolledDown,
onScrollWorklet, onScrollWorklet,
renderTab, renderTab,
registerRef, registerRef,
@@ -302,7 +287,6 @@ function PagerItem({
index: number index: number
isFocused: boolean isFocused: boolean
isReady: boolean isReady: boolean
isScrolledDown: boolean
registerRef: (scrollRef: AnimatedRef<any> | null, atIndex: number) => void registerRef: (scrollRef: AnimatedRef<any> | null, atIndex: number) => void
onScrollWorklet: (e: NativeScrollEvent) => void onScrollWorklet: (e: NativeScrollEvent) => void
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
@@ -316,24 +300,21 @@ function PagerItem({
} }
}, [scrollElRef, registerRef, index]) }, [scrollElRef, registerRef, index])
const scrollHandler = React.useMemo(
() => ({onScroll: onScrollWorklet}),
[onScrollWorklet],
)
if (!isReady || renderTab == null) { if (!isReady || renderTab == null) {
return null return null
} }
return renderTab({ return (
<ScrollProvider onScroll={onScrollWorklet}>
{renderTab({
headerHeight, headerHeight,
isFocused, isFocused,
isScrolledDown,
onScroll: scrollHandler,
scrollElRef: scrollElRef as React.MutableRefObject< scrollElRef: scrollElRef as React.MutableRefObject<
FlatList<any> | ScrollView | null ListMethods | ScrollView | null
>, >,
}) })}
</ScrollProvider>
)
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
+3 -2
View File
@@ -1,7 +1,8 @@
import React, {useCallback, useMemo, useState} from 'react' import React, {useCallback, useMemo, useState} from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -84,7 +85,7 @@ export function PostLikedBy({uri}: {uri: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={likes} data={likes}
keyExtractor={item => item.actor.did} keyExtractor={item => item.actor.did}
refreshControl={ refreshControl={
+3 -2
View File
@@ -1,7 +1,8 @@
import React, {useMemo, useCallback, useState} from 'react' import React, {useMemo, useCallback, useState} from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -85,7 +86,7 @@ export function PostRepostedBy({uri}: {uri: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={repostedBy} data={repostedBy}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+18 -7
View File
@@ -8,7 +8,8 @@ import {
View, View,
} from 'react-native' } from 'react-native'
import {AppBskyFeedDefs} from '@atproto/api' import {AppBskyFeedDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List, ListMethods} from '../util/List'
import { import {
FontAwesomeIcon, FontAwesomeIcon,
FontAwesomeIconStyle, FontAwesomeIconStyle,
@@ -140,7 +141,7 @@ function PostThreadLoaded({
const {_} = useLingui() const {_} = useLingui()
const pal = usePalette('default') const pal = usePalette('default')
const {isTablet, isDesktop} = useWebMediaQueries() const {isTablet, isDesktop} = useWebMediaQueries()
const ref = useRef<FlatList>(null) const ref = useRef<ListMethods>(null)
const highlightedPostRef = useRef<View | null>(null) const highlightedPostRef = useRef<View | null>(null)
const needsScrollAdjustment = useRef<boolean>( const needsScrollAdjustment = useRef<boolean>(
!isNative || // web always uses scroll adjustment !isNative || // web always uses scroll adjustment
@@ -156,7 +157,9 @@ function PostThreadLoaded({
// construct content // construct content
const posts = React.useMemo(() => { const posts = React.useMemo(() => {
let arr = [TOP_COMPONENT].concat( let arr = [TOP_COMPONENT].concat(
Array.from(flattenThreadSkeleton(sortThread(thread, threadViewPrefs))), Array.from(
flattenThreadSkeleton(sortThread(thread, threadViewPrefs), hasSession),
),
) )
if (arr.length > maxVisible) { if (arr.length > maxVisible) {
arr = arr.slice(0, maxVisible).concat([LOAD_MORE]) arr = arr.slice(0, maxVisible).concat([LOAD_MORE])
@@ -165,7 +168,7 @@ function PostThreadLoaded({
arr.push(BOTTOM_COMPONENT) arr.push(BOTTOM_COMPONENT)
} }
return arr return arr
}, [thread, maxVisible, threadViewPrefs]) }, [thread, maxVisible, threadViewPrefs, hasSession])
/** /**
* NOTE * NOTE
@@ -335,7 +338,7 @@ function PostThreadLoaded({
) )
return ( return (
<FlatList <List
ref={ref} ref={ref}
data={posts} data={posts}
initialNumToRender={!isNative ? posts.length : undefined} initialNumToRender={!isNative ? posts.length : undefined}
@@ -467,20 +470,24 @@ function isThreadPost(v: unknown): v is ThreadPost {
function* flattenThreadSkeleton( function* flattenThreadSkeleton(
node: ThreadNode, node: ThreadNode,
hasSession: boolean,
): Generator<YieldedItem, void> { ): Generator<YieldedItem, void> {
if (node.type === 'post') { if (node.type === 'post') {
if (node.parent) { if (node.parent) {
yield* flattenThreadSkeleton(node.parent) yield* flattenThreadSkeleton(node.parent, hasSession)
} else if (node.ctx.isParentLoading) { } else if (node.ctx.isParentLoading) {
yield PARENT_SPINNER yield PARENT_SPINNER
} }
if (!hasSession && node.ctx.depth > 0 && hasPwiOptOut(node)) {
return
}
yield node yield node
if (node.ctx.isHighlightedPost && !node.post.viewer?.replyDisabled) { if (node.ctx.isHighlightedPost && !node.post.viewer?.replyDisabled) {
yield REPLY_PROMPT yield REPLY_PROMPT
} }
if (node.replies?.length) { if (node.replies?.length) {
for (const reply of node.replies) { for (const reply of node.replies) {
yield* flattenThreadSkeleton(reply) yield* flattenThreadSkeleton(reply, hasSession)
} }
} else if (node.ctx.isChildLoading) { } else if (node.ctx.isChildLoading) {
yield CHILD_SPINNER yield CHILD_SPINNER
@@ -492,6 +499,10 @@ function* flattenThreadSkeleton(
} }
} }
function hasPwiOptOut(node: ThreadPost) {
return !!node.post.author.labels?.find(l => l.val === '!no-unauthenticated')
}
function hasBranchingReplies(node: ThreadNode) { function hasBranchingReplies(node: ThreadNode) {
if (node.type !== 'post') { if (node.type !== 'post') {
return false return false
+4 -1
View File
@@ -187,6 +187,9 @@ let PostThreadItemLoaded = ({
return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by') return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
}, [post.uri, post.author]) }, [post.uri, post.author])
const repostsTitle = 'Reposts of this post' const repostsTitle = 'Reposts of this post'
const isSelfLabeledPost =
moderation.decisions.post.cause?.type === 'label' &&
moderation.decisions.post.cause.label.src === currentAccount?.did
const translatorUrl = getTranslatorLink( const translatorUrl = getTranslatorLink(
record?.text || '', record?.text || '',
@@ -351,7 +354,7 @@ let PostThreadItemLoaded = ({
includeMute includeMute
style={styles.alert} style={styles.alert}
/> />
{post.author.did === currentAccount?.did ? ( {post.author.did === currentAccount?.did && !isSelfLabeledPost ? (
<LabelInfo <LabelInfo
details={{uri: post.uri, cid: post.cid}} details={{uri: post.uri, cid: post.cid}}
labels={post.labels} labels={post.labels}
+27 -15
View File
@@ -1,4 +1,4 @@
import React, {memo, MutableRefObject} from 'react' import React, {memo} from 'react'
import { import {
ActivityIndicator, ActivityIndicator,
AppState, AppState,
@@ -10,15 +10,13 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {FeedErrorMessage} from './FeedErrorMessage' import {FeedErrorMessage} from './FeedErrorMessage'
import {FeedSlice} from './FeedSlice' import {FeedSlice} from './FeedSlice'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {logger} from '#/logger' import {logger} from '#/logger'
import { import {
@@ -31,12 +29,16 @@ import {
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {listenPostCreated} from '#/state/events' import {listenPostCreated} from '#/state/events'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {STALE} from '#/state/queries'
const LOADING_ITEM = {_reactKey: '__loading__'} const LOADING_ITEM = {_reactKey: '__loading__'}
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'} const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
const REFRESH_AFTER = STALE.HOURS.ONE
const CHECK_LATEST_AFTER = STALE.SECONDS.THIRTY
let Feed = ({ let Feed = ({
feed, feed,
feedParams, feedParams,
@@ -45,9 +47,8 @@ let Feed = ({
enabled, enabled,
pollInterval, pollInterval,
scrollElRef, scrollElRef,
onScroll, onScrolledDownChange,
onHasNew, onHasNew,
scrollEventThrottle,
renderEmptyState, renderEmptyState,
renderEndOfFeed, renderEndOfFeed,
testID, testID,
@@ -62,10 +63,9 @@ let Feed = ({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
enabled?: boolean enabled?: boolean
pollInterval?: number pollInterval?: number
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onHasNew?: (v: boolean) => void onHasNew?: (v: boolean) => void
onScroll?: OnScrollHandler onScrolledDownChange?: (isScrolledDown: boolean) => void
scrollEventThrottle?: number
renderEmptyState: () => JSX.Element renderEmptyState: () => JSX.Element
renderEndOfFeed?: () => JSX.Element renderEndOfFeed?: () => JSX.Element
testID?: string testID?: string
@@ -81,6 +81,7 @@ let Feed = ({
const {currentAccount} = useSession() const {currentAccount} = useSession()
const [isPTRing, setIsPTRing] = React.useState(false) const [isPTRing, setIsPTRing] = React.useState(false)
const checkForNewRef = React.useRef<(() => void) | null>(null) const checkForNewRef = React.useRef<(() => void) | null>(null)
const lastFetchRef = React.useRef<number>(Date.now())
const opts = React.useMemo( const opts = React.useMemo(
() => ({enabled, ignoreFilterFor}), () => ({enabled, ignoreFilterFor}),
@@ -98,6 +99,9 @@ let Feed = ({
fetchNextPage, fetchNextPage,
} = usePostFeedQuery(feed, feedParams, opts) } = usePostFeedQuery(feed, feedParams, opts)
const isEmpty = !isFetching && !data?.pages[0]?.slices.length const isEmpty = !isFetching && !data?.pages[0]?.slices.length
if (data?.pages[0]) {
lastFetchRef.current = data?.pages[0].fetchedAt
}
const checkForNew = React.useCallback(async () => { const checkForNew = React.useCallback(async () => {
if (!data?.pages[0] || isFetching || !onHasNew || !enabled) { if (!data?.pages[0] || isFetching || !onHasNew || !enabled) {
@@ -137,11 +141,21 @@ let Feed = ({
checkForNewRef.current = checkForNew checkForNewRef.current = checkForNew
}, [checkForNew]) }, [checkForNew])
React.useEffect(() => { React.useEffect(() => {
if (enabled && checkForNewRef.current) { if (enabled) {
const timeSinceFirstLoad = Date.now() - lastFetchRef.current
if (timeSinceFirstLoad > REFRESH_AFTER) {
// do a full refresh
scrollElRef?.current?.scrollToOffset({offset: 0, animated: false})
queryClient.resetQueries({queryKey: RQKEY(feed)})
} else if (
timeSinceFirstLoad > CHECK_LATEST_AFTER &&
checkForNewRef.current
) {
// check for new on enable (aka on focus) // check for new on enable (aka on focus)
checkForNewRef.current() checkForNewRef.current()
} }
}, [enabled]) }
}, [enabled, feed, queryClient, scrollElRef])
React.useEffect(() => { React.useEffect(() => {
let cleanup1: () => void | undefined, cleanup2: () => void | undefined let cleanup1: () => void | undefined, cleanup2: () => void | undefined
const subscription = AppState.addEventListener('change', nextAppState => { const subscription = AppState.addEventListener('change', nextAppState => {
@@ -270,10 +284,9 @@ let Feed = ({
) )
}, [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed, headerOffset]) }, [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed, headerOffset])
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={feedItems} data={feedItems}
@@ -294,8 +307,7 @@ let Feed = ({
minHeight: Dimensions.get('window').height * 1.5, minHeight: Dimensions.get('window').height * 1.5,
}} }}
style={{paddingTop: headerOffset}} style={{paddingTop: headerOffset}}
onScroll={onScroll != null ? scrollHandler : undefined} onScrolledDownChange={onScrolledDownChange}
scrollEventThrottle={scrollEventThrottle}
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
onEndReached={onEndReached} onEndReached={onEndReached}
onEndReachedThreshold={2} // number of posts left to trigger load more onEndReachedThreshold={2} // number of posts left to trigger load more
+3
View File
@@ -50,6 +50,9 @@ export function ProfileCard({
return null return null
} }
const moderation = moderateProfile(profile, moderationOpts) const moderation = moderateProfile(profile, moderationOpts)
if (moderation.account.filter) {
return null
}
return ( return (
<Link <Link
+3 -2
View File
@@ -1,7 +1,8 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from './ProfileCard' import {ProfileCardWithFollowBtn} from './ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -86,7 +87,7 @@ export function ProfileFollowers({name}: {name: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={followers} data={followers}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+3 -2
View File
@@ -1,7 +1,8 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from './ProfileCard' import {ProfileCardWithFollowBtn} from './ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -86,7 +87,7 @@ export function ProfileFollows({name}: {name: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={follows} data={follows}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+64
View File
@@ -0,0 +1,64 @@
import React, {memo, startTransition} from 'react'
import {FlatListProps} from 'react-native'
import {FlatList_INTERNAL} from './Views'
import {useScrollHandlers} from '#/lib/ScrollContext'
import {runOnJS, useSharedValue} from 'react-native-reanimated'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
export type ListMethods = FlatList_INTERNAL
export type ListProps<ItemT> = Omit<
FlatListProps<ItemT>,
'onScroll' // Use ScrollContext instead.
> & {
onScrolledDownChange?: (isScrolledDown: boolean) => void
}
export type ListRef = React.MutableRefObject<FlatList_INTERNAL | null>
const SCROLLED_DOWN_LIMIT = 200
function ListImpl<ItemT>(
{onScrolledDownChange, ...props}: ListProps<ItemT>,
ref: React.Ref<ListMethods>,
) {
const isScrolledDown = useSharedValue(false)
const contextScrollHandlers = useScrollHandlers()
function handleScrolledDownChange(didScrollDown: boolean) {
startTransition(() => {
onScrolledDownChange?.(didScrollDown)
})
}
const scrollHandler = useAnimatedScrollHandler({
onBeginDrag(e, ctx) {
contextScrollHandlers.onBeginDrag?.(e, ctx)
},
onEndDrag(e, ctx) {
contextScrollHandlers.onEndDrag?.(e, ctx)
},
onScroll(e, ctx) {
contextScrollHandlers.onScroll?.(e, ctx)
const didScrollDown = e.contentOffset.y > SCROLLED_DOWN_LIMIT
if (isScrolledDown.value !== didScrollDown) {
isScrolledDown.value = didScrollDown
if (onScrolledDownChange != null) {
runOnJS(handleScrolledDownChange)(didScrollDown)
}
}
},
})
return (
<FlatList_INTERNAL
{...props}
onScroll={scrollHandler}
scrollEventThrottle={1}
ref={ref}
/>
)
}
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
) => React.ReactElement
@@ -1,30 +1,18 @@
import {useState, useCallback, useMemo} from 'react' import React, {useCallback} from 'react'
import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native' import {ScrollProvider} from '#/lib/ScrollContext'
import {NativeScrollEvent} from 'react-native'
import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell'
import {useShellLayout} from '#/state/shell/shell-layout' import {useShellLayout} from '#/state/shell/shell-layout'
import {s} from 'lib/styles'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import { import {useSharedValue, interpolate} from 'react-native-reanimated'
useSharedValue,
interpolate,
runOnJS,
ScrollHandlers,
} from 'react-native-reanimated'
function clamp(num: number, min: number, max: number) { function clamp(num: number, min: number, max: number) {
'worklet' 'worklet'
return Math.min(Math.max(num, min), max) return Math.min(Math.max(num, min), max)
} }
export type OnScrollCb = ( export function MainScrollProvider({children}: {children: React.ReactNode}) {
event: NativeSyntheticEvent<NativeScrollEvent>,
) => void
export type OnScrollHandler = ScrollHandlers<any>
export type ResetCb = () => void
export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
const {headerHeight} = useShellLayout() const {headerHeight} = useShellLayout()
const [isScrolledDown, setIsScrolledDown] = useState(false)
const mode = useMinimalShellMode() const mode = useMinimalShellMode()
const setMode = useSetMinimalShellMode() const setMode = useSetMinimalShellMode()
const startDragOffset = useSharedValue<number | null>(null) const startDragOffset = useSharedValue<number | null>(null)
@@ -58,13 +46,6 @@ export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
const onScroll = useCallback( const onScroll = useCallback(
(e: NativeScrollEvent) => { (e: NativeScrollEvent) => {
'worklet' 'worklet'
// Keep track of whether we want to show "scroll to top".
if (!isScrolledDown && e.contentOffset.y > s.window.height) {
runOnJS(setIsScrolledDown)(true)
} else if (isScrolledDown && e.contentOffset.y < s.window.height) {
runOnJS(setIsScrolledDown)(false)
}
if (startDragOffset.value === null || startMode.value === null) { if (startDragOffset.value === null || startMode.value === null) {
if (mode.value !== 0 && e.contentOffset.y < headerHeight.value) { if (mode.value !== 0 && e.contentOffset.y < headerHeight.value) {
// If we're close enough to the top, always show the shell. // If we're close enough to the top, always show the shell.
@@ -102,24 +83,15 @@ export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
startMode.value = mode.value startMode.value = mode.value
} }
}, },
[headerHeight, mode, setMode, isScrolledDown, startDragOffset, startMode], [headerHeight, mode, setMode, startDragOffset, startMode],
) )
const scrollHandler: ScrollHandlers<any> = useMemo( return (
() => ({ <ScrollProvider
onBeginDrag, onBeginDrag={onBeginDrag}
onEndDrag, onEndDrag={onEndDrag}
onScroll, onScroll={onScroll}>
}), {children}
[onBeginDrag, onEndDrag, onScroll], </ScrollProvider>
) )
return [
scrollHandler,
isScrolledDown,
useCallback(() => {
setIsScrolledDown(false)
setMode(false)
}, [setMode]),
]
} }
+6 -5
View File
@@ -1,13 +1,14 @@
import React, {useEffect, useState} from 'react' import React, {useEffect, useState} from 'react'
import { import {
NativeSyntheticEvent,
NativeScrollEvent,
Pressable, Pressable,
RefreshControl, RefreshControl,
StyleSheet, StyleSheet,
View, View,
ScrollView, ScrollView,
} from 'react-native' } from 'react-native'
import {FlatList} from './Views' import {FlatList_INTERNAL} from './Views'
import {OnScrollCb} from 'lib/hooks/useOnMainScroll'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {Text} from './text/Text' import {Text} from './text/Text'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -38,7 +39,7 @@ export const ViewSelector = React.forwardRef<
| null | null
| undefined | undefined
onSelectView?: (viewIndex: number) => void onSelectView?: (viewIndex: number) => void
onScroll?: OnScrollCb onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
onRefresh?: () => void onRefresh?: () => void
onEndReached?: (info: {distanceFromEnd: number}) => void onEndReached?: (info: {distanceFromEnd: number}) => void
} }
@@ -59,7 +60,7 @@ export const ViewSelector = React.forwardRef<
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
const [selectedIndex, setSelectedIndex] = useState<number>(0) const [selectedIndex, setSelectedIndex] = useState<number>(0)
const flatListRef = React.useRef<FlatList>(null) const flatListRef = React.useRef<FlatList_INTERNAL>(null)
// events // events
// = // =
@@ -110,7 +111,7 @@ export const ViewSelector = React.forwardRef<
[items], [items],
) )
return ( return (
<FlatList <FlatList_INTERNAL
ref={flatListRef} ref={flatListRef}
data={data} data={data}
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import {ViewProps} from 'react-native' import {ViewProps} from 'react-native'
export {FlatList, ScrollView} from 'react-native' export {FlatList as FlatList_INTERNAL, ScrollView} from 'react-native'
export function CenteredView({ export function CenteredView({
style, style,
sideBorders, sideBorders,
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
export const FlatList = Animated.FlatList export const FlatList_INTERNAL = Animated.FlatList
export const ScrollView = Animated.ScrollView export const ScrollView = Animated.ScrollView
export function CenteredView(props) { export function CenteredView(props) {
return <View {...props} /> return <View {...props} />
+1 -1
View File
@@ -49,7 +49,7 @@ export function CenteredView({
return <View style={style} {...props} /> return <View style={style} {...props} />
} }
export const FlatList = React.forwardRef(function FlatListImpl<ItemT>( export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
{ {
contentContainerStyle, contentContainerStyle,
style, style,
@@ -7,7 +7,7 @@ import {Text} from '../text/Text'
import {ShieldExclamation} from 'lib/icons' import {ShieldExclamation} from 'lib/icons'
import {describeModerationCause} from 'lib/moderation' import {describeModerationCause} from 'lib/moderation'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {isPostMediaBlurred} from 'lib/moderation' import {isPostMediaBlurred} from 'lib/moderation'
@@ -95,13 +95,17 @@ export function ContentHider({
<Text type="md" style={pal.text}> <Text type="md" style={pal.text}>
{desc.name} {desc.name}
</Text> </Text>
{!moderation.noOverride && (
<View style={styles.showBtn}> <View style={styles.showBtn}>
<Text type="lg" style={pal.link}> <Text type="lg" style={pal.link}>
{override ? 'Hide' : 'Show'} {moderation.noOverride ? (
<Trans>Learn more</Trans>
) : override ? (
<Trans>Hide</Trans>
) : (
<Trans>Show</Trans>
)}
</Text> </Text>
</View> </View>
)}
</Pressable> </Pressable>
{override && <View style={childContainerStyle}>{children}</View>} {override && <View style={childContainerStyle}>{children}</View>}
</View> </View>
+2 -1
View File
@@ -43,7 +43,8 @@ export function LabelInfo({
]}> ]}>
<Text type="sm" style={pal.text}> <Text type="sm" style={pal.text}>
<Trans> <Trans>
This {'did' in details ? 'account' : 'post'} has been labeled. A content warning has been applied to this{' '}
{'did' in details ? 'account' : 'post'}.
</Trans>{' '} </Trans>{' '}
</Text> </Text>
<Pressable <Pressable
+21 -3
View File
@@ -22,6 +22,7 @@ import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {s} from '#/lib/styles' import {s} from '#/lib/styles'
import {CenteredView} from '../Views'
export function ScreenHider({ export function ScreenHider({
testID, testID,
@@ -53,22 +54,37 @@ export function ScreenHider({
) )
} }
const isNoPwi =
moderation.cause?.type === 'label' &&
moderation.cause?.labelDef.id === '!no-unauthenticated'
const desc = describeModerationCause(moderation.cause, 'account') const desc = describeModerationCause(moderation.cause, 'account')
return ( return (
<View style={[styles.container, pal.view, containerStyle]}> <CenteredView
style={[styles.container, pal.view, containerStyle]}
sideBorders>
<View style={styles.iconContainer}> <View style={styles.iconContainer}>
<View style={[styles.icon, palInverted.view]}> <View style={[styles.icon, palInverted.view]}>
<FontAwesomeIcon <FontAwesomeIcon
icon="exclamation" icon={isNoPwi ? ['far', 'eye-slash'] : 'exclamation'}
style={pal.textInverted as FontAwesomeIconStyle} style={pal.textInverted as FontAwesomeIconStyle}
size={24} size={24}
/> />
</View> </View>
</View> </View>
<Text type="title-2xl" style={[styles.title, pal.text]}> <Text type="title-2xl" style={[styles.title, pal.text]}>
{isNoPwi ? (
<Trans>Sign-in Required</Trans>
) : (
<Trans>Content Warning</Trans> <Trans>Content Warning</Trans>
)}
</Text> </Text>
<Text type="2xl" style={[styles.description, pal.textLight]}> <Text type="2xl" style={[styles.description, pal.textLight]}>
{isNoPwi ? (
<Trans>
This account has requested that users sign in to view their profile.
</Trans>
) : (
<>
<Trans>This {screenDescription} has been flagged:</Trans> <Trans>This {screenDescription} has been flagged:</Trans>
<Text type="2xl-medium" style={[pal.text, s.ml5]}> <Text type="2xl-medium" style={[pal.text, s.ml5]}>
{desc.name}. {desc.name}.
@@ -88,6 +104,8 @@ export function ScreenHider({
<Trans>Learn More</Trans> <Trans>Learn More</Trans>
</Text> </Text>
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
</>
)}{' '}
</Text> </Text>
{isMobile && <View style={styles.spacer} />} {isMobile && <View style={styles.spacer} />}
<View style={styles.btnContainer}> <View style={styles.btnContainer}>
@@ -116,7 +134,7 @@ export function ScreenHider({
</Button> </Button>
)} )}
</View> </View>
</View> </CenteredView>
) )
} }
+3 -6
View File
@@ -10,7 +10,7 @@ import {AppBskyFeedDefs, AppBskyFeedPost} from '@atproto/api'
import {Text} from '../text/Text' import {Text} from '../text/Text'
import {PostDropdownBtn} from '../forms/PostDropdownBtn' import {PostDropdownBtn} from '../forms/PostDropdownBtn'
import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons' import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons'
import {s, colors} from 'lib/styles' import {s} from 'lib/styles'
import {pluralize} from 'lib/strings/helpers' import {pluralize} from 'lib/strings/helpers'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {RepostButton} from './RepostButton' import {RepostButton} from './RepostButton'
@@ -180,7 +180,7 @@ let PostCtrls = ({
accessibilityHint="" accessibilityHint=""
hitSlop={big ? HITSLOP_20 : HITSLOP_10}> hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
{post.viewer?.like ? ( {post.viewer?.like ? (
<HeartIconSolid style={styles.ctrlIconLiked} size={big ? 22 : 16} /> <HeartIconSolid style={s.likeColor} size={big ? 22 : 16} />
) : ( ) : (
<HeartIcon <HeartIcon
style={[defaultCtrlColor, big ? styles.mt1 : undefined]} style={[defaultCtrlColor, big ? styles.mt1 : undefined]}
@@ -193,7 +193,7 @@ let PostCtrls = ({
testID="likeCount" testID="likeCount"
style={ style={
post.viewer?.like post.viewer?.like
? [s.bold, s.red3, s.f15, s.ml5] ? [s.bold, s.likeColor, s.f15, s.ml5]
: [defaultCtrlColor, s.f15, s.ml5] : [defaultCtrlColor, s.f15, s.ml5]
}> }>
{post.likeCount} {post.likeCount}
@@ -233,9 +233,6 @@ const styles = StyleSheet.create({
paddingLeft: 5, paddingLeft: 5,
paddingRight: 5, paddingRight: 5,
}, },
ctrlIconLiked: {
color: colors.like,
},
mt1: { mt1: {
marginTop: 1, marginTop: 1,
}, },
+48
View File
@@ -0,0 +1,48 @@
import React from 'react'
import Svg, {
Path,
Defs,
LinearGradient,
Stop,
SvgProps,
PathProps,
} from 'react-native-svg'
import {colors} from '#/lib/styles'
const ratio = 57 / 64
type Props = {
fill?: PathProps['fill']
} & SvgProps
export const Logo = React.forwardRef(function LogoImpl(props: Props, ref) {
const {fill, ...rest} = props
const gradient = fill === 'sky'
const _fill = gradient ? 'url(#sky)' : fill || colors.blue3
// @ts-ignore it's fiiiiine
const size = parseInt(rest.width || 32)
return (
<Svg
fill="none"
// @ts-ignore it's fiiiiine
ref={ref}
viewBox="0 0 64 57"
{...rest}
style={{width: size, height: size * ratio}}>
{gradient && (
<Defs>
<LinearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
<Stop offset="0" stopColor="#0A7AFF" stopOpacity="1" />
<Stop offset="1" stopColor="#59B9FF" stopOpacity="1" />
</LinearGradient>
</Defs>
)}
<Path
fill={_fill}
d="M13.873 3.805C21.21 9.332 29.103 20.537 32 26.55v15.882c0-.338-.13.044-.41.867-1.512 4.456-7.418 21.847-20.923 7.944-7.111-7.32-3.819-14.64 9.125-16.85-7.405 1.264-15.73-.825-18.014-9.015C1.12 23.022 0 8.51 0 6.55 0-3.268 8.579-.182 13.873 3.805ZM50.127 3.805C42.79 9.332 34.897 20.537 32 26.55v15.882c0-.338.13.044.41.867 1.512 4.456 7.418 21.847 20.923 7.944 7.111-7.32 3.819-14.64-9.125-16.85 7.405 1.264 15.73-.825 18.014-9.015C62.88 23.022 64 8.51 64 6.55c0-9.818-8.578-6.732-13.873-2.745Z"
/>
</Svg>
)
})
+29
View File
@@ -0,0 +1,29 @@
import React from 'react'
import Svg, {Path, SvgProps, PathProps} from 'react-native-svg'
import {usePalette} from '#/lib/hooks/usePalette'
const ratio = 17 / 64
export function Logotype({
fill,
...rest
}: {fill?: PathProps['fill']} & SvgProps) {
const pal = usePalette('default')
// @ts-ignore it's fiiiiine
const size = parseInt(rest.width || 32)
return (
<Svg
fill="none"
viewBox="0 0 64 17"
{...rest}
width={size}
height={Number(size) * ratio}>
<Path
fill={fill || pal.text.color}
d="M8.478 6.252c1.503.538 2.3 1.78 2.3 3.172 0 2.356-1.576 3.785-4.6 3.785H0V0h5.974c2.875 0 4.267 1.466 4.267 3.413 0 1.3-.594 2.245-1.763 2.839Zm-2.69-4.193H2.504v3.45h3.284c1.28 0 1.967-.667 1.967-1.78 0-1.02-.705-1.67-1.967-1.67Zm-3.284 9.072h3.544c1.41 0 2.17-.65 2.17-1.818 0-1.224-.723-1.837-2.17-1.837H2.504v3.655ZM14.251 13.209h-2.337V0h2.337v13.209ZM22.001 8.998V3.636h2.338v9.573h-2.263v-1.392c-.724 1.076-1.726 1.614-3.006 1.614-2.022 0-3.34-1.224-3.34-3.45V3.636h2.338v5.955c0 1.206.594 1.818 1.8 1.818 1.132 0 2.133-.835 2.133-2.411ZM34.979 8.59v.556h-7.161c.167 1.651 1.076 2.467 2.486 2.467 1.076 0 1.8-.463 2.189-1.372h2.244c-.5 1.947-2.17 3.19-4.452 3.19-1.428 0-2.579-.463-3.45-1.372-.872-.91-1.318-2.115-1.318-3.637 0-1.502.427-2.708 1.299-3.636.872-.909 2.004-1.372 3.432-1.372 1.447 0 2.597.482 3.45 1.428.854.946 1.28 2.208 1.28 3.747Zm-4.75-3.358c-1.28 0-2.17.742-2.393 2.281h4.805c-.204-1.391-1.057-2.281-2.411-2.281ZM40.16 13.469c-2.783 0-4.249-1.095-4.379-3.303h2.282c.13 1.188.724 1.633 2.134 1.633 1.261 0 1.892-.39 1.892-1.15 0-.687-.445-1.02-1.874-1.262l-1.094-.185c-2.097-.353-3.136-1.318-3.136-2.894 0-1.8 1.429-2.894 3.97-2.894 2.728 0 4.138 1.075 4.23 3.246h-2.207c-.056-1.169-.742-1.577-2.023-1.577-1.113 0-1.67.371-1.67 1.113 0 .668.483.965 1.596 1.169l1.206.186c2.32.426 3.32 1.28 3.32 2.912 0 1.93-1.557 3.006-4.247 3.006ZM54.667 13.209h-2.671l-2.783-4.453-1.447 1.447v3.006h-2.3V0h2.3v7.606l3.896-3.97h2.783l-3.618 3.618 3.84 5.955ZM60.772 6.048l.78-2.412H64l-3.692 10.352c-.39 1.057-.872 1.818-1.484 2.245-.612.426-1.484.63-2.634.63-.39 0-.724-.018-1.02-.055V14.97h.89c1.057 0 1.577-.65 1.577-1.54 0-.445-.149-1.094-.446-1.929l-2.746-7.866h2.487l.779 2.393c.575 1.8 1.076 3.58 1.521 5.343.408-1.521.928-3.302 1.54-5.324Z"
/>
</Svg>
)
}
+2 -2
View File
@@ -19,7 +19,7 @@ import {
import {ErrorMessage} from 'view/com/util/error/ErrorMessage' import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {FlatList} from 'view/com/util/Views' import {List} from 'view/com/util/List'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
@@ -481,7 +481,7 @@ export function FeedsScreen(_props: Props) {
{preferences ? <View /> : <ActivityIndicator />} {preferences ? <View /> : <ActivityIndicator />}
<FlatList <List
style={[!isTabletOrDesktop && s.flex1, styles.list]} style={[!isTabletOrDesktop && s.flex1, styles.list]}
data={items} data={items}
keyExtractor={item => item.key} keyExtractor={item => item.key}
+2 -6
View File
@@ -9,6 +9,7 @@ import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
import {FeedsTabBar} from '../com/pager/FeedsTabBar' import {FeedsTabBar} from '../com/pager/FeedsTabBar'
import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager' import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager'
import {FeedPage} from 'view/com/feeds/FeedPage' import {FeedPage} from 'view/com/feeds/FeedPage'
import {HomeLoggedOutCTA} from '../com/auth/HomeLoggedOutCTA'
import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell' import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
import {usePreferencesQuery} from '#/state/queries/preferences' import {usePreferencesQuery} from '#/state/queries/preferences'
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types' import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
@@ -199,12 +200,7 @@ function HomeScreenReady({
onPageScrollStateChanged={onPageScrollStateChanged} onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar} renderTabBar={renderTabBar}
tabBarPosition="top"> tabBarPosition="top">
<FeedPage <HomeLoggedOutCTA />
testID="customFeedPage"
isPageFocused={true}
feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`}
renderEmptyState={renderCustomFeedEmptyState}
/>
</Pager> </Pager>
) )
} }
+10 -7
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {FlatList, View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import { import {
@@ -9,8 +9,9 @@ import {
import {ViewHeader} from '../com/util/ViewHeader' import {ViewHeader} from '../com/util/ViewHeader'
import {Feed} from '../com/notifications/Feed' import {Feed} from '../com/notifications/Feed'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListMethods} from 'view/com/util/List'
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {MainScrollProvider} from '../com/util/MainScrollProvider'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {s, colors} from 'lib/styles' import {s, colors} from 'lib/styles'
@@ -35,8 +36,8 @@ type Props = NativeStackScreenProps<
export function NotificationsScreen({}: Props) { export function NotificationsScreen({}: Props) {
const {_} = useLingui() const {_} = useLingui()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const scrollElRef = React.useRef<FlatList>(null) const scrollElRef = React.useRef<ListMethods>(null)
const checkLatestRef = React.useRef<() => void | null>() const checkLatestRef = React.useRef<() => void | null>()
const {screen} = useAnalytics() const {screen} = useAnalytics()
const pal = usePalette('default') const pal = usePalette('default')
@@ -50,8 +51,8 @@ export function NotificationsScreen({}: Props) {
// = // =
const scrollToTop = React.useCallback(() => { const scrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0}) scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0})
resetMainScroll() setMinimalShellMode(false)
}, [scrollElRef, resetMainScroll]) }, [scrollElRef, setMinimalShellMode])
const onPressLoadLatest = React.useCallback(() => { const onPressLoadLatest = React.useCallback(() => {
scrollToTop() scrollToTop()
@@ -130,11 +131,13 @@ export function NotificationsScreen({}: Props) {
return ( return (
<View testID="notificationsScreen" style={s.hContentRegion}> <View testID="notificationsScreen" style={s.hContentRegion}>
<ViewHeader title={_(msg`Notifications`)} canGoBack={false} /> <ViewHeader title={_(msg`Notifications`)} canGoBack={false} />
<MainScrollProvider>
<Feed <Feed
onScroll={onMainScroll} onScrolledDownChange={setIsScrolledDown}
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
ListHeaderComponent={ListHeaderComponent} ListHeaderComponent={ListHeaderComponent}
/> />
</MainScrollProvider>
{(isScrolledDown || hasNew) && ( {(isScrolledDown || hasNew) && (
<LoadLatestBtn <LoadLatestBtn
onPress={onPressLoadLatest} onPress={onPressLoadLatest}
+3 -1
View File
@@ -24,11 +24,13 @@ import {useResolveUriQuery} from '#/state/queries/resolve-uri'
import {ErrorMessage} from '../com/util/error/ErrorMessage' import {ErrorMessage} from '../com/util/error/ErrorMessage'
import {CenteredView} from '../com/util/Views' import {CenteredView} from '../com/util/Views'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {useSession} from '#/state/session'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
export function PostThreadScreen({route}: Props) { export function PostThreadScreen({route}: Props) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {_} = useLingui() const {_} = useLingui()
const {hasSession} = useSession()
const {fabMinimalShellTransform} = useMinimalShellMode() const {fabMinimalShellTransform} = useMinimalShellMode()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
@@ -89,7 +91,7 @@ export function PostThreadScreen({route}: Props) {
/> />
)} )}
</View> </View>
{isMobile && canReply && ( {isMobile && canReply && hasSession && (
<Animated.View <Animated.View
style={[ style={[
styles.prompt, styles.prompt,
+19 -65
View File
@@ -5,7 +5,8 @@ import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {CenteredView, FlatList} from '../com/util/Views' import {CenteredView} from '../com/util/Views'
import {ListRef} from '../com/util/List'
import {ScreenHider} from 'view/com/util/moderation/ScreenHider' import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
import {Feed} from 'view/com/posts/Feed' import {Feed} from 'view/com/posts/Feed'
import {ProfileLists} from '../com/lists/ProfileLists' import {ProfileLists} from '../com/lists/ProfileLists'
@@ -20,7 +21,6 @@ import {useAnalytics} from 'lib/analytics/analytics'
import {ComposeIcon2} from 'lib/icons' import {ComposeIcon2} from 'lib/icons'
import {useSetTitle} from 'lib/hooks/useSetTitle' import {useSetTitle} from 'lib/hooks/useSetTitle'
import {combinedDisplayName} from 'lib/strings/display-names' import {combinedDisplayName} from 'lib/strings/display-names'
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
import {FeedDescriptor} from '#/state/queries/post-feed' import {FeedDescriptor} from '#/state/queries/post-feed'
import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
@@ -153,7 +153,7 @@ function ProfileScreenLoaded({
const isMe = profile.did === currentAccount?.did const isMe = profile.did === currentAccount?.did
const showRepliesTab = hasSession const showRepliesTab = hasSession
const showLikesTab = isMe const showLikesTab = isMe
const showFeedsTab = isMe || extraInfoQuery.data?.hasFeedgens const showFeedsTab = hasSession && (isMe || extraInfoQuery.data?.hasFeedgens)
const showListsTab = hasSession && (isMe || extraInfoQuery.data?.hasLists) const showListsTab = hasSession && (isMe || extraInfoQuery.data?.hasLists)
const sectionTitles = useMemo<string[]>(() => { const sectionTitles = useMemo<string[]>(() => {
return [ return [
@@ -277,103 +277,67 @@ function ProfileScreenLoaded({
onPageSelected={onPageSelected} onPageSelected={onPageSelected}
onCurrentPageSelected={onCurrentPageSelected} onCurrentPageSelected={onCurrentPageSelected}
renderHeader={renderHeader}> renderHeader={renderHeader}>
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => ( {({headerHeight, isFocused, scrollElRef}) => (
<FeedSection <FeedSection
ref={postsSectionRef} ref={postsSectionRef}
feed={`author|${profile.did}|posts_and_author_threads`} feed={`author|${profile.did}|posts_and_author_threads`}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} scrollElRef={scrollElRef as ListRef}
scrollElRef={
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
{showRepliesTab {showRepliesTab
? ({ ? ({headerHeight, isFocused, scrollElRef}) => (
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
}) => (
<FeedSection <FeedSection
ref={repliesSectionRef} ref={repliesSectionRef}
feed={`author|${profile.did}|posts_with_replies`} feed={`author|${profile.did}|posts_with_replies`}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} scrollElRef={scrollElRef as ListRef}
scrollElRef={
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
) )
: null} : null}
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => ( {({headerHeight, isFocused, scrollElRef}) => (
<FeedSection <FeedSection
ref={mediaSectionRef} ref={mediaSectionRef}
feed={`author|${profile.did}|posts_with_media`} feed={`author|${profile.did}|posts_with_media`}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} scrollElRef={scrollElRef as ListRef}
scrollElRef={
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
{showLikesTab {showLikesTab
? ({ ? ({headerHeight, isFocused, scrollElRef}) => (
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
}) => (
<FeedSection <FeedSection
ref={likesSectionRef} ref={likesSectionRef}
feed={`likes|${profile.did}`} feed={`likes|${profile.did}`}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} scrollElRef={scrollElRef as ListRef}
scrollElRef={
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
) )
: null} : null}
{showFeedsTab {showFeedsTab
? ({onScroll, headerHeight, isFocused, scrollElRef}) => ( ? ({headerHeight, isFocused, scrollElRef}) => (
<ProfileFeedgens <ProfileFeedgens
ref={feedsSectionRef} ref={feedsSectionRef}
did={profile.did} did={profile.did}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll}
scrollEventThrottle={1}
headerOffset={headerHeight} headerOffset={headerHeight}
enabled={isFocused} enabled={isFocused}
/> />
) )
: null} : null}
{showListsTab {showListsTab
? ({onScroll, headerHeight, isFocused, scrollElRef}) => ( ? ({headerHeight, isFocused, scrollElRef}) => (
<ProfileLists <ProfileLists
ref={listsSectionRef} ref={listsSectionRef}
did={profile.did} did={profile.did}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll}
scrollEventThrottle={1}
headerOffset={headerHeight} headerOffset={headerHeight}
enabled={isFocused} enabled={isFocused}
/> />
@@ -396,28 +360,19 @@ function ProfileScreenLoaded({
interface FeedSectionProps { interface FeedSectionProps {
feed: FeedDescriptor feed: FeedDescriptor
onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isFocused: boolean isFocused: boolean
isScrolledDown: boolean scrollElRef: ListRef
scrollElRef: React.MutableRefObject<FlatList<any> | null>
ignoreFilterFor?: string ignoreFilterFor?: string
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl(
{ {feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor},
feed,
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
ignoreFilterFor,
},
ref, ref,
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const onScrollToTop = React.useCallback(() => { const onScrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollToOffset({ scrollElRef.current?.scrollToOffset({
@@ -443,8 +398,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
feed={feed} feed={feed}
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
renderEndOfFeed={ProfileEndOfFeed} renderEndOfFeed={ProfileEndOfFeed}
+27 -96
View File
@@ -1,25 +1,20 @@
import React, {useMemo, useCallback} from 'react' import React, {useMemo, useCallback} from 'react'
import { import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native'
Dimensions,
StyleSheet,
View,
ActivityIndicator,
FlatList,
} from 'react-native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {useNavigation} from '@react-navigation/native' import {useIsFocused, useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {HeartIcon, HeartIconSolid} from 'lib/icons' import {HeartIcon, HeartIconSolid} from 'lib/icons'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {CommonNavigatorParams} from 'lib/routes/types' import {CommonNavigatorParams} from 'lib/routes/types'
import {makeRecordUri} from 'lib/strings/url-helpers' import {makeRecordUri} from 'lib/strings/url-helpers'
import {colors, s} from 'lib/styles' import {s} from 'lib/styles'
import {FeedDescriptor} from '#/state/queries/post-feed' import {FeedDescriptor} from '#/state/queries/post-feed'
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
import {Feed} from 'view/com/posts/Feed' import {Feed} from 'view/com/posts/Feed'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from 'view/com/util/text/RichText'
@@ -29,12 +24,13 @@ import {EmptyState} from 'view/com/util/EmptyState'
import * as Toast from 'view/com/util/Toast' import * as Toast from 'view/com/util/Toast'
import {useSetTitle} from 'lib/hooks/useSetTitle' import {useSetTitle} from 'lib/hooks/useSetTitle'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {shareUrl} from 'lib/sharing' import {shareUrl} from 'lib/sharing'
import {toShareUrl} from 'lib/strings/url-helpers' import {toShareUrl} from 'lib/strings/url-helpers'
import {Haptics} from 'lib/haptics' import {Haptics} from 'lib/haptics'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown' import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown'
import {useScrollHandlers} from '#/lib/ScrollContext'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {makeCustomFeedLink} from 'lib/routes/links' import {makeCustomFeedLink} from 'lib/routes/links'
import {pluralize} from 'lib/strings/helpers' import {pluralize} from 'lib/strings/helpers'
import {CenteredView, ScrollView} from 'view/com/util/Views' import {CenteredView, ScrollView} from 'view/com/util/Views'
@@ -46,12 +42,7 @@ import {logger} from '#/logger'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' import {useFeedSourceInfoQuery, FeedSourceFeedInfo} from '#/state/queries/feed'
import {
useFeedSourceInfoQuery,
FeedSourceFeedInfo,
useIsFeedPublicQuery,
} from '#/state/queries/feed'
import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {useResolveUriQuery} from '#/state/queries/resolve-uri'
import { import {
UsePreferencesQueryResponse, UsePreferencesQueryResponse,
@@ -137,10 +128,8 @@ export function ProfileFeedScreen(props: Props) {
function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) { function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
const {data: preferences} = usePreferencesQuery() const {data: preferences} = usePreferencesQuery()
const {data: info} = useFeedSourceInfoQuery({uri: feedUri}) const {data: info} = useFeedSourceInfoQuery({uri: feedUri})
const {isLoading: isPublicStatusLoading, data: isPublicResponse} =
useIsFeedPublicQuery({uri: feedUri})
if (!preferences || !info || isPublicStatusLoading) { if (!preferences || !info) {
return ( return (
<CenteredView> <CenteredView>
<View style={s.p20}> <View style={s.p20}>
@@ -154,7 +143,6 @@ function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
<ProfileFeedScreenInner <ProfileFeedScreenInner
preferences={preferences} preferences={preferences}
feedInfo={info as FeedSourceFeedInfo} feedInfo={info as FeedSourceFeedInfo}
isPublicResponse={isPublicResponse}
/> />
) )
} }
@@ -162,11 +150,9 @@ function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
export function ProfileFeedScreenInner({ export function ProfileFeedScreenInner({
preferences, preferences,
feedInfo, feedInfo,
isPublicResponse,
}: { }: {
preferences: UsePreferencesQueryResponse preferences: UsePreferencesQueryResponse
feedInfo: FeedSourceFeedInfo feedInfo: FeedSourceFeedInfo
isPublicResponse: ReturnType<typeof useIsFeedPublicQuery>['data']
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const pal = usePalette('default') const pal = usePalette('default')
@@ -175,6 +161,7 @@ export function ProfileFeedScreenInner({
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
const {track} = useAnalytics() const {track} = useAnalytics()
const feedSectionRef = React.useRef<SectionRef>(null) const feedSectionRef = React.useRef<SectionRef>(null)
const isScreenFocused = useIsFocused()
const { const {
mutateAsync: saveFeed, mutateAsync: saveFeed,
@@ -210,6 +197,9 @@ export function ProfileFeedScreenInner({
useSetTitle(feedInfo?.displayName) useSetTitle(feedInfo?.displayName)
// event handlers
//
const onToggleSaved = React.useCallback(async () => { const onToggleSaved = React.useCallback(async () => {
try { try {
Haptics.default() Haptics.default()
@@ -403,32 +393,21 @@ export function ProfileFeedScreenInner({
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader} renderHeader={renderHeader}
onCurrentPageSelected={onCurrentPageSelected}> onCurrentPageSelected={onCurrentPageSelected}>
{({onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}) => {({headerHeight, scrollElRef, isFocused}) => (
isPublicResponse?.isPublic ? (
<FeedSection <FeedSection
ref={feedSectionRef} ref={feedSectionRef}
feed={`feedgen|${feedInfo.uri}`} feed={`feedgen|${feedInfo.uri}`}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown} scrollElRef={scrollElRef as ListRef}
scrollElRef={ isFocused={isScreenFocused && isFocused}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
isFocused={isFocused}
/> />
) : ( )}
<CenteredView sideBorders style={[{paddingTop: headerHeight}]}> {({headerHeight, scrollElRef}) => (
<NonPublicFeedMessage rawError={isPublicResponse?.error} />
</CenteredView>
)
}
{({onScroll, headerHeight, scrollElRef}) => (
<AboutSection <AboutSection
feedOwnerDid={feedInfo.creatorDid} feedOwnerDid={feedInfo.creatorDid}
feedRkey={feedInfo.route.params.rkey} feedRkey={feedInfo.route.params.rkey}
feedInfo={feedInfo} feedInfo={feedInfo}
headerHeight={headerHeight} headerHeight={headerHeight}
onScroll={onScroll}
scrollElRef={ scrollElRef={
scrollElRef as React.MutableRefObject<ScrollView | null> scrollElRef as React.MutableRefObject<ScrollView | null>
} }
@@ -456,59 +435,16 @@ export function ProfileFeedScreenInner({
) )
} }
function NonPublicFeedMessage({rawError}: {rawError?: Error}) {
const pal = usePalette('default')
return (
<View
style={[
pal.border,
{
padding: 18,
borderTopWidth: 1,
minHeight: Dimensions.get('window').height * 1.5,
},
]}>
<View
style={[
pal.viewLight,
{
padding: 12,
borderRadius: 8,
gap: 12,
},
]}>
<Text style={[pal.text]}>
<Trans>
Looks like this feed is only available to users with a Bluesky
account. Please sign up or sign in to view this feed!
</Trans>
</Text>
{rawError?.message && (
<Text style={pal.textLight}>
<Trans>Message from server</Trans>: {rawError.message}
</Text>
)}
</View>
</View>
)
}
interface FeedSectionProps { interface FeedSectionProps {
feed: FeedDescriptor feed: FeedDescriptor
onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean scrollElRef: ListRef
scrollElRef: React.MutableRefObject<FlatList<any> | null>
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl({feed, headerHeight, scrollElRef, isFocused}, ref) {
{feed, onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused},
ref,
) {
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const queryClient = useQueryClient() const queryClient = useQueryClient()
const onScrollToTop = useCallback(() => { const onScrollToTop = useCallback(() => {
@@ -533,11 +469,10 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
<Feed <Feed
enabled={isFocused} enabled={isFocused}
feed={feed} feed={feed}
pollInterval={30e3} pollInterval={60e3}
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={5}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
/> />
@@ -558,7 +493,6 @@ function AboutSection({
feedRkey, feedRkey,
feedInfo, feedInfo,
headerHeight, headerHeight,
onScroll,
scrollElRef, scrollElRef,
isOwner, isOwner,
}: { }: {
@@ -566,13 +500,13 @@ function AboutSection({
feedRkey: string feedRkey: string
feedInfo: FeedSourceFeedInfo feedInfo: FeedSourceFeedInfo
headerHeight: number headerHeight: number
onScroll: OnScrollHandler
scrollElRef: React.MutableRefObject<ScrollView | null> scrollElRef: React.MutableRefObject<ScrollView | null>
isOwner: boolean isOwner: boolean
}) { }) {
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const scrollHandler = useAnimatedScrollHandler(onScroll) const scrollHandlers = useScrollHandlers()
const onScroll = useAnimatedScrollHandler(scrollHandlers)
const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri) const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri)
const {hasSession} = useSession() const {hasSession} = useSession()
const {track} = useAnalytics() const {track} = useAnalytics()
@@ -608,12 +542,12 @@ function AboutSection({
return ( return (
<ScrollView <ScrollView
ref={scrollElRef} ref={scrollElRef}
onScroll={onScroll}
scrollEventThrottle={1} scrollEventThrottle={1}
contentContainerStyle={{ contentContainerStyle={{
paddingTop: headerHeight, paddingTop: headerHeight,
minHeight: Dimensions.get('window').height * 1.5, minHeight: Dimensions.get('window').height * 1.5,
}} }}>
onScroll={scrollHandler}>
<View <View
style={[ style={[
{ {
@@ -646,7 +580,7 @@ function AboutSection({
onPress={onToggleLiked} onPress={onToggleLiked}
style={{paddingHorizontal: 10}}> style={{paddingHorizontal: 10}}>
{isLiked ? ( {isLiked ? (
<HeartIconSolid size={19} style={styles.liked} /> <HeartIconSolid size={19} style={s.likeColor} />
) : ( ) : (
<HeartIcon strokeWidth={3} size={19} style={pal.textLight} /> <HeartIcon strokeWidth={3} size={19} style={pal.textLight} />
)} )}
@@ -689,9 +623,6 @@ const styles = StyleSheet.create({
borderRadius: 50, borderRadius: 50,
marginLeft: 6, marginLeft: 6,
}, },
liked: {
color: colors.red3,
},
notFoundContainer: { notFoundContainer: {
margin: 10, margin: 10,
paddingHorizontal: 18, paddingHorizontal: 18,
+20 -50
View File
@@ -1,12 +1,6 @@
import React, {useCallback, useMemo} from 'react' import React, {useCallback, useMemo} from 'react'
import { import {ActivityIndicator, Pressable, StyleSheet, View} from 'react-native'
ActivityIndicator, import {useFocusEffect, useIsFocused} from '@react-navigation/native'
FlatList,
Pressable,
StyleSheet,
View,
} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
@@ -22,6 +16,7 @@ import {EmptyState} from 'view/com/util/EmptyState'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from 'view/com/util/text/RichText'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List'
import * as Toast from 'view/com/util/Toast' import * as Toast from 'view/com/util/Toast'
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
import {FAB} from 'view/com/util/fab/FAB' import {FAB} from 'view/com/util/fab/FAB'
@@ -31,7 +26,6 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useSetTitle} from 'lib/hooks/useSetTitle' import {useSetTitle} from 'lib/hooks/useSetTitle'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
import {toShareUrl} from 'lib/strings/url-helpers' import {toShareUrl} from 'lib/strings/url-helpers'
import {shareUrl} from 'lib/sharing' import {shareUrl} from 'lib/sharing'
@@ -121,6 +115,7 @@ function ProfileListScreenLoaded({
const aboutSectionRef = React.useRef<SectionRef>(null) const aboutSectionRef = React.useRef<SectionRef>(null)
const {openModal} = useModalControls() const {openModal} = useModalControls()
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist' const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
const isScreenFocused = useIsFocused()
useSetTitle(list.name) useSetTitle(list.name)
@@ -165,36 +160,22 @@ function ProfileListScreenLoaded({
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader} renderHeader={renderHeader}
onCurrentPageSelected={onCurrentPageSelected}> onCurrentPageSelected={onCurrentPageSelected}>
{({ {({headerHeight, scrollElRef, isFocused}) => (
onScroll,
headerHeight,
isScrolledDown,
scrollElRef,
isFocused,
}) => (
<FeedSection <FeedSection
ref={feedSectionRef} ref={feedSectionRef}
feed={`list|${uri}`} feed={`list|${uri}`}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown} isFocused={isScreenFocused && isFocused}
isFocused={isFocused}
/> />
)} )}
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({headerHeight, scrollElRef}) => (
<AboutSection <AboutSection
ref={aboutSectionRef} ref={aboutSectionRef}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
list={list} list={list}
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/> />
)} )}
</PagerWithHeader> </PagerWithHeader>
@@ -221,16 +202,12 @@ function ProfileListScreenLoaded({
items={SECTION_TITLES_MOD} items={SECTION_TITLES_MOD}
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader}> renderHeader={renderHeader}>
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({headerHeight, scrollElRef}) => (
<AboutSection <AboutSection
list={list} list={list}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/> />
)} )}
</PagerWithHeader> </PagerWithHeader>
@@ -615,19 +592,15 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
interface FeedSectionProps { interface FeedSectionProps {
feed: FeedDescriptor feed: FeedDescriptor
onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean scrollElRef: ListRef
scrollElRef: React.MutableRefObject<FlatList<any> | null>
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl({feed, scrollElRef, headerHeight, isFocused}, ref) {
{feed, scrollElRef, onScroll, headerHeight, isScrolledDown, isFocused},
ref,
) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const onScrollToTop = useCallback(() => { const onScrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({ scrollElRef.current?.scrollToOffset({
@@ -651,11 +624,10 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
testID="listFeed" testID="listFeed"
enabled={isFocused} enabled={isFocused}
feed={feed} feed={feed}
pollInterval={30e3} pollInterval={60e3}
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
/> />
@@ -674,20 +646,19 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
interface AboutSectionProps { interface AboutSectionProps {
list: AppBskyGraphDefs.ListView list: AppBskyGraphDefs.ListView
onPressAddUser: () => void onPressAddUser: () => void
onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean scrollElRef: ListRef
scrollElRef: React.MutableRefObject<FlatList<any> | null>
} }
const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>( const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
function AboutSectionImpl( function AboutSectionImpl(
{list, onPressAddUser, onScroll, headerHeight, isScrolledDown, scrollElRef}, {list, onPressAddUser, headerHeight, scrollElRef},
ref, ref,
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist' const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
const isOwner = list.creator.did === currentAccount?.did const isOwner = list.creator.did === currentAccount?.did
@@ -817,8 +788,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
renderHeader={renderHeader} renderHeader={renderHeader}
renderEmptyState={renderEmptyState} renderEmptyState={renderEmptyState}
headerOffset={headerHeight} headerOffset={headerHeight}
onScroll={onScroll} onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1}
/> />
{isScrolledDown && ( {isScrolledDown && (
<LoadLatestBtn <LoadLatestBtn
+47 -13
View File
@@ -8,7 +8,8 @@ import {
Pressable, Pressable,
Platform, Platform,
} from 'react-native' } from 'react-native'
import {FlatList, ScrollView, CenteredView} from '#/view/com/util/Views' import {ScrollView, CenteredView} from '#/view/com/util/Views'
import {List} from '#/view/com/util/List'
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api' import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -155,7 +156,7 @@ function SearchScreenSuggestedFollows() {
}, [currentAccount, setSuggestions, getSuggestedFollowsByActor]) }, [currentAccount, setSuggestions, getSuggestedFollowsByActor])
return suggestions.length ? ( return suggestions.length ? (
<FlatList <List
data={suggestions} data={suggestions}
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />} renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />}
keyExtractor={item => item.did} keyExtractor={item => item.did}
@@ -243,7 +244,7 @@ function SearchScreenPostResults({query}: {query: string}) {
{isFetched ? ( {isFetched ? (
<> <>
{posts.length ? ( {posts.length ? (
<FlatList <List
data={items} data={items}
renderItem={({item}) => { renderItem={({item}) => {
if (item.type === 'post') { if (item.type === 'post') {
@@ -284,7 +285,7 @@ function SearchScreenUserResults({query}: {query: string}) {
return isFetched && results ? ( return isFetched && results ? (
<> <>
{results.length ? ( {results.length ? (
<FlatList <List
data={results} data={results}
renderItem={({item}) => ( renderItem={({item}) => (
<ProfileCardWithFollowBtn profile={item} noBg /> <ProfileCardWithFollowBtn profile={item} noBg />
@@ -303,7 +304,8 @@ function SearchScreenUserResults({query}: {query: string}) {
) )
} }
const SECTIONS = ['Posts', 'Users'] const SECTIONS_LOGGEDOUT = ['Users']
const SECTIONS_LOGGEDIN = ['Posts', 'Users']
export function SearchScreenInner({query}: {query?: string}) { export function SearchScreenInner({query}: {query?: string}) {
const pal = usePalette('default') const pal = usePalette('default')
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
@@ -319,13 +321,14 @@ export function SearchScreenInner({query}: {query?: string}) {
[setDrawerSwipeDisabled, setMinimalShellMode], [setDrawerSwipeDisabled, setMinimalShellMode],
) )
if (hasSession) {
return query ? ( return query ? (
<Pager <Pager
tabBarPosition="top" tabBarPosition="top"
onPageSelected={onPageSelected} onPageSelected={onPageSelected}
renderTabBar={props => ( renderTabBar={props => (
<CenteredView sideBorders style={pal.border}> <CenteredView sideBorders style={pal.border}>
<TabBar items={SECTIONS} {...props} /> <TabBar items={SECTIONS_LOGGEDIN} {...props} />
</CenteredView> </CenteredView>
)} )}
initialPage={0}> initialPage={0}>
@@ -336,7 +339,7 @@ export function SearchScreenInner({query}: {query?: string}) {
<SearchScreenUserResults query={query} /> <SearchScreenUserResults query={query} />
</View> </View>
</Pager> </Pager>
) : hasSession ? ( ) : (
<View> <View>
<CenteredView sideBorders style={pal.border}> <CenteredView sideBorders style={pal.border}>
<Text <Text
@@ -357,6 +360,23 @@ export function SearchScreenInner({query}: {query?: string}) {
<SearchScreenSuggestedFollows /> <SearchScreenSuggestedFollows />
</View> </View>
)
}
return query ? (
<Pager
tabBarPosition="top"
onPageSelected={onPageSelected}
renderTabBar={props => (
<CenteredView sideBorders style={pal.border}>
<TabBar items={SECTIONS_LOGGEDOUT} {...props} />
</CenteredView>
)}
initialPage={0}>
<View>
<SearchScreenUserResults query={query} />
</View>
</Pager>
) : ( ) : (
<CenteredView sideBorders style={pal.border}> <CenteredView sideBorders style={pal.border}>
<View <View
@@ -382,14 +402,28 @@ export function SearchScreenInner({query}: {query?: string}) {
</Text> </Text>
)} )}
<Text <View
style={[ style={{
pal.textLight, flexDirection: 'column',
{textAlign: 'center', paddingVertical: 12, paddingHorizontal: 18}, alignItems: 'center',
]}> justifyContent: 'center',
<Trans>Search for posts and users.</Trans> paddingVertical: 30,
gap: 15,
}}>
<MagnifyingGlassIcon
strokeWidth={3}
size={isDesktop ? 60 : 60}
style={pal.textLight}
/>
<Text type="xl" style={[pal.textLight, {paddingHorizontal: 18}]}>
{isDesktop ? (
<Trans>Find users with the search tool on the right</Trans>
) : (
<Trans>Find users on Bluesky</Trans>
)}
</Text> </Text>
</View> </View>
</View>
</CenteredView> </CenteredView>
) )
} }
+6 -6
View File
@@ -221,19 +221,17 @@ let DrawerContent = ({}: {}): React.ReactNode => {
<NavSignupCard /> <NavSignupCard />
)} )}
{hasSession && <InviteCodes />} {hasSession ? (
{hasSession && <View style={{height: 10}} />} <>
<InviteCodes />
<View style={{height: 10}} />
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} /> <SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
<HomeMenuItem isActive={isAtHome} onPress={onPressHome} /> <HomeMenuItem isActive={isAtHome} onPress={onPressHome} />
{hasSession && (
<NotificationsMenuItem <NotificationsMenuItem
isActive={isAtNotifications} isActive={isAtNotifications}
onPress={onPressNotifications} onPress={onPressNotifications}
/> />
)}
<FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} /> <FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} />
{hasSession && (
<>
<ListsMenuItem onPress={onPressLists} /> <ListsMenuItem onPress={onPressLists} />
<ModerationMenuItem onPress={onPressModeration} /> <ModerationMenuItem onPress={onPressModeration} />
<ProfileMenuItem <ProfileMenuItem
@@ -242,6 +240,8 @@ let DrawerContent = ({}: {}): React.ReactNode => {
/> />
<SettingsMenuItem onPress={onPressSettings} /> <SettingsMenuItem onPress={onPressSettings} />
</> </>
) : (
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
)} )}
<View style={styles.smallSpacer} /> <View style={styles.smallSpacer} />
+16 -10
View File
@@ -5,22 +5,28 @@ import {useLingui} from '@lingui/react'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {DefaultAvatar} from '#/view/com/util/UserAvatar'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import {Button} from '#/view/com/util/forms/Button' import {Button} from '#/view/com/util/forms/Button'
import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util' import {useCloseAllActiveElements} from '#/state/util'
import {Logo} from '#/view/icons/Logo'
let NavSignupCard = ({}: {}): React.ReactNode => { let NavSignupCard = ({}: {}): React.ReactNode => {
const {_} = useLingui() const {_} = useLingui()
const pal = usePalette('default') const pal = usePalette('default')
const {setShowLoggedOut} = useLoggedOutViewControls() const {requestSwitchToAccount} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements() const closeAllActiveElements = useCloseAllActiveElements()
const showLoggedOut = React.useCallback(() => { const showSignIn = React.useCallback(() => {
closeAllActiveElements() closeAllActiveElements()
setShowLoggedOut(true) requestSwitchToAccount({requestedAccount: 'none'})
}, [setShowLoggedOut, closeAllActiveElements]) }, [requestSwitchToAccount, closeAllActiveElements])
const showCreateAccount = React.useCallback(() => {
closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'new'})
// setShowLoggedOut(true)
}, [requestSwitchToAccount, closeAllActiveElements])
return ( return (
<View <View
@@ -29,17 +35,17 @@ let NavSignupCard = ({}: {}): React.ReactNode => {
paddingTop: 6, paddingTop: 6,
marginBottom: 24, marginBottom: 24,
}}> }}>
<DefaultAvatar type="user" size={48} /> <Logo width={48} />
<View style={{paddingTop: 12}}> <View style={{paddingTop: 18}}>
<Text type="md" style={[pal.text, s.bold]}> <Text type="md-bold" style={[pal.text]}>
<Trans>Sign up or sign in to join the conversation</Trans> <Trans>Sign up or sign in to join the conversation</Trans>
</Text> </Text>
</View> </View>
<View style={{flexDirection: 'row', paddingTop: 12, gap: 8}}> <View style={{flexDirection: 'row', paddingTop: 12, gap: 8}}>
<Button <Button
onPress={showLoggedOut} onPress={showCreateAccount}
accessibilityHint={_(msg`Sign up`)} accessibilityHint={_(msg`Sign up`)}
accessibilityLabel={_(msg`Sign up`)}> accessibilityLabel={_(msg`Sign up`)}>
<Text type="md" style={[{color: 'white'}, s.bold]}> <Text type="md" style={[{color: 'white'}, s.bold]}>
@@ -48,7 +54,7 @@ let NavSignupCard = ({}: {}): React.ReactNode => {
</Button> </Button>
<Button <Button
type="default" type="default"
onPress={showLoggedOut} onPress={showSignIn}
accessibilityHint={_(msg`Sign in`)} accessibilityHint={_(msg`Sign in`)}
accessibilityLabel={_(msg`Sign in`)}> accessibilityLabel={_(msg`Sign in`)}>
<Text type="md" style={[pal.text, s.bold]}> <Text type="md" style={[pal.text, s.bold]}>
+65 -4
View File
@@ -23,13 +23,19 @@ import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
import {useNavigationTabState} from 'lib/hooks/useNavigationTabState' import {useNavigationTabState} from 'lib/hooks/useNavigationTabState'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from 'view/com/util/UserAvatar'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {useShellLayout} from '#/state/shell/shell-layout' import {useShellLayout} from '#/state/shell/shell-layout'
import {useUnreadNotifications} from '#/state/queries/notifications/unread' import {useUnreadNotifications} from '#/state/queries/notifications/unread'
import {emitSoftReset} from '#/state/events' import {emitSoftReset} from '#/state/events'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util'
import {Button} from '#/view/com/util/forms/Button'
import {s} from 'lib/styles'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds' type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
@@ -46,6 +52,19 @@ export function BottomBar({navigation}: BottomTabBarProps) {
const numUnreadNotifications = useUnreadNotifications() const numUnreadNotifications = useUnreadNotifications()
const {footerMinimalShellTransform} = useMinimalShellMode() const {footerMinimalShellTransform} = useMinimalShellMode()
const {data: profile} = useProfileQuery({did: currentAccount?.did}) const {data: profile} = useProfileQuery({did: currentAccount?.did})
const {requestSwitchToAccount} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements()
const showSignIn = React.useCallback(() => {
closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'none'})
}, [requestSwitchToAccount, closeAllActiveElements])
const showCreateAccount = React.useCallback(() => {
closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'new'})
// setShowLoggedOut(true)
}, [requestSwitchToAccount, closeAllActiveElements])
const onPressTab = React.useCallback( const onPressTab = React.useCallback(
(tab: TabOptions) => { (tab: TabOptions) => {
@@ -94,6 +113,8 @@ export function BottomBar({navigation}: BottomTabBarProps) {
onLayout={e => { onLayout={e => {
footerHeight.value = e.nativeEvent.layout.height footerHeight.value = e.nativeEvent.layout.height
}}> }}>
{hasSession ? (
<>
<Btn <Btn
testID="bottomBarHomeBtn" testID="bottomBarHomeBtn"
icon={ icon={
@@ -160,9 +181,6 @@ export function BottomBar({navigation}: BottomTabBarProps) {
accessibilityLabel={_(msg`Feeds`)} accessibilityLabel={_(msg`Feeds`)}
accessibilityHint="" accessibilityHint=""
/> />
{hasSession && (
<>
<Btn <Btn
testID="bottomBarNotificationsBtn" testID="bottomBarNotificationsBtn"
icon={ icon={
@@ -230,6 +248,49 @@ export function BottomBar({navigation}: BottomTabBarProps) {
accessibilityHint="" accessibilityHint=""
/> />
</> </>
) : (
<>
<View
style={{
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingTop: 14,
paddingBottom: 2,
paddingLeft: 14,
paddingRight: 6,
gap: 8,
}}>
<View style={{flexDirection: 'row', alignItems: 'center', gap: 8}}>
<Logo width={28} />
<View style={{paddingTop: 4}}>
<Logotype width={80} fill={pal.text.color} />
</View>
</View>
<View style={{flexDirection: 'row', alignItems: 'center', gap: 4}}>
<Button
onPress={showCreateAccount}
accessibilityHint={_(msg`Sign up`)}
accessibilityLabel={_(msg`Sign up`)}>
<Text type="md" style={[{color: 'white'}, s.bold]}>
<Trans>Sign up</Trans>
</Text>
</Button>
<Button
type="default"
onPress={showSignIn}
accessibilityHint={_(msg`Sign in`)}
accessibilityLabel={_(msg`Sign in`)}>
<Text type="md" style={[pal.text, s.bold]}>
<Trans>Sign in</Trans>
</Text>
</Button>
</View>
</View>
</>
)} )}
</Animated.View> </Animated.View>
) )
+74 -3
View File
@@ -3,6 +3,9 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useNavigationState} from '@react-navigation/native' import {useNavigationState} from '@react-navigation/native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {getCurrentRoute, isTab} from 'lib/routes/helpers' import {getCurrentRoute, isTab} from 'lib/routes/helpers'
import {styles} from './BottomBarStyles' import {styles} from './BottomBarStyles'
import {clamp} from 'lib/numbers' import {clamp} from 'lib/numbers'
@@ -22,12 +25,33 @@ import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
import {CommonNavigatorParams} from 'lib/routes/types' import {CommonNavigatorParams} from 'lib/routes/types'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util'
import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {s} from 'lib/styles'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
export function BottomBarWeb() { export function BottomBarWeb() {
const {_} = useLingui()
const {hasSession, currentAccount} = useSession() const {hasSession, currentAccount} = useSession()
const pal = usePalette('default') const pal = usePalette('default')
const safeAreaInsets = useSafeAreaInsets() const safeAreaInsets = useSafeAreaInsets()
const {footerMinimalShellTransform} = useMinimalShellMode() const {footerMinimalShellTransform} = useMinimalShellMode()
const {requestSwitchToAccount} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements()
const showSignIn = React.useCallback(() => {
closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'none'})
}, [requestSwitchToAccount, closeAllActiveElements])
const showCreateAccount = React.useCallback(() => {
closeAllActiveElements()
requestSwitchToAccount({requestedAccount: 'new'})
// setShowLoggedOut(true)
}, [requestSwitchToAccount, closeAllActiveElements])
return ( return (
<Animated.View <Animated.View
@@ -38,6 +62,8 @@ export function BottomBarWeb() {
{paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)}, {paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)},
footerMinimalShellTransform, footerMinimalShellTransform,
]}> ]}>
{hasSession ? (
<>
<NavItem routeName="Home" href="/"> <NavItem routeName="Home" href="/">
{({isActive}) => { {({isActive}) => {
const Icon = isActive ? HomeIconSolid : HomeIcon const Icon = isActive ? HomeIconSolid : HomeIcon
@@ -64,6 +90,9 @@ export function BottomBarWeb() {
) )
}} }}
</NavItem> </NavItem>
{hasSession && (
<>
<NavItem routeName="Feeds" href="/feeds"> <NavItem routeName="Feeds" href="/feeds">
{({isActive}) => { {({isActive}) => {
return ( return (
@@ -75,9 +104,6 @@ export function BottomBarWeb() {
) )
}} }}
</NavItem> </NavItem>
{hasSession && (
<>
<NavItem routeName="Notifications" href="/notifications"> <NavItem routeName="Notifications" href="/notifications">
{({isActive}) => { {({isActive}) => {
const Icon = isActive ? BellIconSolid : BellIcon const Icon = isActive ? BellIconSolid : BellIcon
@@ -113,6 +139,51 @@ export function BottomBarWeb() {
</NavItem> </NavItem>
</> </>
)} )}
</>
) : (
<>
<View
style={{
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingTop: 14,
paddingBottom: 2,
paddingLeft: 14,
paddingRight: 6,
gap: 8,
}}>
<View style={{flexDirection: 'row', alignItems: 'center', gap: 12}}>
<Logo width={32} />
<View style={{paddingTop: 4}}>
<Logotype width={80} fill={pal.text.color} />
</View>
</View>
<View style={{flexDirection: 'row', alignItems: 'center', gap: 8}}>
<Button
onPress={showCreateAccount}
accessibilityHint={_(msg`Sign up`)}
accessibilityLabel={_(msg`Sign up`)}>
<Text type="md" style={[{color: 'white'}, s.bold]}>
<Trans>Sign up</Trans>
</Text>
</Button>
<Button
type="default"
onPress={showSignIn}
accessibilityHint={_(msg`Sign in`)}
accessibilityLabel={_(msg`Sign in`)}>
<Text type="md" style={[pal.text, s.bold]}>
<Trans>Sign in</Trans>
</Text>
</Button>
</View>
</View>
</>
)}
</Animated.View> </Animated.View>
) )
} }
+7 -5
View File
@@ -266,6 +266,10 @@ export function DesktopLeftNav() {
const {isDesktop, isTablet} = useWebMediaQueries() const {isDesktop, isTablet} = useWebMediaQueries()
const numUnread = useUnreadNotifications() const numUnread = useUnreadNotifications()
if (!hasSession && !isDesktop) {
return null
}
return ( return (
<View <View
style={[ style={[
@@ -282,6 +286,8 @@ export function DesktopLeftNav() {
</View> </View>
) : null} ) : null}
{hasSession && (
<>
<BackBtn /> <BackBtn />
<NavItem <NavItem
@@ -332,9 +338,6 @@ export function DesktopLeftNav() {
} }
label={_(msg`Feeds`)} label={_(msg`Feeds`)}
/> />
{hasSession && (
<>
<NavItem <NavItem
href="/notifications" href="/notifications"
count={numUnread} count={numUnread}
@@ -406,7 +409,7 @@ export function DesktopLeftNav() {
style={pal.text} style={pal.text}
/> />
} }
label="Profile" label={_(msg`Profile`)}
/> />
<NavItem <NavItem
href="/settings" href="/settings"
@@ -512,7 +515,6 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
width: 140,
borderRadius: 24, borderRadius: 24,
paddingTop: 10, paddingTop: 10,
paddingBottom: 12, // visually aligns the text vertically inside the button paddingBottom: 12, // visually aligns the text vertically inside the button
+1 -1
View File
@@ -52,7 +52,7 @@ export function DesktopRightNav() {
</Text> </Text>
</View> </View>
) : undefined} ) : undefined}
<View style={[s.flexRow]}> <View style={[{flexWrap: 'wrap'}, s.flexRow]}>
{hasSession && ( {hasSession && (
<> <>
<TextLink <TextLink
-6
View File
@@ -19,10 +19,6 @@ import {useTheme} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {RoutesContainer, TabsNavigator} from '../../Navigation' import {RoutesContainer, TabsNavigator} from '../../Navigation'
import {isStateAtTabRoot} from 'lib/routes/helpers' import {isStateAtTabRoot} from 'lib/routes/helpers'
import {
SafeAreaProvider,
initialWindowMetrics,
} from 'react-native-safe-area-context'
import { import {
useIsDrawerOpen, useIsDrawerOpen,
useSetDrawerOpen, useSetDrawerOpen,
@@ -107,14 +103,12 @@ export const Shell: React.FC = function ShellImpl() {
const pal = usePalette('default') const pal = usePalette('default')
const theme = useTheme() const theme = useTheme()
return ( return (
<SafeAreaProvider initialMetrics={initialWindowMetrics} style={pal.view}>
<View testID="mobileShellView" style={[styles.outerContainer, pal.view]}> <View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
<StatusBar style={theme.colorScheme === 'dark' ? 'light' : 'dark'} /> <StatusBar style={theme.colorScheme === 'dark' ? 'light' : 'dark'} />
<RoutesContainer> <RoutesContainer>
<ShellInner /> <ShellInner />
</RoutesContainer> </RoutesContainer>
</View> </View>
</SafeAreaProvider>
) )
} }
+9 -4
View File
@@ -48,10 +48,10 @@
typed-emitter "^2.1.0" typed-emitter "^2.1.0"
zod "^3.21.4" zod "^3.21.4"
"@atproto/api@^0.7.3": "@atproto/api@^0.7.4":
version "0.7.3" version "0.7.4"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.7.3.tgz#3224000353619970d5e397a157c6e189e195ef47" resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.7.4.tgz#0dd6e725c88d1f941c57670dc82b60fde10f4ec6"
integrity sha512-fKU+W+S4kKxClE6IcPBHPZAjcyBYxG28S0FW/bv3T/ZYDkNxGzDV4xuoHOyEDGtB30slltl5U83njuuRZs5xtw== integrity sha512-7DBy6/OcXemzCPzA0dx52LLYRABBs8bq9Docs3is+WRgEx5/Pd1kHSAlCHIaBhsym8fZ3/U4Fks/5FSHkSm4yQ==
dependencies: dependencies:
"@atproto/common-web" "^0.2.3" "@atproto/common-web" "^0.2.3"
"@atproto/lexicon" "^0.3.1" "@atproto/lexicon" "^0.3.1"
@@ -4448,6 +4448,11 @@
resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.3.0.tgz#9e558170c106bbafaa1ef502bd8e6d4651012bf9" resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.3.0.tgz#9e558170c106bbafaa1ef502bd8e6d4651012bf9"
integrity sha512-+zDZ20NUnSWghj7Ku5aFphMzuM9JulqCW+aPXT6IfIXFbb8tzYTTOSeRFOtuekJ99ibW2fUCSsjuKNlwDIbHFg== integrity sha512-+zDZ20NUnSWghj7Ku5aFphMzuM9JulqCW+aPXT6IfIXFbb8tzYTTOSeRFOtuekJ99ibW2fUCSsjuKNlwDIbHFg==
"@react-native-masked-view/masked-view@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@react-native-masked-view/masked-view/-/masked-view-0.3.1.tgz#5bd76f17004a6ccbcec03856893777ee91f23d29"
integrity sha512-uVm8U6nwFIlUd1iDIB5cS+lDadApKR+l8k4k84d9hn+GN4lzAIJhUZ9syYX7c022MxNgAlbxoFLt0pqKoyaAGg==
"@react-native-menu/menu@^0.8.0": "@react-native-menu/menu@^0.8.0":
version "0.8.0" version "0.8.0"
resolved "https://registry.yarnpkg.com/@react-native-menu/menu/-/menu-0.8.0.tgz#dbf227c2081e5ffd3d2073ee68ecc84cf8639727" resolved "https://registry.yarnpkg.com/@react-native-menu/menu/-/menu-0.8.0.tgz#dbf227c2081e5ffd3d2073ee68ecc84cf8639727"