Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep track of progress through books over time #354

Merged
merged 43 commits into from Jan 22, 2021

Conversation

cincodenada
Copy link
Contributor

@cincodenada cincodenada commented Nov 19, 2020

This works towards implementing #56, which is one of my personal must-haves for record-keeping purposes :)

This is very much an early draft that's very open for feedback, I'm not attached to any details of the implementation here.

What I've done so far:

  • Created a new ProgressUpdate model/table/migration to store progress updates, which are associated with a ReadThrough
  • Added a "current page" input to the readthrough input which populates the existing pages_read field and creates a ProgressUpdate record on save
  • Added basic UI to the book page to display reading progress, hidden by default and shown with a query param

Base functionality:

  • Test coverage (and fixes, if I broke anything, getting testing going now)
  • Add ability to delete a progress update
  • Allow specifying progress as a percentage, mainly for ebooks (the model supports this already, but the UI/logic is not there)
  • Figure out what to do if a book doesn't have a page count populated - should we allow users to update the book record, or store a per-user page count that overrides/fills in for any page count on the book level? What does that UI look like?

Improvements:

  • Add option to add a comment along with the progress udpate
  • Optionally post progress updates on ActivityPub as a new type of status (there's some code working towards this that's not used yet)
  • The ActivityPub statuses will be pretty duplicative of the ProgressUpdate model. We could possibly have them be the same thing, that would just require having some, statuses (private maybe?) that never actually get posted to ActivityPub or possibly not even show up in your private feed, which may be more trouble than it's worth.

Nice to have but not essential:

  • Add a quick update on the feed sidebar
  • Make it look prettier
  • Add (optional) Javascript for showing the progress updates w/o reloading the page
  • Show a chart of progress over time
  • Get clever and convert when switching between pages/percent

I think that's most of it, although I'll probably realize later I forgot something. Right now this is just on my local dev instance, but I'll probably put it up on my staging instance once I get it running again. Happy to hear any feedback on style/approach/etc!

@mouse-reeve
Copy link
Member

wow this rules, I'm so stoked!! I'm going to take a closer look tomorrow but rad, thank you

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are accessibility issues in these changes.

@@ -0,0 +1,5 @@
<div class="progress-update is-small">
on page
<input class="is-small" type="text" size="3">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's a label missing for this input. That makes it hard for people using screen readers or voice control to use the input.

Copy link
Member

@mouse-reeve mouse-reeve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's a question I have as someone who doesn't use this feature -- would you want to post updates to your feed as you update your progress, or would you assume/prefer that it's just for your personal tracking?

bookwyrm/static/css/format.css Outdated Show resolved Hide resolved
bookwyrm/views.py Outdated Show resolved Hide resolved
bookwyrm/models/status.py Outdated Show resolved Hide resolved
bookwyrm/activitypub/note.py Outdated Show resolved Hide resolved
@cincodenada
Copy link
Contributor Author

would you want to post updates to your feed as you update your progress, or would you assume/prefer that it's just for your personal tracking?

It kinda depends - I'd say it's primarily for my personal tracking, but I might occasionally want to post an update. A feature that I haven't added yet is the ability to write a short note along with the progress update (e.g. "oh dang, this is getting good!"), and I'd be more likely to want to post those to my feed.

@mouse-reeve
Copy link
Member

ah yeah that makes a lot of sense! My first thought is that the simplest route would be to associate a progress update with a Comment status, maybe with an optional foreign key from the status to the update. It would be pretty straightforward to include the page/percent value in the ActivityPub serialization without having to federate the update object itself.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are accessibility issues in these changes.

<div class="field is-grouped is-small px-2">
<div class="control">on page</div>
<div class="control">
<input class="input is-small" type="text" size="3">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's a label missing for this input. That makes it hard for people using screen readers or voice control to use the input.

@rkingett
Copy link

Wish the bot gave more information, but it looks like you're trying to make a div be an edit field. Using native HTML elements is better because, not only will it work across browsers effortlessly, but you get a dozen accessibility properties for free.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

@cincodenada
Copy link
Contributor Author

accesslintbot seems a little...overexcited here 😆 I don't see an issue tracker for it, I was thinking of just emailing their support with a link to this issue?

Also add $@ to bw-dev migrations, and factor the shift 1 out
Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

@cincodenada
Copy link
Contributor Author

cincodenada commented Jan 17, 2021

As for the PR itself, I just merged in the latest changes from main (love the reorganization!) and I think this is in an okay checkpoint to merge - there's still stuff I'd like to add, but I think it's reasonably complete and useful in its current state. I've rearranged the checklist accordingly.

On the last item, I think we can punt on that for now, and just show the total if we have it, and not if we don't, and I think that's fine.

Oh, I do want to go in and tidy up some of these migrations, there's no reason to have all these merge commits for a single PR, I'll collapse those down.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

@cincodenada
Copy link
Contributor Author

Okay, actually I'll leave most of the migrations in place, cause I don't want to mess with them. There was just one I hadn't added yet (0037), and so I added that and in place of the 0036 merge, since that's a pretty simple substitution.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

self.assertEqual(self.edition.readthrough_set.count(), 0)

self.client.post('/start-reading/{}'.format(self.edition.id), {
'start_date': '2020-11-27',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might have the side effect of creating a "started reading" status and then triggering a broadcast task, which could be why the tests are hanging. you can use with patch('bookwyrm.broadcast.broadcast_task.delay') if that's what's happening. Stopping celery and redis when you run the tests will show these errors locally. I have learned the hard way!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh rad, that's very helpful, thanks! I'll take a peek at that, hopefully the logs will confirm once they time out again in a couple hours 🙃

@mouse-reeve
Copy link
Member

I made a bunch of merge conflicts for you again! As before, I'd be happy to resolve them for you if that would be easier.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

@cincodenada
Copy link
Contributor Author

Those merge conflicts were 🍰 😄, barely had to tell my diff tool anything, yay!

I poked around at the patch() stuff and implemented it by mocking it for the whole test class, since there's no case in this test where we want to have it unpatched. Let me know what you think - I'm happy to switch it up if it's better to be consistent with the others.

@mouse-reeve
Copy link
Member

oh patching for the whole class is great! I'm looking forward to testing tomorrow :)

Copy link
Member

@mouse-reeve mouse-reeve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is at a good point to merge, after these couple small model and display changes. I really appreciate all your work on this!

@@ -47,7 +47,17 @@ <h2 class="title is-5">Your books</h2>
</div>
</div>
<div class="card-content">
{% include 'snippets/shelve_button.html' with book=book %}
<div class="columns is-gapless">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this works better just flat, rather than in columns -- so this markup minus all the added divs? it was too long for my screen as is

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up flattening this and then totally reworking the update snippet. Curious to hear what you think, I'm...mostly happy with it I think 😅

<div class="control">
<input
aria-label="{% if readthrough.progress_mode == 'PG' %}Current page{% else %}Percent read{% endif %}"
class="input is-small" type="text"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this type should be number, rather than text for better input validation

class ProgressUpdate(BookWyrmModel):
''' Store progress through a book in the database. '''
user = models.ForeignKey('User', on_delete=models.PROTECT)
readthrough = models.ForeignKey('ReadThrough', on_delete=models.PROTECT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try to delete a readthrough that has an associated progress update, I get an error because of the protected relationship. I think this is a case where CASCADE would be better than PROTECT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, if a user is deleting a readthrough there's no reason to keep the progress updates. There's already a confirmation dialog for readthroughs, I bet I can add a "...and its X progress updates" to that just to make it clear.

''' Store progress through a book in the database. '''
user = models.ForeignKey('User', on_delete=models.PROTECT)
readthrough = models.ForeignKey('ReadThrough', on_delete=models.PROTECT)
progress = models.IntegerField()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should have a min value validator to prevent negative values here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added validators here and on ReadThrough.progress (and tests to make sure they work), but didn't actually use them anywhere. I'm not sure they'll have any effect on ProgressUpdate, but might on the ReadThrough depending on how we use them?

In any case, having the validators is better than not

Add a warning about it, and update test to confirm it works
I don't think these validators will do anything unless we use them or
are submitting a form, but they're there nonetheless
Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 You fixed the issue(s)! Great work.

@mouse-reeve
Copy link
Member

Whew, thank you so much for bearing with this, I'm stoked to have the feature. I think the next step is making it possible to post status update Generated Notes, and associated progress points with statuses

@mouse-reeve mouse-reeve merged commit 6c52afe into bookwyrm-social:main Jan 22, 2021
@mouse-reeve
Copy link
Member

I've been posting periodic updates on patreon with a list of newly added features. If you're okay with it, what's the best way to credit you for this? The default would just be like, First Name Last Name with a link to your website, but whatever feels best to you within reason is good for me

@cincodenada
Copy link
Contributor Author

Oh, sure, thanks! Joel Bradshaw is good, with a link to...uhh https://cincodenada.com I suppose. Or just my Mastodon account, whatever seems best!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants