├── dist
├── style.css
├── lowtick.wav
├── lib
│ └── themes
│ │ └── default
│ │ └── assets
│ │ └── fonts
│ │ ├── icons.eot
│ │ ├── icons.ttf
│ │ ├── icons.woff
│ │ └── icons.woff2
├── index.html
├── ports.js
└── main.js
├── src
├── Model.elm
├── Main.elm
├── Update.elm
└── View.elm
├── elm-package.json
├── package.json
├── README.md
└── .gitignore
/dist/style.css:
--------------------------------------------------------------------------------
1 | #main-container {
2 | padding-top: 1em;
3 | }
--------------------------------------------------------------------------------
/dist/lowtick.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickSeagull/wihere/HEAD/dist/lowtick.wav
--------------------------------------------------------------------------------
/dist/lib/themes/default/assets/fonts/icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickSeagull/wihere/HEAD/dist/lib/themes/default/assets/fonts/icons.eot
--------------------------------------------------------------------------------
/dist/lib/themes/default/assets/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickSeagull/wihere/HEAD/dist/lib/themes/default/assets/fonts/icons.ttf
--------------------------------------------------------------------------------
/dist/lib/themes/default/assets/fonts/icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickSeagull/wihere/HEAD/dist/lib/themes/default/assets/fonts/icons.woff
--------------------------------------------------------------------------------
/dist/lib/themes/default/assets/fonts/icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickSeagull/wihere/HEAD/dist/lib/themes/default/assets/fonts/icons.woff2
--------------------------------------------------------------------------------
/src/Model.elm:
--------------------------------------------------------------------------------
1 | module Model exposing (..)
2 |
3 | type alias Model =
4 | { refreshSeconds : Int
5 | , playing : Bool
6 | , currentSeconds : Int
7 | }
8 |
--------------------------------------------------------------------------------
/elm-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "summary": "helpful summary of your project, less than 80 characters",
4 | "repository": "https://github.com/user/project.git",
5 | "license": "BSD3",
6 | "source-directories": [
7 | "./src"
8 | ],
9 | "exposed-modules": [],
10 | "dependencies": {
11 | "elm-lang/core": "4.0.3 <= v < 5.0.0",
12 | "elm-lang/html": "1.1.0 <= v < 2.0.0"
13 | },
14 | "elm-version": "0.17.1 <= v < 0.18.0"
15 | }
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wihere",
3 | "version": "0.0.1",
4 | "description": "Wireless Headphone Refresher",
5 | "main": "dist/main.js",
6 | "scripts": {
7 | "build": "elm make src/Main.elm --output dist/elm.js || true",
8 | "watch": "chokidar '**/*.elm' -c 'npm run build'",
9 | "start": "electron dist/main.js"
10 | },
11 | "author": "Nikita Tchayka",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "electron": "^1.3.1",
15 | "electron-prebuilt": "^1.3.1",
16 | "jquery": "^3.1.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wihere
2 | ## Wireless Headphone Refresher
3 |
4 | 
5 |
6 | Wireless Headphones are great, they are wireless! But sometimes there are
7 | annoying things like having interferences, or even worse, sometimes they even
8 | start producing white noise after a while without sound, or even they turn off.
9 |
10 | This utility helps to fix this problem by playing a really low sound on a given
11 | interval of seconds.
12 |
13 | ## Downloads
14 | Download it in the [releases page](https://github.com/NickSeagull/wihere/releases)
15 |
16 |
--------------------------------------------------------------------------------
/src/Main.elm:
--------------------------------------------------------------------------------
1 | module Main exposing (..)
2 | import Html.App as App
3 | import Html.Events exposing (..)
4 | import Time exposing (Time ,second)
5 | import Task
6 | import View exposing (view)
7 | import Update exposing (..)
8 |
9 |
10 | main = App.program
11 | { init = init
12 | , view = view
13 | , update = update
14 | , subscriptions = subscriptions
15 | }
16 |
17 |
18 | subscriptions model =
19 | Time.every second Tick
20 |
21 | init = ({refreshSeconds = 0, playing = False, currentSeconds = 0}, Cmd.none)
22 |
23 | initialMessage : Msg -> Cmd Msg
24 | initialMessage msg = Task.perform identity identity (Task.succeed msg)
25 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Wihere
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/dist/ports.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global Elm */ // This will keep your linter happy
3 | var lowTick = new Audio('lowtick.wav');
4 | var $ = require('jquery');
5 | var totalSeconds = 0;
6 | var currentSeconds = 0;
7 |
8 | app.ports.js_playSound.subscribe(function(){
9 | lowTick.play();
10 | });
11 |
12 | app.ports.js_initProgress.subscribe(function(totalNumber){
13 | totalSeconds = totalNumber;
14 | currentSeconds = 0;
15 | $("#progress-bar").progress('reset');
16 | $("#progress-bar").progress({
17 | total: totalNumber
18 | });
19 | });
20 |
21 | app.ports.js_incrementProgress.subscribe(function(){
22 | if (totalSeconds <= currentSeconds){
23 | currentSeconds = 0;
24 | $("#progress-bar").progress('reset');
25 | }
26 | currentSeconds++;
27 | $("#progress-bar").progress('increment');
28 | });
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/node,elm
3 |
4 | ### Node ###
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # node-waf configuration
29 | .lock-wscript
30 |
31 | # Compiled binary addons (http://nodejs.org/api/addons.html)
32 | build/Release
33 |
34 | # Dependency directories
35 | node_modules
36 | jspm_packages
37 |
38 | # Optional npm cache directory
39 | .npm
40 |
41 | # Optional REPL history
42 | .node_repl_history
43 |
44 |
45 | ### Elm ###
46 | # elm-package generated files
47 | elm-stuff/
48 | # elm-repl generated files
49 | repl-temp-*
50 | dist/elm.js
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const electron = require('electron')
3 |
4 | const app = electron.app // this is our app
5 | const BrowserWindow = electron.BrowserWindow // This is a Module that creates windows
6 |
7 | let mainWindow // saves a global reference to mainWindow so it doesn't get garbage collected
8 |
9 | app.on('ready', createWindow) // called when electron has initialized
10 |
11 | // This will create our app window, no surprise there
12 | function createWindow () {
13 | mainWindow = new BrowserWindow({
14 | width: 350,
15 | height: 175,
16 | resizable: false
17 | })
18 |
19 | // display the index.html file
20 | mainWindow.loadURL(`file://${ __dirname }/index.html`)
21 |
22 | // open dev tools by default so we can see any console errors
23 | // mainWindow.webContents.openDevTools()
24 |
25 | mainWindow.on('closed', function () {
26 | mainWindow = null
27 | })
28 | }
29 |
30 | /* Mac Specific things */
31 |
32 | // when you close all the windows on a non-mac OS it quits the app
33 | app.on('window-all-closed', () => {
34 | if (process.platform !== 'darwin') { app.quit() }
35 | })
36 |
37 | // if there is no mainWindow it creates one (like when you click the dock icon)
38 | app.on('activate', () => {
39 | if (mainWindow === null) { createWindow() }
40 | })
41 |
42 |
--------------------------------------------------------------------------------
/src/Update.elm:
--------------------------------------------------------------------------------
1 | port module Update exposing (..)
2 | import Time exposing (Time)
3 | import Task
4 |
5 |
6 | type Msg
7 | = TogglePlay
8 | | UpdateRefreshRate Int
9 | | Tick Time
10 | | InitializeProgressBar
11 |
12 | update msg model =
13 | case msg of
14 | TogglePlay ->
15 | ( togglePlay model, Cmd.none )
16 | UpdateRefreshRate seconds ->
17 | ( updateRefreshRate seconds model, afterUpdate )
18 | InitializeProgressBar ->
19 | ( resetTime model, maybeInitProgressBar model )
20 | Tick _ ->
21 | ( ticked model, afterTick model )
22 |
23 | afterUpdate : Cmd Msg
24 | afterUpdate = Task.perform identity identity (Task.succeed InitializeProgressBar)
25 |
26 | afterTick model =
27 | if model.currentSeconds >= model.refreshSeconds
28 | then Cmd.batch [maybePlay model, maybeInitProgressBar model]
29 | else maybeIncrementProgressBar model
30 |
31 | togglePlay model =
32 | { model | playing = not model.playing }
33 |
34 | updateRefreshRate seconds model =
35 | { model | refreshSeconds = seconds }
36 |
37 | ticked model =
38 | if model.playing
39 | then { model | currentSeconds =
40 | if model.currentSeconds >= model.refreshSeconds
41 | then 0
42 | else model.currentSeconds + 1
43 | }
44 | else model
45 |
46 | resetTime model = { model | currentSeconds = 0 }
47 |
48 | maybeInitProgressBar model =
49 | if not model.playing
50 | then js_initProgress model.refreshSeconds
51 | else Cmd.none
52 |
53 | maybePlay model =
54 | if model.playing
55 | then js_playSound ()
56 | else Cmd.none
57 |
58 | maybeIncrementProgressBar model =
59 | if model.playing
60 | then js_incrementProgress ()
61 | else Cmd.none
62 |
63 | port js_playSound : () -> Cmd msg
64 | port js_incrementProgress : () -> Cmd msg
65 | port js_initProgress: Int -> Cmd msg
66 |
--------------------------------------------------------------------------------
/src/View.elm:
--------------------------------------------------------------------------------
1 | module View exposing (view)
2 | import Model exposing (Model)
3 | import Update exposing (Msg(..))
4 | import Html exposing (..)
5 | import Html.Attributes exposing (..)
6 | import Html.Events exposing (..)
7 | import String exposing (toInt)
8 |
9 | playingButton : Model -> Html Msg
10 | playingButton model =
11 | let
12 | status = if model.playing then "active" else ""
13 | statusIcon = if model.playing then "pause" else "play"
14 | in
15 | button
16 | [ class <| "ui " ++ status ++ " icon button"
17 | , onClick TogglePlay
18 | ]
19 | [ i [ class <| statusIcon ++ " icon" ] []
20 | ]
21 |
22 | progressBar model =
23 | let
24 | playingColor = if model.playing then "success" else ""
25 | in
26 | div
27 | [ class "centered row" ]
28 | [ div
29 | [ class "sixteen wide column" ]
30 | [ div
31 | [ class <| "ui indicating progress " ++ playingColor
32 | , attribute "data-percent" "74"
33 | , id "progress-bar"
34 | ]
35 | [ div
36 | [ class "bar" ]
37 | []
38 | , div
39 | [ class "label" ]
40 | []
41 | ]
42 | ]
43 | ]
44 |
45 | view : Model -> Html Msg
46 | view model =
47 | div
48 | [ class "ui grid container"
49 | ]
50 | [ div
51 | [ class "row" ]
52 | []
53 | , div
54 | [ class "center aligned row" ]
55 | [ div
56 | [ class "sixteen wide column" ]
57 | [ div
58 | [ class "ui fluid massive transparent right action icon input"]
59 | [ input
60 | [ type' "number"
61 | , id "number"
62 | , placeholder "Seconds"
63 | , onInput saveRefreshRate
64 | , Html.Attributes.min "1"
65 | , disabled model.playing
66 | ] []
67 | , playingButton model
68 | ]
69 | ]
70 | ]
71 | , progressBar model
72 | ]
73 |
74 | saveRefreshRate : String -> Msg
75 | saveRefreshRate s =
76 | case toInt s of
77 | Ok number ->
78 | UpdateRefreshRate number
79 | Err _ ->
80 | UpdateRefreshRate 1
81 |
--------------------------------------------------------------------------------