tweak rounding

- avoid rounding minutes
- round the seconds taken in the card info screen
- provide different precise and imprecise modes, since we need
to display seconds to multiple decimals in some areas
This commit is contained in:
Damien Elmes 2020-02-25 17:29:06 +10:00
parent fd835d9b64
commit fbbbbd6a7d
6 changed files with 39 additions and 20 deletions

View file

@ -307,8 +307,9 @@ message TranslateArgValue {
message FormatTimeSpanIn {
enum Context {
NORMAL = 0;
PRECISE = 0;
ANSWER_BUTTONS = 1;
INTERVALS = 2;
}
float seconds = 1;

View file

@ -342,7 +342,7 @@ class RustBackend:
def format_time_span(
self,
seconds: float,
context: FormatTimeSpanContext = FormatTimeSpanContext.NORMAL,
context: FormatTimeSpanContext = FormatTimeSpanContext.INTERVALS,
) -> str:
return self._run_command(
pb.BackendInput(

View file

@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple
import anki
from anki.consts import *
from anki.lang import _, ngettext
from anki.rsbackend import FString
from anki.rsbackend import FormatTimeSpanContext, FString
from anki.utils import ids2str
# Card stats
@ -85,7 +85,9 @@ class CardStats:
return time.strftime("%Y-%m-%d", time.localtime(tm))
def time(self, tm: float) -> str:
return self.col.backend.format_time_span(tm)
return self.col.backend.format_time_span(
tm, context=FormatTimeSpanContext.PRECISE
)
# Collection stats

View file

@ -1503,7 +1503,7 @@ border: 1px solid #000; padding: 3px; '>%s</div>"""
s += ("<td align=right>%s</td>" * 2) % (
"%d%%" % (factor / 10) if factor else "",
cs.time(taken),
self.col.backend.format_time_span(taken)
) + "</tr>"
s += "</table>"
if cnt < self.card.reps:

View file

@ -422,7 +422,10 @@ impl Backend {
None => return "".to_string(),
};
match context {
pb::format_time_span_in::Context::Normal => time_span(input.seconds, &self.i18n),
pb::format_time_span_in::Context::Precise => time_span(input.seconds, &self.i18n, true),
pb::format_time_span_in::Context::Intervals => {
time_span(input.seconds, &self.i18n, false)
}
pb::format_time_span_in::Context::AnswerButtons => {
answer_button_time(input.seconds, &self.i18n)
}

View file

@ -6,13 +6,7 @@ use crate::i18n::{tr_args, FString, I18n};
/// Short string like '4d' to place above answer buttons.
pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String {
let span = Timespan::from_secs(seconds).natural_span();
let amount = match span.unit() {
// months/years shown with 1 decimal place
TimespanUnit::Months | TimespanUnit::Years => (span.as_unit() * 10.0).round() / 10.0,
// other values shown without decimals
_ => span.as_unit().round(),
};
let args = tr_args!["amount" => amount];
let args = tr_args!["amount" => span.as_rounded_unit()];
let key = match span.unit() {
TimespanUnit::Seconds => FString::SchedulingAnswerButtonTimeSeconds,
TimespanUnit::Minutes => FString::SchedulingAnswerButtonTimeMinutes,
@ -24,11 +18,17 @@ pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String {
i18n.trn(key, args)
}
/// Describe the given seconds using the largest appropriate unit
/// Describe the given seconds using the largest appropriate unit.
/// If precise is true, show to two decimal places, eg
/// eg 70 seconds -> "1.17 minutes"
pub fn time_span(seconds: f32, i18n: &I18n) -> String {
/// If false, seconds and days are shown without decimals.
pub fn time_span(seconds: f32, i18n: &I18n, precise: bool) -> String {
let span = Timespan::from_secs(seconds).natural_span();
let amount = span.as_unit();
let amount = if precise {
span.as_unit()
} else {
span.as_rounded_unit()
};
let args = tr_args!["amount" => amount];
let key = match span.unit() {
TimespanUnit::Seconds => FString::SchedulingTimeSpanSeconds,
@ -133,6 +133,17 @@ impl Timespan {
}
}
/// Round seconds and days to integers, otherwise
/// truncates to one decimal place.
fn as_rounded_unit(self) -> f32 {
match self.unit {
// seconds/days as integer
TimespanUnit::Seconds | TimespanUnit::Days => self.as_unit().round(),
// other values shown to 1 decimal place
_ => (self.as_unit() * 10.0).round() / 10.0,
}
}
fn unit(self) -> TimespanUnit {
self.unit
}
@ -173,16 +184,18 @@ mod test {
fn answer_buttons() {
let i18n = I18n::new(&["zz"], "");
assert_eq!(answer_button_time(30.0, &i18n), "30s");
assert_eq!(answer_button_time(70.0, &i18n), "1m");
assert_eq!(answer_button_time(70.0, &i18n), "1.2m");
assert_eq!(answer_button_time(1.1 * MONTH, &i18n), "1.1mo");
}
#[test]
fn time_spans() {
let i18n = I18n::new(&["zz"], "");
assert_eq!(time_span(1.0, &i18n), "1 second");
assert_eq!(time_span(30.0, &i18n), "30 seconds");
assert_eq!(time_span(90.0, &i18n), "1.5 minutes");
assert_eq!(time_span(1.0, &i18n, false), "1 second");
assert_eq!(time_span(30.3, &i18n, false), "30 seconds");
assert_eq!(time_span(30.3, &i18n, true), "30.3 seconds");
assert_eq!(time_span(90.0, &i18n, false), "1.5 minutes");
assert_eq!(time_span(45.0 * 86_400.0, &i18n, false), "1.5 months");
}
#[test]