diff --git a/push-uploader/src/main/resources/stravaUpload16.png b/push-uploader/src/main/resources/stravaUpload16.png new file mode 100644 index 00000000..0ff7d830 Binary files /dev/null and b/push-uploader/src/main/resources/stravaUpload16.png differ diff --git a/push-uploader/src/main/resources/stravaUpload32.png b/push-uploader/src/main/resources/stravaUpload32.png new file mode 100644 index 00000000..233eab98 Binary files /dev/null and b/push-uploader/src/main/resources/stravaUpload32.png differ diff --git a/push-uploader/src/main/scala/com/github/opengrabeso/stravamat/Start.scala b/push-uploader/src/main/scala/com/github/opengrabeso/stravamat/Start.scala index a604f74e..afd0f561 100644 --- a/push-uploader/src/main/scala/com/github/opengrabeso/stravamat/Start.scala +++ b/push-uploader/src/main/scala/com/github/opengrabeso/stravamat/Start.scala @@ -17,7 +17,7 @@ import akka.stream.{ActorMaterializer, BindFailedException} import akka.util.ByteString import scala.concurrent.duration.Duration -import scala.concurrent.{Await, Future, duration} +import scala.concurrent.{Await, Future, Promise, duration} import scala.util.Try import scala.xml.Elem import org.joda.time.{DateTimeZone, DateTime => 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 ea1ed656..233eab98 100644 Binary files a/work/stravaUpload32.png and b/work/stravaUpload32.png differ diff --git a/work/stravaUpload64.png b/work/stravaUpload64.png new file mode 100644 index 00000000..ea1ed656 Binary files /dev/null and b/work/stravaUpload64.png differ