mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
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:
parent
fd835d9b64
commit
fbbbbd6a7d
6 changed files with 39 additions and 20 deletions
|
@ -307,8 +307,9 @@ message TranslateArgValue {
|
|||
|
||||
message FormatTimeSpanIn {
|
||||
enum Context {
|
||||
NORMAL = 0;
|
||||
PRECISE = 0;
|
||||
ANSWER_BUTTONS = 1;
|
||||
INTERVALS = 2;
|
||||
}
|
||||
|
||||
float seconds = 1;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue