bluesky-social / social-app

The Bluesky Social application for Web, iOS, and Android
https://bsky.app
MIT License
10.27k stars 1.3k forks source link

Pinned posts #851

Closed Cloudhunter closed 4 weeks ago

Cloudhunter commented 1 year ago

Is your feature request related to a problem? Please describe.

Sometimes people like to pin posts to get more attention to them or to provide important information about an account. The bio limit is generous (thanks for that!) but being able to pin a post would allow other media such as photos or links with proper link cards.

Describe the solution you'd like

Support for pinning a post/posts to a profile.

Describe alternatives you've considered

The bio, but it would miss the advantages of media

Additional context

This is popular on other services such as Twitter or Mastodon.

I wouldn't mind looking into implementing this myself if the team think it would be a good feature.

ejmg commented 1 year ago

I'm personally a big fan of pinned posts and I would love to help implement the issue. The issue has been tagged as on the roadmap, does that mean outside contributors should keep away? I don't want to step on toes or get in the way.

pfrazee commented 1 year ago

@ejmg if you're up for it, this would be a great contribution

The way to move forward with this is to open an issue on bluesky-social/atproto discussing the schema changes needed. We need to decide the following:

Once that's established, we create a PR to the atproto repo which adds the pinned record schema (a lexicon file) and updates both the API, the PDS, and any other necessary services. You'll likely need the backend team's help with this, especially because they're refactoring a lot of things for federation.

Once that PR is in review, we can create a PR to add the behavior here. That's when things get much more straightforward (just UI work).

ejmg commented 1 year ago

awesome! I would definitely love to try. I'll dig into atproto and report over in that repo to see if I can get things going.

pfrazee commented 1 year ago

Wonderful! I'll do my best to facilitate when I can

KiameV commented 1 year ago

@pfrazee let me know if this would be better in a discussion in atproto.

I jumped into the AT protocol and dug around as I'd like to see the ability to pin posts. My idea:

Looking at the lexicons and guessing how the application works, getAuthorFeed will need to know which post is pinned. I'm guessing this is a highly parallelized system app and I'm guessing it cannot be guaranteed that the getProfile will have returned prior to getAuthorFeed being executed.

I was originally thinking of adding pinned message to the user's profile but due to the limitations imposed above, I don't think that will work.

Instead, I'm thinking of a new def in feed/defs.json of pinnedPost.

    "pinnedPost": {
      "type": "object",
      "required": ["uri", "author"],
      "properties": {
        "uri": {"type": "string", "format": "at-uri"},
        "author": {"type": "ref", "ref": "app.bsky.actor.defs#profileViewBasic"}
      }
    }

With this approach, getAuthorFeed could include pinnedPost in the output. As I say all of this, though, I don't think it'll work as I'm guessing feedViewPost is a db table and I can't just append a field to a cursor/array tuple.

The easiest solution would be to add a boolean to every post specifying whether it's pinned or not but storing/sending an additional bit for every post seems wasteful...

WriterStat commented 1 year ago

Hi, don't know your code base yet, but from the outside it appears...don't you all(bluesky), already have what you need for pinning a post... inside your code base already for reposting a post? Can't you reuse that repost code with a really quick tweak/user flag/user json pin field to also Pin a post?

  1. Here's my thought...in the current code when I repost a post, it automatically posts the selected post to the very top of my page. Lets call this post position index 0. Index 0 is the very first item in a list/array.
  2. It does this currently for every repost, it places that repost at index 0.
  3. Everyone now sees the repost at the top of my page. The current code/system has placed it there at index 0 for everyone to see.
  4. A pinned post is just a repost just as it is now, but instead where any post or repost done after that is added at post position index 1/after the pinned post at position index 0.
  5. This way you don't even have to know if any particular post is pinned, and no boolean added to every post is needed. You instead just have to insert any post or repost after that at position index 1, which is below the first post(pinned) on the page. You can accomplish this in many ways.
  6. To get fancy...you could even have a user pin index flag through json or other. If the pin flag is 0 then insert all posts/reposts at index 0. If pin flag is 1 then insert all posts/reposts at index 1. If pin flag is 2 then insert all posts/reposts at index 2. And so on... That way you could have multiple pinned posts if you so wanted.
  7. No reason to gum up the system or add much overhead.
WriterStat commented 1 year ago

While I think the above should be done. If for some reason I'm way off.

There's also another really quick way to pin a post to post position index 0 without changing/adding to the post's data. - On a new post or repost, record the current top position post's info. -Do/run the new post or repost. -Then unrepost and repost the previous top pinned post after that in code. It would take two transactions, but not that bad. And the code is already there to leverage.

Thoughts?

Basically, you do an unrepost and then a repost of the pinned item after any new post or repost. This can also be done in many ways.

WriterStat commented 1 year ago

You asked...

Is there one pinned post or multiple?
Is the pinned post stored in the profile record or as some separate kind of record?
How will the pinned post be transmitted to the client? via getProfile() or some other means?

Question 1 doesn't really matter. It's up to business needs to limit/allow how many pinned items are allowed/displayed at top(example: 0 to 5). Only one item is ever added to the top of the list (pinned) at a time (just like a repost). You'll want to keep track of how many items on top are pinned for each user.

The real question is do you really need to know what's individually pinned in the view? Or can you just say the top 1 to 5 of the items in the initial displayed list of items viewed are pinned? I'm not sure there's an advantage of knowing anything more than the top 0 to 5 items are pinned. 0 being no items are pinned.

Either way you'll want to pin/unpin one at a time just like a repost. And can't you already leverage/reuse some current code to do this now, or at least copy it/use as template?

Question 2 I think the real question is do you need to know if a post is pinned for a view on a page? Why? Or do you just want it to be at the top of the initial viewed list of items on a page/list of items? Cuz won't that give you all the info you need already? If it's listed at the top of the page? And you know 0 through however many on top are pinned? Then just adjust what you need.

Note: this may lead to the question how do I know where the original post was in the list? There's an answer for that.

Question 3 The answer here is quite simple ~If you just want pinned posts at the top. It's transmitted just like a repost is. You may want to add a db field in the user's profile or where appropriate called 'pinned' this alerts you to how many items on the top of the intial item list are pinned.

You may also want to add a db field in the user's profile or where appropriate called 'pinned_items' that is a list of ids/identifiers of pinned items in the initial list of items but only if you are not storing everything as json.

You'll want to adjust the repost/post functions to take a passed in index called Pinned. New posts and new reposts are then added to the initial views item list below that. But in reality you could reuse most of the code now being used for reposting.

If you have db people, you'll want to ask them how they want to store, either normalize or denormalize.

Note: in our own code here we store quite a lot as JSON.

Maybe I've got this totally wrong but...isn't a pinned item just an extended case or special case repost of an item?

mmangopear commented 7 months ago

Out of curiosity, any updates on this request? I know yall purposefully keep the timeline vague so you can deliver on promises. Just wanted to ask :)

mary-ext commented 6 months ago

Starting with the lexicon definitions itself seems worthwhile, there are still questions that needed answers, but I've done it: https://github.com/bluesky-social/atproto/pull/2455

Interested on moving this forward, I have a semi-working implementation for this ready, just need help with the viewer hydration aspect

mschwendener commented 1 month ago

This can be closed :D

https://bsky.app/profile/bsky.app/post/3l66vf2q4pi26