forked from mirrors/bookwyrm
Add option for progress percentage
And rework display on book page as well
This commit is contained in:
parent
9ed7d23000
commit
500f05266a
6 changed files with 95 additions and 39 deletions
|
@ -292,13 +292,21 @@ class Boost(Status):
|
||||||
# unique_together = ('user', 'boosted_status')
|
# unique_together = ('user', 'boosted_status')
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressMode(models.TextChoices):
|
||||||
|
PAGE = 'PG', 'page'
|
||||||
|
PERCENT = 'PCT', 'percent'
|
||||||
|
|
||||||
class ReadThrough(BookWyrmModel):
|
class ReadThrough(BookWyrmModel):
|
||||||
''' Store a read through a book in the database. '''
|
''' Store a read through a book in the database. '''
|
||||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||||
book = models.ForeignKey('Book', on_delete=models.PROTECT)
|
book = models.ForeignKey('Book', on_delete=models.PROTECT)
|
||||||
pages_read = models.IntegerField(
|
progress = models.IntegerField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True)
|
blank=True)
|
||||||
|
progress_mode = models.CharField(
|
||||||
|
max_length=3,
|
||||||
|
choices=ProgressMode.choices,
|
||||||
|
default=ProgressMode.PAGE)
|
||||||
start_date = models.DateTimeField(
|
start_date = models.DateTimeField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True)
|
null=True)
|
||||||
|
@ -312,9 +320,13 @@ class ReadThrough(BookWyrmModel):
|
||||||
self.user.save()
|
self.user.save()
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
class ProgressMode(models.TextChoices):
|
def create_update(self):
|
||||||
PAGE = 'PG', 'page'
|
if self.progress:
|
||||||
PERCENT = 'PCT', 'percent'
|
return self.progressupdate_set.create(
|
||||||
|
user=self.user,
|
||||||
|
progress=self.progress,
|
||||||
|
mode=self.progress_mode)
|
||||||
|
|
||||||
|
|
||||||
class ProgressUpdate(BookWyrmModel):
|
class ProgressUpdate(BookWyrmModel):
|
||||||
''' Store progress through a book in the database. '''
|
''' Store progress through a book in the database. '''
|
||||||
|
|
|
@ -74,9 +74,13 @@
|
||||||
{% if readthrough.finish_date %}
|
{% if readthrough.finish_date %}
|
||||||
<dt>Finished reading:</dt>
|
<dt>Finished reading:</dt>
|
||||||
<dd>{{ readthrough.finish_date | naturalday }}</dd>
|
<dd>{{ readthrough.finish_date | naturalday }}</dd>
|
||||||
{% elif readthrough.pages_read %}
|
{% elif readthrough.progress %}
|
||||||
<dt>On page:</dt>
|
<dt>Progress:</dt>
|
||||||
<dd>{{ readthrough.pages_read }} of {{ book.pages }}</dd>
|
{% if readthrough.progress_mode == 'PG' %}
|
||||||
|
<dd>on page {{ readthrough.progress }} of {{ book.pages }}</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{{ readthrough.progress }}%</dd>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
|
@ -93,12 +97,22 @@
|
||||||
</div>
|
</div>
|
||||||
{% if show_progress %}
|
{% if show_progress %}
|
||||||
Progress Updates:
|
Progress Updates:
|
||||||
<dl class="progress-updates">
|
<ul>
|
||||||
|
{% if readthrough.finish_date %}
|
||||||
|
<li>{{ readthrough.start_date | naturalday }}: finished</li>
|
||||||
|
{% endif %}
|
||||||
{% for progress_update in readthrough.progress_updates %}
|
{% for progress_update in readthrough.progress_updates %}
|
||||||
<dt>{{ progress_update.created_date | naturalday }}:</dt>
|
<li>
|
||||||
<dd>{{ progress_update.progress }} of {{ book.pages }}</dd>
|
{{ progress_update.created_date | naturalday }}:
|
||||||
|
{% if progress_update.mode == 'PG' %}
|
||||||
|
page {{ progress_update.progress }} of {{ book.pages }}
|
||||||
|
{% else %}
|
||||||
|
{{ progress_update.progress }}%
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
<li>{{ readthrough.start_date | naturalday }}: started</li>
|
||||||
|
</ul>
|
||||||
{% elif readthrough.progress_updates|length %}
|
{% elif readthrough.progress_updates|length %}
|
||||||
<a href="?showprogress">Show {{ readthrough.progress_updates|length }} Progress Updates</a>
|
<a href="?showprogress">Show {{ readthrough.progress_updates|length }} Progress Updates</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -118,11 +132,27 @@
|
||||||
<input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
|
<input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="columns">
|
||||||
<label class="label">
|
<div class="column">
|
||||||
On page
|
<div class="field">
|
||||||
<input type="number" name="pages_read" class="input" id="id_pages_read-{{ readthrough.id }}" value="{{ readthrough.pages_read }}">
|
<label class="label">
|
||||||
</label>
|
Progress
|
||||||
|
<input type="number" name="progress" class="input" id="id_progress-{{ readthrough.id }}" value="{{ readthrough.progress }}">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<div class="control mt-5">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="progress_mode" id="id_progress_mode-{{ readthrough.id }}" value="PG" {% if readthrough.progress_mode == 'PG' %}checked{% endif %}>
|
||||||
|
pages
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="progress_mode" id="id_progress_mode-{{ readthrough.id }}" value="PCT" {% if readthrough.progress_mode == 'PCT' %}checked{% endif %}>
|
||||||
|
percent
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
<form class="field is-grouped is-small pl-2" action="/edit-readthrough" method="POST">
|
<form class="field is-grouped is-small pl-2" action="/edit-readthrough" method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="id" value="{{ readthrough.id }}"/>
|
<input type="hidden" name="id" value="{{ readthrough.id }}"/>
|
||||||
<div class="control">on page</div>
|
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input aria-label="Current page" class="input is-small" type="text" name="pages_read" size="3" value="{{ readthrough.pages_read }}">
|
{% if readthrough.progress_mode == 'PG' %}
|
||||||
|
on page
|
||||||
|
{% else %}
|
||||||
|
currently at
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<input
|
||||||
|
aria-label="{% if readthrough.progress_mode == 'PG' %}Current page{% else %}Perent read{% endif%}"
|
||||||
|
class="input is-small" type="text"
|
||||||
|
name="progress" size="3" value="{{ readthrough.progress }}">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
{% if readthrough.progress_mode == 'PG' and book.pages %}
|
||||||
|
of {{ book.pages }}
|
||||||
|
{% else %}
|
||||||
|
%
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if book.pages %}
|
|
||||||
<div class="control">of {{ book.pages }}</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button is-small px-2" type="submit">Go</button>
|
<button class="button is-small px-2" type="submit">Go</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ReadThrough(TestCase):
|
||||||
self.assertEqual(readthroughs[0].progressupdate_set.count(), 0)
|
self.assertEqual(readthroughs[0].progressupdate_set.count(), 0)
|
||||||
self.assertEqual(readthroughs[0].start_date,
|
self.assertEqual(readthroughs[0].start_date,
|
||||||
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
||||||
self.assertEqual(readthroughs[0].pages_read, None)
|
self.assertEqual(readthroughs[0].progress, None)
|
||||||
self.assertEqual(readthroughs[0].finish_date, None)
|
self.assertEqual(readthroughs[0].finish_date, None)
|
||||||
|
|
||||||
def test_create_progress_readthrough(self):
|
def test_create_progress_readthrough(self):
|
||||||
|
@ -44,14 +44,14 @@ class ReadThrough(TestCase):
|
||||||
|
|
||||||
self.client.post('/start-reading/{}'.format(self.edition.id), {
|
self.client.post('/start-reading/{}'.format(self.edition.id), {
|
||||||
'start_date': '2020-11-27',
|
'start_date': '2020-11-27',
|
||||||
'pages_read': 50,
|
'progress': 50,
|
||||||
})
|
})
|
||||||
|
|
||||||
readthroughs = self.edition.readthrough_set.all()
|
readthroughs = self.edition.readthrough_set.all()
|
||||||
self.assertEqual(len(readthroughs), 1)
|
self.assertEqual(len(readthroughs), 1)
|
||||||
self.assertEqual(readthroughs[0].start_date,
|
self.assertEqual(readthroughs[0].start_date,
|
||||||
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
datetime(2020, 11, 27, tzinfo=timezone.utc))
|
||||||
self.assertEqual(readthroughs[0].pages_read, 50)
|
self.assertEqual(readthroughs[0].progress, 50)
|
||||||
self.assertEqual(readthroughs[0].finish_date, None)
|
self.assertEqual(readthroughs[0].finish_date, None)
|
||||||
|
|
||||||
progress_updates = readthroughs[0].progressupdate_set.all()
|
progress_updates = readthroughs[0].progressupdate_set.all()
|
||||||
|
@ -62,7 +62,7 @@ class ReadThrough(TestCase):
|
||||||
# Update progress
|
# Update progress
|
||||||
self.client.post('/edit-readthrough', {
|
self.client.post('/edit-readthrough', {
|
||||||
'id': readthroughs[0].id,
|
'id': readthroughs[0].id,
|
||||||
'pages_read': 100,
|
'progress': 100,
|
||||||
})
|
})
|
||||||
|
|
||||||
progress_updates = readthroughs[0].progressupdate_set\
|
progress_updates = readthroughs[0].progressupdate_set\
|
||||||
|
|
|
@ -364,11 +364,7 @@ def start_reading(request, book_id):
|
||||||
readthrough.save()
|
readthrough.save()
|
||||||
|
|
||||||
# create a progress update if we have a page
|
# create a progress update if we have a page
|
||||||
if readthrough.pages_read:
|
readthrough.create_update()
|
||||||
readthrough.progressupdate_set.create(
|
|
||||||
user=request.user,
|
|
||||||
progress=readthrough.pages_read,
|
|
||||||
mode=models.ProgressMode.PAGE)
|
|
||||||
|
|
||||||
# shelve the book
|
# shelve the book
|
||||||
if request.POST.get('reshelve', True):
|
if request.POST.get('reshelve', True):
|
||||||
|
@ -440,10 +436,7 @@ def edit_readthrough(request):
|
||||||
|
|
||||||
# record the progress update individually
|
# record the progress update individually
|
||||||
# use default now for date field
|
# use default now for date field
|
||||||
readthrough.progressupdate_set.create(
|
readthrough.create_update()
|
||||||
user=request.user,
|
|
||||||
progress=readthrough.pages_read,
|
|
||||||
mode=models.ProgressMode.PAGE)
|
|
||||||
|
|
||||||
return redirect(request.headers.get('Referer', '/'))
|
return redirect(request.headers.get('Referer', '/'))
|
||||||
|
|
||||||
|
@ -750,11 +743,19 @@ def update_readthrough(request, book=None, create=True):
|
||||||
except ParserError:
|
except ParserError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
pages_read = request.POST.get('pages_read')
|
progress = request.POST.get('progress')
|
||||||
if pages_read:
|
if progress:
|
||||||
try:
|
try:
|
||||||
pages_read = int(pages_read)
|
progress = int(progress)
|
||||||
readthrough.pages_read = pages_read
|
readthrough.progress = progress
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
progress_mode = request.POST.get('progress_mode')
|
||||||
|
if progress_mode:
|
||||||
|
try:
|
||||||
|
progress_mode = models.ProgressMode(progress_mode)
|
||||||
|
readthrough.progress_mode = progress_mode
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -564,7 +564,7 @@ def book_page(request, book_id):
|
||||||
|
|
||||||
for readthrough in readthroughs:
|
for readthrough in readthroughs:
|
||||||
readthrough.progress_updates = \
|
readthrough.progress_updates = \
|
||||||
readthrough.progressupdate_set.all().order_by('updated_date')
|
readthrough.progressupdate_set.all().order_by('-updated_date')
|
||||||
|
|
||||||
rating = reviews.aggregate(Avg('rating'))
|
rating = reviews.aggregate(Avg('rating'))
|
||||||
tags = models.Tag.objects.filter(
|
tags = models.Tag.objects.filter(
|
||||||
|
|
Loading…
Reference in a new issue