From 8c0063350b6e8d33fedb4d8badb3181e12a28ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Thu, 7 Sep 2017 16:10:33 +0200 Subject: [PATCH] Basic tray icon working. --- .../src/main/resources/stravaUpload16.png | Bin 0 -> 662 bytes .../src/main/resources/stravaUpload32.png | Bin 0 -> 1207 bytes .../github/opengrabeso/stravamat/Start.scala | 85 +++++++++++++++++- .../opengrabeso/stravamat/DefineRequest.scala | 2 +- ...{stravaUpload32.png => stravaUpload64.png} | Bin work/stravaUpload32.png | Bin 1776 -> 1207 bytes work/stravaUpload64.png | Bin 0 -> 1776 bytes 7 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 push-uploader/src/main/resources/stravaUpload16.png create mode 100644 push-uploader/src/main/resources/stravaUpload32.png rename web/static/{stravaUpload32.png => stravaUpload64.png} (100%) create mode 100644 work/stravaUpload64.png diff --git a/push-uploader/src/main/resources/stravaUpload16.png b/push-uploader/src/main/resources/stravaUpload16.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff7d8300a3d52657543ed9c10e9e7443eb343c3 GIT binary patch literal 662 zcmV;H0%`q;P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700IU{L_t(IPmNN~YZE~johD6UY}#rHA|)0D zAsV75!Gi}qh$!q%ch@9ZqV!-9LA(iGO7~FkBH~#vhzBp?A0VhGp45XmMDXBA5VQwt z?3(QC%w|95$L_jGgZSXVeDC|-rhsP8QnHo&fD zWdO0}9wnRpx&?#x&mf7w=>oF~Lm|DTvMvLtG5awR>B?aUNI$dzwA*cU2m+w@t__6{ zYtO0*!1-@NU@K(+XHywC9LE9PmK0}!!G{;|H}P=cjtub3-LGZp?S>o@=yWI&!QugidbZGKG#G>S0z^cEhrT2Pppip>#)*1Bq{tLm9xYx(3Mt|PR0 z`NRUnSt1$?=YW|zV@76GPjj<+Exz?DX^zmZmu|`}M#x)|Nsa0`XRBGMNMi&5G{Jw< zyG%<5$zjnFjB2K5x^83Pv^0$asqMqmm}xU@QU-BJlHwfUYd>`_9X%ii{{`-t_|-gC w=GR(MC4%miGez0_AMjUPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^PVZl7ZS00bvVL_t(oN9|W#Y*S?zZYf)-D{N~=XA$fe z*qB``>X@jR6a@?cyR~PW+K%FWV@AUW$d%qyqM&zRFmhu|%rqgoJ1$HN34w59V$={4 ziQ-TgY^9W~TYGx`U%&74>)K<#wOxg9->JU-}4-is2=HnyOa0ZCuv6ID0#=tQkd(?yp{6Qn}VoC1TvNaRZ+ z7GbSCv$m?XFGVyQGMd0%Vo@6DVCxB*$iInKfYi4R#Ict_9BBiQX{5&GDEJ$0;pIzg z=(zLlJ54;(RJQd}Z#~H8PJ+s308|A)kwO0BDo8_{sqtBw;K6|B5V4{o8QwBTPtHBiH zq~{|FJ$3y35&wE(smHZwv{qp3w`qw|&;jafj98S0eEuxTF%@ZOI^LClHmL2yQje(v zopxMdQ4(r-=G0xGi*B&R9dL&T?#GWT~9T2}dPSlE_C<=r^A()t;Pe=@9>Q9h* zECmIi4)nQ?5=%YMo?VOf{i(tNl=GhxsbXMbqtOUXrxOy11bM56nv8?YSQquQIWV;C zHDaj;UIiTMx=>hvc=i~U$*L7#W@ZMOo10MzPBQ?@vY@KPamo#}H*}lxdZ@#RgFPEG zLmKA89m9nM$UX}wm%c?(d2!r&pU<~wj)^-lK0Zz&vQY2c2Ib#pT|Ja^OPlE_CC)NfR$u0KOBZS=WdE`MMs9c&uE&^(pUf(5;T83P8px z&p0l}N8aejDm)}ikA@u!eeH)c`<#~qU;Xqi+sy)ctrfug>Jx(B_8S-6bUHb>YwNPd zd%3{d_U;X~F8tGEG~D|2Sh((y|1+YX4G|B+P3`G1;Qs<1djWXTtwFSEPgTKS_y< ZonedDateTime} @@ -111,6 +111,73 @@ object Start extends App { useLocal } + private object Tray { + import java.awt.{SystemTray, TrayIcon, AWTException, Image} + import javax.swing.SwingUtilities + + private def showImpl() = { + assert(SwingUtilities.isEventDispatchThread) + import javax.imageio.ImageIO + // https://docs.oracle.com/javase/7/docs/api/java/awt/SystemTray.html + + if (SystemTray.isSupported) { + val tray = SystemTray.getSystemTray + val iconSize = tray.getTrayIconSize + val imageFile = if ((iconSize.height max iconSize.width) > 16) "/stravaUpload32.png" else "/stravaUpload16.png" + val is = getClass.getResourceAsStream(imageFile) + + val image = ImageIO.read(is) + val imageSized = image.getScaledInstance(iconSize.width, iconSize.height, Image.SCALE_SMOOTH) + + val trayIcon = new TrayIcon(imageSized, "Stravamat") + try { + tray.add(trayIcon) + } catch { + case e: AWTException => + e.printStackTrace() + } + Some(trayIcon) + } else { + None + } + } + + private def removeImpl(icon: TrayIcon): Unit = { + assert(SwingUtilities.isEventDispatchThread) + if (SystemTray.isSupported) { + val tray = SystemTray.getSystemTray + tray.remove(icon) + } + } + + private def changeStateImpl(icon: TrayIcon, state: =>String): Unit = { + assert(SwingUtilities.isEventDispatchThread) + val title = "Stravamat" + val text = if (state.isEmpty) title else title + ": " + state + icon.setToolTip(text) + } + + def show(): Option[TrayIcon] = { + val p = Promise[Option[TrayIcon]] + SwingUtilities.invokeLater(new Runnable { + override def run() = p.success(showImpl()) + }) + Await.result(p.future, Duration.Inf) + } + + def remove(icon: TrayIcon): Unit = { + SwingUtilities.invokeLater(new Runnable { + override def run() = removeImpl(icon) + }) + } + + def changeState(icon: TrayIcon, state: =>String): Unit = { + SwingUtilities.invokeLater(new Runnable { + override def run() = changeStateImpl(icon, state) + }) + } + } + private def startBrowser() = { /* Authentication dance @@ -213,6 +280,8 @@ object Start extends App { // sort files by timestamp val wantedFiles = listFiles.filter(MoveslinkFiles.timestampFromName(_).forall(_ > sinceDate)) + reportProgress(wantedFiles.size) + val sortedFiles = wantedFiles.sortBy(MoveslinkFiles.timestampFromName) val localTimeZone = DateTimeZone.getDefault.toString @@ -291,17 +360,27 @@ object Start extends App { f -> req } + reportProgress(reqs.size) - reqs.foreach { case (f, r) => + reqs.zipWithIndex.foreach { case ((f, r), i) => Await.result(r, Duration.Inf) // TODO: handle upload failures somehow println(s" Await upload $f status $r") + reportProgress(reqs.size + 1 - i) } serverInfo.system.terminate() } + val icon = Tray.show() + + def reportProgress(i: Int): Unit = { + def localSuffix = if (useLocal) " to local server" else "" + def state = s"Uploading $i files" + localSuffix + icon.foreach(Tray.changeState(_, state)) + } + checkLocalStravamat() private val serverInfo = startHttpServer(serverPort) @@ -318,5 +397,5 @@ object Start extends App { Await.result(serverInfo.system.whenTerminated, Duration.Inf) println("System stopped") - + icon.foreach(Tray.remove) } diff --git a/src/main/scala/com/github/opengrabeso/stravamat/DefineRequest.scala b/src/main/scala/com/github/opengrabeso/stravamat/DefineRequest.scala index 58df83f1..a77f7d68 100644 --- a/src/main/scala/com/github/opengrabeso/stravamat/DefineRequest.scala +++ b/src/main/scala/com/github/opengrabeso/stravamat/DefineRequest.scala @@ -59,7 +59,7 @@ abstract class DefineRequest(val handleUri: String, val method: Method = Method.
- + diff --git a/web/static/stravaUpload32.png b/web/static/stravaUpload64.png similarity index 100% rename from web/static/stravaUpload32.png rename to web/static/stravaUpload64.png diff --git a/work/stravaUpload32.png b/work/stravaUpload32.png index ea1ed6565c68043a6ba1e54c6f8518aa25fc5468..233eab981c5721e8a792f65eb12dbbd502f52553 100644 GIT binary patch delta 1135 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 S&D?tc0000