├── 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 | ![SS](https://cloud.githubusercontent.com/assets/7448243/17271026/5c50f7c8-5668-11e6-80f2-9d19ce1de029.png) 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 | --------------------------------------------------------------------------------