Skip to content

Commit 5fb739c

Browse files
EKIRJASTO-341 Show position in queue in holds, remove time estimate (#203)
* Show queue in holds, remove time estimate As the time estimate is unreliable, remove it and prefer showing your position in the queue. To match iOS and to show more information to the user, show how many copies are currently in "circulation" aka how many copies of the book we have. * Fix tests * Fix spacing
1 parent 22894a3 commit 5fb739c

File tree

11 files changed

+53
-40
lines changed

11 files changed

+53
-40
lines changed

simplified-books-borrowing/src/main/java/org/nypl/simplified/books/borrowing/internal/BorrowLoanCreate.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ class BorrowLoanCreate private constructor() : BorrowSubtaskType {
224224
queuePosition = a.positionOrNull,
225225
startDate = a.startDateOrNull,
226226
isRevocable = a.revoke.isSome,
227+
copiesTotal = a.copiesOrNull,
227228
endDate = a.endDateOrNull
228229
)
229230
)

simplified-books-registry-api/src/main/java/org/nypl/simplified/books/book_registry/BookStatus.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ sealed class BookStatus {
7272

7373
val startDate: DateTime?,
7474

75+
/**
76+
* @return The number of copies for this book
77+
*/
78+
79+
val copiesTotal: Int?,
80+
7581
override val isRevocable: Boolean,
7682
override val endDate: DateTime?
7783
) : Held() {
@@ -480,6 +486,7 @@ sealed class BookStatus {
480486
queuePosition = this.someOrNull(a.position),
481487
startDate = this.someOrNull(a.startDate),
482488
endDate = this.someOrNull(a.endDate),
489+
copiesTotal = this.someOrNull(a.copies),
483490
isRevocable = a.revoke.isSome
484491
)
485492
}

simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAcquisitionFeedEntryParser.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,11 +802,16 @@ private OPDSAvailabilityType inferAvailability(
802802
final OptionType<DateTime> start_date =
803803
OPDSXML.getAttributeRFC3339Optional(available, "since");
804804
OptionType<Integer> queue = Option.none();
805+
OptionType<Integer> copies = Option.none();
805806
if (holds_opt.isSome()) {
806807
final Some<Element> holds_some = (Some<Element>) holds_opt;
807808
queue = OPDSXML.getAttributeIntegerOptional(holds_some.get(), "position");
808809
}
809-
return OPDSAvailabilityHeld.get(start_date, queue, end_date, revoke);
810+
if (copies_opt.isSome()) {
811+
final Some<Element> copies_some = (Some<Element>) copies_opt;
812+
copies = OPDSXML.getAttributeIntegerOptional(copies_some.get(), "total");
813+
}
814+
return OPDSAvailabilityHeld.get(start_date, queue, end_date, copies, revoke);
810815
}
811816

812817
if ("available".equals(status)) {

simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSAvailabilityHeld.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import java.net.URI
1313
data class OPDSAvailabilityHeld private constructor(
1414
val startDate: OptionType<DateTime>,
1515
val position: OptionType<Int>,
16+
val copies: OptionType<Int>,
1617
private val endDate: OptionType<DateTime>,
1718

1819
/**
@@ -35,6 +36,9 @@ data class OPDSAvailabilityHeld private constructor(
3536
val positionOrNull: Int?
3637
get() = this.position.getOrNull()
3738

39+
val copiesOrNull: Int?
40+
get() = this.copies.getOrNull()
41+
3842
/**
3943
* @return The date that the hold will become unavailable
4044
*/
@@ -54,6 +58,8 @@ data class OPDSAvailabilityHeld private constructor(
5458
val b = StringBuilder(256)
5559
b.append("[OPDSAvailabilityHeld position=")
5660
b.append(this.position)
61+
b.append(" copies=")
62+
b.append(this.copies)
5763
b.append(" start_date=")
5864
this.startDate.map { e: DateTime? ->
5965
b.append(fmt.print(e))
@@ -77,6 +83,7 @@ data class OPDSAvailabilityHeld private constructor(
7783
* @param startDate The start date (if known)
7884
* @param position The queue position
7985
* @param endDate The end date (if known)
86+
* @param copies The number of copies for the book
8087
* @param revoke An optional revocation link for the hold
8188
* @return A value that states that a book is on hold
8289
*/
@@ -86,12 +93,14 @@ data class OPDSAvailabilityHeld private constructor(
8693
startDate: OptionType<DateTime>,
8794
position: OptionType<Int>,
8895
endDate: OptionType<DateTime>,
96+
copies: OptionType<Int>,
8997
revoke: OptionType<URI>
9098
): OPDSAvailabilityHeld {
9199
return OPDSAvailabilityHeld(
92100
startDate = startDate,
93101
position = position,
94102
endDate = endDate,
103+
copies = copies,
95104
revoke = revoke
96105
)
97106
}

simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,11 @@ private static OPDSAvailabilityType parseAvailability(
183183
JSONParserUtilities.getIntegerOptional(n, "position");
184184
final OptionType<DateTime> in_end_date =
185185
JSONParserUtilities.getTimestampOptional(n, "end_date");
186+
final OptionType<Integer> in_copies =
187+
JSONParserUtilities.getIntegerOptional(n, "total");
186188
final OptionType<URI> in_revoke =
187189
JSONParserUtilities.getURIOptional(n, "revoke");
188-
return OPDSAvailabilityHeld.get(in_start_date, in_position, in_end_date, in_revoke);
190+
return OPDSAvailabilityHeld.get(in_start_date, in_position, in_end_date, in_copies, in_revoke);
189191
}
190192

191193
if (node.has("held_ready")) {

simplified-opds-core/src/main/java/org/nypl/simplified/opds/core/OPDSJSONSerializer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ public ObjectNode onHeld(final OPDSAvailabilityHeld a) {
163163
oh.put("position", x);
164164
return Unit.unit();
165165
});
166+
a.getCopies().map(x -> {
167+
oh.put("total", x);
168+
return Unit.unit();
169+
});
166170
a.getRevoke().map(uri -> {
167171
oh.put("revoke", uri.toString());
168172
return Unit.unit();

simplified-tests/src/test/java/org/nypl/simplified/tests/accessibility/AccessibilityServiceTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class AccessibilityServiceTest {
261261
this.bookRegistry.update(
262262
BookWithStatus(
263263
book = this.book0,
264-
status = BookStatus.Held.HeldInQueue(this.book0.id, null, null, false, null)
264+
status = BookStatus.Held.HeldInQueue(this.book0.id, null, null, null, false, null)
265265
)
266266
)
267267

simplified-tests/src/test/java/org/nypl/simplified/tests/books/controller/BookRevokeTaskTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ class BookRevokeTaskTest {
960960
Option.none(),
961961
Option.none(),
962962
Option.none(),
963+
Option.none(),
963964
Option.some(this.server.url("revoke").toUri())
964965
)
965966
)
@@ -1093,6 +1094,7 @@ class BookRevokeTaskTest {
10931094
Option.none(),
10941095
Option.none(),
10951096
Option.none(),
1097+
Option.none(),
10961098
Option.none()
10971099
)
10981100
)

simplified-tests/src/test/java/org/nypl/simplified/tests/opds/OPDSFeedEntryParserTest.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,12 @@ public void testEntryAvailabilityHeldIndefinite()
164164
final OptionType<DateTime> expected_start_date = Option.some(
165165
OPDSDateParsers.dateTimeParser().parseDateTime("2000-01-01T00:00:00Z"));
166166
final OptionType<Integer> queue_position = Option.none();
167+
final OptionType<Integer> copies_total = Option.some(1);
167168
final OptionType<DateTime> expected_end_date = Option.none();
168169
final OptionType<URI> expected_revoke =
169170
Option.some(new URI("http://example.com/revoke"));
170171
final OPDSAvailabilityHeld expected = OPDSAvailabilityHeld.get(
171-
expected_start_date, queue_position, expected_end_date, expected_revoke);
172+
expected_start_date, queue_position, expected_end_date, copies_total,expected_revoke);
172173

173174
Assertions.assertEquals(expected, availability);
174175
Assertions.assertEquals(1, e.getAcquisitions().size());
@@ -196,10 +197,11 @@ public void testEntryAvailabilityHeldTimed()
196197
final OptionType<DateTime> expected_end_date = Option.some(
197198
OPDSDateParsers.dateTimeParser().parseDateTime("2010-01-01T00:00:00Z"));
198199
final OptionType<Integer> queue_position = Option.none();
200+
final OptionType<Integer> copies_total = Option.some(1);
199201
final OptionType<URI> expected_revoke =
200202
Option.some(new URI("http://example.com/revoke"));
201203
final OPDSAvailabilityHeld expected = OPDSAvailabilityHeld.get(
202-
expected_start_date, queue_position, expected_end_date, expected_revoke);
204+
expected_start_date, queue_position, expected_end_date, copies_total, expected_revoke);
203205

204206
Assertions.assertEquals(expected, availability);
205207
Assertions.assertEquals(1, e.getAcquisitions().size());
@@ -225,11 +227,12 @@ public void testEntryAvailabilityHeldIndefiniteQueued()
225227
final OptionType<DateTime> expected_start_date = Option.some(
226228
OPDSDateParsers.dateTimeParser().parseDateTime("2000-01-01T00:00:00Z"));
227229
final OptionType<Integer> queue_position = Option.some(3);
230+
final OptionType<Integer> copies_total = Option.some(1);
228231
final OptionType<DateTime> expected_end_date = Option.none();
229232
final OptionType<URI> expected_revoke =
230233
Option.some(new URI("http://example.com/revoke"));
231234
final OPDSAvailabilityHeld expected = OPDSAvailabilityHeld.get(
232-
expected_start_date, queue_position, expected_end_date, expected_revoke);
235+
expected_start_date, queue_position, expected_end_date,copies_total, expected_revoke);
233236

234237
Assertions.assertEquals(expected, availability);
235238
Assertions.assertEquals(1, e.getAcquisitions().size());
@@ -257,10 +260,11 @@ public void testEntryAvailabilityHeldTimedQueued()
257260
final OptionType<DateTime> expected_end_date = Option.some(
258261
OPDSDateParsers.dateTimeParser().parseDateTime("2010-01-01T00:00:00Z"));
259262
final OptionType<Integer> queue_position = Option.some(3);
263+
final OptionType<Integer> copies_total = Option.some(1);
260264
final OptionType<URI> expected_revoke =
261265
Option.some(new URI("http://example.com/revoke"));
262266
final OPDSAvailabilityHeld expected = OPDSAvailabilityHeld.get(
263-
expected_start_date, queue_position, expected_end_date, expected_revoke);
267+
expected_start_date, queue_position, expected_end_date, copies_total, expected_revoke);
264268

265269
Assertions.assertEquals(expected, availability);
266270
Assertions.assertEquals(1, e.getAcquisitions().size());

simplified-ui-catalog/src/main/java/org/librarysimplified/ui/catalog/CatalogBookAvailabilityStrings.kt

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.io7m.jfunctional.Some
77
import org.joda.time.DateTime
88
import org.joda.time.Hours
99
import org.nypl.simplified.books.book_registry.BookStatus
10+
import org.nypl.simplified.opds.core.getOrNull
1011
import java.util.concurrent.TimeUnit
1112

1213
/**
@@ -30,7 +31,7 @@ object CatalogBookAvailabilityStrings {
3031
): String {
3132
return when (status) {
3233
is BookStatus.Held.HeldInQueue ->
33-
onHeld(resources, Option.of(status.endDate), Option.of(status.queuePosition))
34+
onHeld(resources, Option.of(status.copiesTotal), Option.of(status.queuePosition))
3435
is BookStatus.Held.HeldReady ->
3536
onLoanable(resources)
3637
is BookStatus.Holdable ->
@@ -84,23 +85,10 @@ object CatalogBookAvailabilityStrings {
8485
status: BookStatus.Held.HeldInQueue
8586
): String {
8687
val queuePositionOpt : OptionType<Int> = Option.of(status.queuePosition)
87-
val endDateOpt : OptionType<DateTime> = Option.of(status.endDate)
88-
/*
89-
* If there is an availability date, show this in preference to
90-
* anything else.
91-
*/
92-
if (endDateOpt is Some<DateTime>) {
93-
val endDate = endDateOpt.get()
94-
val now = DateTime.now()
95-
return resources.getString(
96-
R.string.catalogBookAvailabilityHeldTimedShort,
97-
this.intervalStringHoldDuration(resources, now, endDate)
98-
)
99-
}
10088

101-
/*
102-
* If there is a queue position, attempt to show this instead.
103-
*/
89+
/**
90+
* If there is a queue position, attempt to show it.
91+
*/
10492

10593
if (queuePositionOpt is Some<Int>) {
10694
return resources.getString(R.string.catalogBookAvailabilityHeldQueueShort, queuePositionOpt.get())
@@ -173,28 +161,18 @@ object CatalogBookAvailabilityStrings {
173161

174162
private fun onHeld(
175163
resources: Resources,
176-
endDateOpt: OptionType<DateTime>,
164+
copiesTotalOpt: OptionType<Int>,
177165
queuePositionOpt: OptionType<Int>
178166
): String {
179-
/*
180-
* If there is an availability date, show this in preference to
181-
* anything else.
182-
*/
183-
184-
if (endDateOpt is Some<DateTime>) {
185-
val endDate = endDateOpt.get()
186-
val now = DateTime.now()
187-
return resources.getString(
188-
R.string.catalogBookAvailabilityHeldTimed,
189-
this.intervalString(resources, now, endDate)
190-
)
191-
}
192167

193-
/*
194-
* If there is a queue position, attempt to show this instead.
168+
/**
169+
* If there is a queue position, attempt to show it.
195170
*/
196171

197172
if (queuePositionOpt is Some<Int>) {
173+
if (copiesTotalOpt is Some<Int>) {
174+
return resources.getString(R.string.catalogBookAvailabilityHeldQueueWithCopies, queuePositionOpt.get(), copiesTotalOpt.getOrNull())
175+
}
198176
return resources.getString(R.string.catalogBookAvailabilityHeldQueue, queuePositionOpt.get())
199177
}
200178

simplified-ui-catalog/src/main/res/values/stringsCatalog.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<string name="catalogAccounts">Choose another library catalog…</string>
2424
<string name="catalogBookAvailabilityHeldIndefinite">You have this book on hold.</string>
2525
<string name="catalogBookAvailabilityHeldQueue">You are at position %1$d in the queue for this book.</string>
26+
<string name="catalogBookAvailabilityHeldQueueWithCopies">You are at position %1$d in the queue for %2$d copies of this book.</string>
2627
<string name="catalogBookAvailabilityHeldTimed">You will be able to borrow this book in %1$s.</string>
2728
<string name="catalogBookAvailabilityHeldIndefiniteShort">On hold</string>
2829
<string name="catalogBookAvailabilityHeldQueueShort">At position: %1$d</string>

0 commit comments

Comments
 (0)