keys.scala, etc.: Make merging public keys have a progress bar.
[tripe-android] / progress.scala
CommitLineData
c8292b34
MW
1/* -*-scala-*-
2 *
3 * Reporting progress for long-running jobs
4 *
5 * (c) 2018 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Trivial IP Encryption (TrIPE) Android app.
11 *
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
24 */
25
68df6e8f 26package uk.org.distorted.tripe; package object progress {
c8292b34
MW
27
28/*----- Imports -----------------------------------------------------------*/
29
68df6e8f
MW
30import scala.collection.mutable.{Publisher, Subscriber};
31
68df6e8f 32import java.lang.System.currentTimeMillis;
c8292b34 33
04a5abae 34/*----- Progress displays -------------------------------------------------*/
c8292b34 35
04a5abae
MW
36trait Model {
37 protected val t0 = currentTimeMillis;
c8292b34 38
04a5abae
MW
39 def what: String;
40 def max: Long;
c8292b34 41
04a5abae 42 def eta(cur: Long): Double = {
c8292b34
MW
43 /* Report the estimated time remaining in seconds, or -1 if no idea.
44 *
04a5abae
MW
45 * The model here is very stupid. Weird jobs should override this and
46 * do something more sensible.
c8292b34
MW
47 */
48
04a5abae
MW
49 val max = this.max;
50 val delta = currentTimeMillis - t0
51 if (max < 0 || cur <= 0) -1 else delta*(max - cur)/cur.toDouble
68df6e8f
MW
52 }
53
04a5abae 54 protected def fmt1(n: Long): String = n.toString;
68df6e8f 55
04a5abae
MW
56 def format(cur: Long): String = {
57 val max = this.max;
58 val fc = fmt1(cur);
59 if (max >= 0) { val fm = fmt1(max); s"%${fm.length}s/%s".format(fc, fm) }
60 else if (cur > 0) fc
61 else ""
68df6e8f 62 }
04a5abae 63}
68df6e8f 64
04a5abae 65class SimpleModel(val what: String, val max: Long) extends Model;
68df6e8f 66
b1ec59e3
MW
67class DetailedModel(what: String, max: Long) extends SimpleModel(what, max) {
68 var detail: String = null;
69 override def format(cur: Long): String = {
70 val sb = new StringBuilder;
71 sb ++= super.format(cur);
72 if (detail != null) { sb += ' '; sb ++= detail; }
73 sb.result
74 }
75}
76
04a5abae 77private val UDATA = Seq("kB", "MB", "GB", "TB", "PB", "EB");
68df6e8f 78
04a5abae
MW
79trait DataModel extends Model {
80 override def fmt1(n: Long): String = {
81 val (x, u) = ((n.toDouble, "B ") /: UDATA) { (xu, n) => (xu, n) match {
82 case ((x, u), name) if x >= 1024.0 => (x/1024.0, name)
83 case (xu, _) => xu
84 } }
85 f"$x%6.1f$u%s"
68df6e8f
MW
86 }
87}
88
04a5abae
MW
89trait BaseReporter {
90 def done();
91 def failed(e: Exception);
92}
68df6e8f 93
04a5abae
MW
94trait JobReporter extends BaseReporter {
95 def step(cur: Long);
96 def change(model: Model, cur: Long);
c8292b34
MW
97}
98
04a5abae
MW
99trait OperationReporter extends BaseReporter {
100 def step(detail: String);
101}
68df6e8f 102
b1ec59e3 103def withReporter[T, P <: BaseReporter](rep: P, body: P => T): T = {
04a5abae
MW
104 val ret = try { body(rep) }
105 catch { case e: Exception => rep.failed(e); throw e; }
106 rep.done();
107 ret
108}
68df6e8f 109
04a5abae
MW
110trait Eyecandy {
111 def note(msg: String);
112 def clear();
113 def commit();
114 def record(msg: String) { note(msg); commit(); }
115 def done();
116 def cancelled() { failed("cancelled"); }
117 def failed(msg: String);
68df6e8f 118
04a5abae
MW
119 def beginJob(model: Model): JobReporter
120 // = new JobReporter(model);
68df6e8f 121
04a5abae
MW
122 def beginOperation(what: String): OperationReporter
123 // = new OperationReporter(what);
68df6e8f 124
04a5abae
MW
125 def job[T](model: Model)(body: JobReporter => T): T =
126 withReporter(beginJob(model), body);
68df6e8f 127
04a5abae
MW
128 def operation[T](what: String)(body: OperationReporter => T): T =
129 withReporter(beginOperation(what), body);
68df6e8f
MW
130}
131
c8292b34 132/*----- That's all, folks -------------------------------------------------*/
68df6e8f
MW
133
134}