diff --git a/app.js b/app.js index d7e3b94..ef966a7 100644 --- a/app.js +++ b/app.js @@ -80,271 +80,6 @@ function A9(fun, a, b, c, d, e, f, g, h, i) { console.warn('Compiled in DEV mode. Follow the advice at https://elm-lang.org/0.19.1/optimize for better performance and smaller assets.'); -// EQUALITY - -function _Utils_eq(x, y) -{ - for ( - var pair, stack = [], isEqual = _Utils_eqHelp(x, y, 0, stack); - isEqual && (pair = stack.pop()); - isEqual = _Utils_eqHelp(pair.a, pair.b, 0, stack) - ) - {} - - return isEqual; -} - -function _Utils_eqHelp(x, y, depth, stack) -{ - if (x === y) - { - return true; - } - - if (typeof x !== 'object' || x === null || y === null) - { - typeof x === 'function' && _Debug_crash(5); - return false; - } - - if (depth > 100) - { - stack.push(_Utils_Tuple2(x,y)); - return true; - } - - /**/ - if (x.$ === 'Set_elm_builtin') - { - x = $elm$core$Set$toList(x); - y = $elm$core$Set$toList(y); - } - if (x.$ === 'RBNode_elm_builtin' || x.$ === 'RBEmpty_elm_builtin') - { - x = $elm$core$Dict$toList(x); - y = $elm$core$Dict$toList(y); - } - //*/ - - /**_UNUSED/ - if (x.$ < 0) - { - x = $elm$core$Dict$toList(x); - y = $elm$core$Dict$toList(y); - } - //*/ - - for (var key in x) - { - if (!_Utils_eqHelp(x[key], y[key], depth + 1, stack)) - { - return false; - } - } - return true; -} - -var _Utils_equal = F2(_Utils_eq); -var _Utils_notEqual = F2(function(a, b) { return !_Utils_eq(a,b); }); - - - -// COMPARISONS - -// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on -// the particular integer values assigned to LT, EQ, and GT. - -function _Utils_cmp(x, y, ord) -{ - if (typeof x !== 'object') - { - return x === y ? /*EQ*/ 0 : x < y ? /*LT*/ -1 : /*GT*/ 1; - } - - /**/ - if (x instanceof String) - { - var a = x.valueOf(); - var b = y.valueOf(); - return a === b ? 0 : a < b ? -1 : 1; - } - //*/ - - /**_UNUSED/ - if (typeof x.$ === 'undefined') - //*/ - /**/ - if (x.$[0] === '#') - //*/ - { - return (ord = _Utils_cmp(x.a, y.a)) - ? ord - : (ord = _Utils_cmp(x.b, y.b)) - ? ord - : _Utils_cmp(x.c, y.c); - } - - // traverse conses until end of a list or a mismatch - for (; x.b && y.b && !(ord = _Utils_cmp(x.a, y.a)); x = x.b, y = y.b) {} // WHILE_CONSES - return ord || (x.b ? /*GT*/ 1 : y.b ? /*LT*/ -1 : /*EQ*/ 0); -} - -var _Utils_lt = F2(function(a, b) { return _Utils_cmp(a, b) < 0; }); -var _Utils_le = F2(function(a, b) { return _Utils_cmp(a, b) < 1; }); -var _Utils_gt = F2(function(a, b) { return _Utils_cmp(a, b) > 0; }); -var _Utils_ge = F2(function(a, b) { return _Utils_cmp(a, b) >= 0; }); - -var _Utils_compare = F2(function(x, y) -{ - var n = _Utils_cmp(x, y); - return n < 0 ? $elm$core$Basics$LT : n ? $elm$core$Basics$GT : $elm$core$Basics$EQ; -}); - - -// COMMON VALUES - -var _Utils_Tuple0_UNUSED = 0; -var _Utils_Tuple0 = { $: '#0' }; - -function _Utils_Tuple2_UNUSED(a, b) { return { a: a, b: b }; } -function _Utils_Tuple2(a, b) { return { $: '#2', a: a, b: b }; } - -function _Utils_Tuple3_UNUSED(a, b, c) { return { a: a, b: b, c: c }; } -function _Utils_Tuple3(a, b, c) { return { $: '#3', a: a, b: b, c: c }; } - -function _Utils_chr_UNUSED(c) { return c; } -function _Utils_chr(c) { return new String(c); } - - -// RECORDS - -function _Utils_update(oldRecord, updatedFields) -{ - var newRecord = {}; - - for (var key in oldRecord) - { - newRecord[key] = oldRecord[key]; - } - - for (var key in updatedFields) - { - newRecord[key] = updatedFields[key]; - } - - return newRecord; -} - - -// APPEND - -var _Utils_append = F2(_Utils_ap); - -function _Utils_ap(xs, ys) -{ - // append Strings - if (typeof xs === 'string') - { - return xs + ys; - } - - // append Lists - if (!xs.b) - { - return ys; - } - var root = _List_Cons(xs.a, ys); - xs = xs.b - for (var curr = root; xs.b; xs = xs.b) // WHILE_CONS - { - curr = curr.b = _List_Cons(xs.a, ys); - } - return root; -} - - - -var _List_Nil_UNUSED = { $: 0 }; -var _List_Nil = { $: '[]' }; - -function _List_Cons_UNUSED(hd, tl) { return { $: 1, a: hd, b: tl }; } -function _List_Cons(hd, tl) { return { $: '::', a: hd, b: tl }; } - - -var _List_cons = F2(_List_Cons); - -function _List_fromArray(arr) -{ - var out = _List_Nil; - for (var i = arr.length; i--; ) - { - out = _List_Cons(arr[i], out); - } - return out; -} - -function _List_toArray(xs) -{ - for (var out = []; xs.b; xs = xs.b) // WHILE_CONS - { - out.push(xs.a); - } - return out; -} - -var _List_map2 = F3(function(f, xs, ys) -{ - for (var arr = []; xs.b && ys.b; xs = xs.b, ys = ys.b) // WHILE_CONSES - { - arr.push(A2(f, xs.a, ys.a)); - } - return _List_fromArray(arr); -}); - -var _List_map3 = F4(function(f, xs, ys, zs) -{ - for (var arr = []; xs.b && ys.b && zs.b; xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES - { - arr.push(A3(f, xs.a, ys.a, zs.a)); - } - return _List_fromArray(arr); -}); - -var _List_map4 = F5(function(f, ws, xs, ys, zs) -{ - for (var arr = []; ws.b && xs.b && ys.b && zs.b; ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES - { - arr.push(A4(f, ws.a, xs.a, ys.a, zs.a)); - } - return _List_fromArray(arr); -}); - -var _List_map5 = F6(function(f, vs, ws, xs, ys, zs) -{ - for (var arr = []; vs.b && ws.b && xs.b && ys.b && zs.b; vs = vs.b, ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES - { - arr.push(A5(f, vs.a, ws.a, xs.a, ys.a, zs.a)); - } - return _List_fromArray(arr); -}); - -var _List_sortBy = F2(function(f, xs) -{ - return _List_fromArray(_List_toArray(xs).sort(function(a, b) { - return _Utils_cmp(f(a), f(b)); - })); -}); - -var _List_sortWith = F2(function(f, xs) -{ - return _List_fromArray(_List_toArray(xs).sort(function(a, b) { - var ord = A2(f, a, b); - return ord === $elm$core$Basics$EQ ? 0 : ord === $elm$core$Basics$LT ? -1 : 1; - })); -}); - - - var _JsArray_empty = []; function _JsArray_singleton(value) @@ -793,6 +528,271 @@ function _Debug_regionToString(region) +// EQUALITY + +function _Utils_eq(x, y) +{ + for ( + var pair, stack = [], isEqual = _Utils_eqHelp(x, y, 0, stack); + isEqual && (pair = stack.pop()); + isEqual = _Utils_eqHelp(pair.a, pair.b, 0, stack) + ) + {} + + return isEqual; +} + +function _Utils_eqHelp(x, y, depth, stack) +{ + if (x === y) + { + return true; + } + + if (typeof x !== 'object' || x === null || y === null) + { + typeof x === 'function' && _Debug_crash(5); + return false; + } + + if (depth > 100) + { + stack.push(_Utils_Tuple2(x,y)); + return true; + } + + /**/ + if (x.$ === 'Set_elm_builtin') + { + x = $elm$core$Set$toList(x); + y = $elm$core$Set$toList(y); + } + if (x.$ === 'RBNode_elm_builtin' || x.$ === 'RBEmpty_elm_builtin') + { + x = $elm$core$Dict$toList(x); + y = $elm$core$Dict$toList(y); + } + //*/ + + /**_UNUSED/ + if (x.$ < 0) + { + x = $elm$core$Dict$toList(x); + y = $elm$core$Dict$toList(y); + } + //*/ + + for (var key in x) + { + if (!_Utils_eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; +} + +var _Utils_equal = F2(_Utils_eq); +var _Utils_notEqual = F2(function(a, b) { return !_Utils_eq(a,b); }); + + + +// COMPARISONS + +// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on +// the particular integer values assigned to LT, EQ, and GT. + +function _Utils_cmp(x, y, ord) +{ + if (typeof x !== 'object') + { + return x === y ? /*EQ*/ 0 : x < y ? /*LT*/ -1 : /*GT*/ 1; + } + + /**/ + if (x instanceof String) + { + var a = x.valueOf(); + var b = y.valueOf(); + return a === b ? 0 : a < b ? -1 : 1; + } + //*/ + + /**_UNUSED/ + if (typeof x.$ === 'undefined') + //*/ + /**/ + if (x.$[0] === '#') + //*/ + { + return (ord = _Utils_cmp(x.a, y.a)) + ? ord + : (ord = _Utils_cmp(x.b, y.b)) + ? ord + : _Utils_cmp(x.c, y.c); + } + + // traverse conses until end of a list or a mismatch + for (; x.b && y.b && !(ord = _Utils_cmp(x.a, y.a)); x = x.b, y = y.b) {} // WHILE_CONSES + return ord || (x.b ? /*GT*/ 1 : y.b ? /*LT*/ -1 : /*EQ*/ 0); +} + +var _Utils_lt = F2(function(a, b) { return _Utils_cmp(a, b) < 0; }); +var _Utils_le = F2(function(a, b) { return _Utils_cmp(a, b) < 1; }); +var _Utils_gt = F2(function(a, b) { return _Utils_cmp(a, b) > 0; }); +var _Utils_ge = F2(function(a, b) { return _Utils_cmp(a, b) >= 0; }); + +var _Utils_compare = F2(function(x, y) +{ + var n = _Utils_cmp(x, y); + return n < 0 ? $elm$core$Basics$LT : n ? $elm$core$Basics$GT : $elm$core$Basics$EQ; +}); + + +// COMMON VALUES + +var _Utils_Tuple0_UNUSED = 0; +var _Utils_Tuple0 = { $: '#0' }; + +function _Utils_Tuple2_UNUSED(a, b) { return { a: a, b: b }; } +function _Utils_Tuple2(a, b) { return { $: '#2', a: a, b: b }; } + +function _Utils_Tuple3_UNUSED(a, b, c) { return { a: a, b: b, c: c }; } +function _Utils_Tuple3(a, b, c) { return { $: '#3', a: a, b: b, c: c }; } + +function _Utils_chr_UNUSED(c) { return c; } +function _Utils_chr(c) { return new String(c); } + + +// RECORDS + +function _Utils_update(oldRecord, updatedFields) +{ + var newRecord = {}; + + for (var key in oldRecord) + { + newRecord[key] = oldRecord[key]; + } + + for (var key in updatedFields) + { + newRecord[key] = updatedFields[key]; + } + + return newRecord; +} + + +// APPEND + +var _Utils_append = F2(_Utils_ap); + +function _Utils_ap(xs, ys) +{ + // append Strings + if (typeof xs === 'string') + { + return xs + ys; + } + + // append Lists + if (!xs.b) + { + return ys; + } + var root = _List_Cons(xs.a, ys); + xs = xs.b + for (var curr = root; xs.b; xs = xs.b) // WHILE_CONS + { + curr = curr.b = _List_Cons(xs.a, ys); + } + return root; +} + + + +var _List_Nil_UNUSED = { $: 0 }; +var _List_Nil = { $: '[]' }; + +function _List_Cons_UNUSED(hd, tl) { return { $: 1, a: hd, b: tl }; } +function _List_Cons(hd, tl) { return { $: '::', a: hd, b: tl }; } + + +var _List_cons = F2(_List_Cons); + +function _List_fromArray(arr) +{ + var out = _List_Nil; + for (var i = arr.length; i--; ) + { + out = _List_Cons(arr[i], out); + } + return out; +} + +function _List_toArray(xs) +{ + for (var out = []; xs.b; xs = xs.b) // WHILE_CONS + { + out.push(xs.a); + } + return out; +} + +var _List_map2 = F3(function(f, xs, ys) +{ + for (var arr = []; xs.b && ys.b; xs = xs.b, ys = ys.b) // WHILE_CONSES + { + arr.push(A2(f, xs.a, ys.a)); + } + return _List_fromArray(arr); +}); + +var _List_map3 = F4(function(f, xs, ys, zs) +{ + for (var arr = []; xs.b && ys.b && zs.b; xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A3(f, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_map4 = F5(function(f, ws, xs, ys, zs) +{ + for (var arr = []; ws.b && xs.b && ys.b && zs.b; ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A4(f, ws.a, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_map5 = F6(function(f, vs, ws, xs, ys, zs) +{ + for (var arr = []; vs.b && ws.b && xs.b && ys.b && zs.b; vs = vs.b, ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A5(f, vs.a, ws.a, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_sortBy = F2(function(f, xs) +{ + return _List_fromArray(_List_toArray(xs).sort(function(a, b) { + return _Utils_cmp(f(a), f(b)); + })); +}); + +var _List_sortWith = F2(function(f, xs) +{ + return _List_fromArray(_List_toArray(xs).sort(function(a, b) { + var ord = A2(f, a, b); + return ord === $elm$core$Basics$EQ ? 0 : ord === $elm$core$Basics$LT ? -1 : 1; + })); +}); + + + // MATH var _Basics_add = F2(function(a, b) { return a + b; }); @@ -4628,10 +4628,31 @@ function _Time_getZoneName() callback(_Scheduler_succeed(name)); }); } -var $elm$core$Basics$EQ = {$: 'EQ'}; -var $elm$core$Basics$GT = {$: 'GT'}; -var $elm$core$Basics$LT = {$: 'LT'}; var $elm$core$List$cons = _List_cons; +var $elm$core$Elm$JsArray$foldr = _JsArray_foldr; +var $elm$core$Array$foldr = F3( + function (func, baseCase, _v0) { + var tree = _v0.c; + var tail = _v0.d; + var helper = F2( + function (node, acc) { + if (node.$ === 'SubTree') { + var subTree = node.a; + return A3($elm$core$Elm$JsArray$foldr, helper, acc, subTree); + } else { + var values = node.a; + return A3($elm$core$Elm$JsArray$foldr, func, acc, values); + } + }); + return A3( + $elm$core$Elm$JsArray$foldr, + helper, + A3($elm$core$Elm$JsArray$foldr, func, baseCase, tail), + tree); + }); +var $elm$core$Array$toList = function (array) { + return A3($elm$core$Array$foldr, $elm$core$List$cons, _List_Nil, array); +}; var $elm$core$Dict$foldr = F3( function (func, acc, t) { foldr: @@ -4684,30 +4705,9 @@ var $elm$core$Set$toList = function (_v0) { var dict = _v0.a; return $elm$core$Dict$keys(dict); }; -var $elm$core$Elm$JsArray$foldr = _JsArray_foldr; -var $elm$core$Array$foldr = F3( - function (func, baseCase, _v0) { - var tree = _v0.c; - var tail = _v0.d; - var helper = F2( - function (node, acc) { - if (node.$ === 'SubTree') { - var subTree = node.a; - return A3($elm$core$Elm$JsArray$foldr, helper, acc, subTree); - } else { - var values = node.a; - return A3($elm$core$Elm$JsArray$foldr, func, acc, values); - } - }); - return A3( - $elm$core$Elm$JsArray$foldr, - helper, - A3($elm$core$Elm$JsArray$foldr, func, baseCase, tail), - tree); - }); -var $elm$core$Array$toList = function (array) { - return A3($elm$core$Array$foldr, $elm$core$List$cons, _List_Nil, array); -}; +var $elm$core$Basics$EQ = {$: 'EQ'}; +var $elm$core$Basics$GT = {$: 'GT'}; +var $elm$core$Basics$LT = {$: 'LT'}; var $elm$core$Result$Err = function (a) { return {$: 'Err', a: a}; }; @@ -5103,6 +5103,7 @@ var $elm$core$Result$isOk = function (result) { return false; } }; +var $elm$json$Json$Decode$float = _Json_decodeFloat; var $elm$json$Json$Decode$map = _Json_map1; var $elm$json$Json$Decode$map2 = _Json_map2; var $elm$json$Json$Decode$succeed = _Json_succeed; @@ -5417,9 +5418,8 @@ var $elm$core$Task$perform = F2( A2($elm$core$Task$map, toMessage, task))); }); var $elm$browser$Browser$element = _Browser_element; -var $elm$json$Json$Decode$float = _Json_decodeFloat; var $elm$core$String$fromFloat = _String_fromNumber; -var $author$project$PhotoGroove$GotPhotos = function (a) { +var $author$project$PhotoGroove$Internal$GotPhotos = function (a) { return {$: 'GotPhotos', a: a}; }; var $elm$json$Json$Decode$decodeString = _Json_runOnString; @@ -6210,7 +6210,7 @@ var $elm$http$Http$get = function (r) { {body: $elm$http$Http$emptyBody, expect: r.expect, headers: _List_Nil, method: 'GET', timeout: $elm$core$Maybe$Nothing, tracker: $elm$core$Maybe$Nothing, url: r.url}); }; var $elm$json$Json$Decode$list = _Json_decodeList; -var $author$project$PhotoGroove$Photo = F3( +var $author$project$PhotoGroove$Internal$Photo = F3( function (url, size, title) { return {size: size, title: title, url: url}; }); @@ -6282,7 +6282,7 @@ var $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required = F3( decoder); }); var $elm$json$Json$Decode$string = _Json_decodeString; -var $author$project$PhotoGroove$photoDecoder = A4( +var $author$project$PhotoGroove$Internal$photoDecoder = A4( $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$optional, 'title', $elm$json$Json$Decode$string, @@ -6295,52 +6295,52 @@ var $author$project$PhotoGroove$photoDecoder = A4( $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required, 'url', $elm$json$Json$Decode$string, - $elm$json$Json$Decode$succeed($author$project$PhotoGroove$Photo)))); -var $author$project$PhotoGroove$initialCommand = $elm$http$Http$get( + $elm$json$Json$Decode$succeed($author$project$PhotoGroove$Internal$Photo)))); +var $author$project$PhotoGroove$Internal$initialCommand = $elm$http$Http$get( { expect: A2( $elm$http$Http$expectJson, - $author$project$PhotoGroove$GotPhotos, - $elm$json$Json$Decode$list($author$project$PhotoGroove$photoDecoder)), + $author$project$PhotoGroove$Internal$GotPhotos, + $elm$json$Json$Decode$list($author$project$PhotoGroove$Internal$photoDecoder)), url: 'list' }); -var $author$project$PhotoGroove$Loading = {$: 'Loading'}; -var $author$project$PhotoGroove$Medium = {$: 'Medium'}; -var $author$project$PhotoGroove$initialModel = { +var $author$project$PhotoGroove$Internal$Loading = {$: 'Loading'}; +var $author$project$PhotoGroove$Internal$Medium = {$: 'Medium'}; +var $author$project$PhotoGroove$Internal$initialModel = { activity: '', - chosenSize: $author$project$PhotoGroove$Medium, + chosenSize: $author$project$PhotoGroove$Internal$Medium, filterValues: {hue: 0, noise: 0, ripple: 0}, - status: $author$project$PhotoGroove$Loading + status: $author$project$PhotoGroove$Internal$Loading }; -var $author$project$PhotoGroove$init = function (flags) { +var $author$project$PhotoGroove$Internal$init = function (flags) { var activity = 'Initializing Pasta v' + $elm$core$String$fromFloat(flags); return _Utils_Tuple2( _Utils_update( - $author$project$PhotoGroove$initialModel, + $author$project$PhotoGroove$Internal$initialModel, {activity: activity}), - $author$project$PhotoGroove$initialCommand); + $author$project$PhotoGroove$Internal$initialCommand); }; -var $author$project$PhotoGroove$GotActivity = function (a) { +var $author$project$PhotoGroove$Internal$GotActivity = function (a) { return {$: 'GotActivity', a: a}; }; -var $author$project$PhotoGroove$activityChanges = _Platform_incomingPort('activityChanges', $elm$json$Json$Decode$string); -var $author$project$PhotoGroove$subscriptions = function (_v0) { - return $author$project$PhotoGroove$activityChanges($author$project$PhotoGroove$GotActivity); +var $author$project$PhotoGroove$Internal$activityChanges = _Platform_incomingPort('activityChanges', $elm$json$Json$Decode$string); +var $author$project$PhotoGroove$Internal$subscriptions = function (_v0) { + return $author$project$PhotoGroove$Internal$activityChanges($author$project$PhotoGroove$Internal$GotActivity); }; -var $author$project$PhotoGroove$Errored = function (a) { +var $author$project$PhotoGroove$Internal$Errored = function (a) { return {$: 'Errored', a: a}; }; -var $author$project$PhotoGroove$GotRandomPhoto = function (a) { +var $author$project$PhotoGroove$Internal$GotRandomPhoto = function (a) { return {$: 'GotRandomPhoto', a: a}; }; -var $author$project$PhotoGroove$Loaded = F2( +var $author$project$PhotoGroove$Internal$Loaded = F2( function (a, b) { return {$: 'Loaded', a: a, b: b}; }); -var $author$project$PhotoGroove$Hue = {$: 'Hue'}; -var $author$project$PhotoGroove$Noise = {$: 'Noise'}; -var $author$project$PhotoGroove$Ripple = {$: 'Ripple'}; -var $author$project$PhotoGroove$filterTypeToName = function (t) { +var $author$project$PhotoGroove$Internal$Hue = {$: 'Hue'}; +var $author$project$PhotoGroove$Internal$Noise = {$: 'Noise'}; +var $author$project$PhotoGroove$Internal$Ripple = {$: 'Ripple'}; +var $author$project$PhotoGroove$Internal$filterTypeToName = function (t) { switch (t.$) { case 'Hue': return 'Hue'; @@ -6376,7 +6376,7 @@ var $elm$json$Json$Encode$object = function (pairs) { pairs)); }; var $elm$json$Json$Encode$string = _Json_wrap; -var $author$project$PhotoGroove$setFilters = _Platform_outgoingPort( +var $author$project$PhotoGroove$Internal$setFilters = _Platform_outgoingPort( 'setFilters', function ($) { return $elm$json$Json$Encode$object( @@ -6402,14 +6402,14 @@ var $author$project$PhotoGroove$setFilters = _Platform_outgoingPort( $elm$json$Json$Encode$string($.url)) ])); }); -var $author$project$PhotoGroove$urlPrefix = 'http://elm-in-action.com/'; -var $author$project$PhotoGroove$applyFilters = function (model) { +var $author$project$PhotoGroove$Internal$urlPrefix = 'http://elm-in-action.com/'; +var $author$project$PhotoGroove$Internal$applyFilters = function (model) { var _v0 = model.status; switch (_v0.$) { case 'Loaded': var photos = _v0.a; var selectedUrl = _v0.b; - var url = $author$project$PhotoGroove$urlPrefix + ('large/' + selectedUrl); + var url = $author$project$PhotoGroove$Internal$urlPrefix + ('large/' + selectedUrl); var inPecent = function (v) { return v / 11; }; @@ -6417,20 +6417,20 @@ var $author$project$PhotoGroove$applyFilters = function (model) { [ { amount: inPecent(model.filterValues.hue), - name: $author$project$PhotoGroove$filterTypeToName($author$project$PhotoGroove$Hue) + name: $author$project$PhotoGroove$Internal$filterTypeToName($author$project$PhotoGroove$Internal$Hue) }, { amount: inPecent(model.filterValues.ripple), - name: $author$project$PhotoGroove$filterTypeToName($author$project$PhotoGroove$Ripple) + name: $author$project$PhotoGroove$Internal$filterTypeToName($author$project$PhotoGroove$Internal$Ripple) }, { amount: inPecent(model.filterValues.noise), - name: $author$project$PhotoGroove$filterTypeToName($author$project$PhotoGroove$Noise) + name: $author$project$PhotoGroove$Internal$filterTypeToName($author$project$PhotoGroove$Internal$Noise) } ]); return _Utils_Tuple2( model, - $author$project$PhotoGroove$setFilters( + $author$project$PhotoGroove$Internal$setFilters( {filters: filters, url: url})); case 'Loading': return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none); @@ -6545,7 +6545,7 @@ var $elm$random$Random$generate = F2( $elm$random$Random$Generate( A2($elm$random$Random$map, tagger, generator))); }); -var $author$project$PhotoGroove$httpErrorToString = function (err) { +var $author$project$PhotoGroove$Internal$httpErrorToString = function (err) { switch (err.$) { case 'BadUrl': var msg = err.a; @@ -6566,19 +6566,19 @@ var $elm$core$Tuple$pair = F2( function (a, b) { return _Utils_Tuple2(a, b); }); -var $author$project$PhotoGroove$selectUrl = F2( +var $author$project$PhotoGroove$Internal$selectUrl = F2( function (url, status) { switch (status.$) { case 'Loading': return status; case 'Loaded': var photos = status.a; - return A2($author$project$PhotoGroove$Loaded, photos, url); + return A2($author$project$PhotoGroove$Internal$Loaded, photos, url); default: return status; } }); -var $author$project$PhotoGroove$setFilterValue = F3( +var $author$project$PhotoGroove$Internal$setFilterValue = F3( function (filterType, val, values) { switch (filterType.$) { case 'Hue': @@ -6678,16 +6678,16 @@ var $elm$random$Random$uniform = F2( $elm$random$Random$addOne(value), A2($elm$core$List$map, $elm$random$Random$addOne, valueList)); }); -var $author$project$PhotoGroove$update = F2( +var $author$project$PhotoGroove$Internal$update = F2( function (msg, model) { switch (msg.$) { case 'ClickedThumbnail': var thumb = msg.a; - return $author$project$PhotoGroove$applyFilters( + return $author$project$PhotoGroove$Internal$applyFilters( _Utils_update( model, { - status: A2($author$project$PhotoGroove$selectUrl, thumb, model.status) + status: A2($author$project$PhotoGroove$Internal$selectUrl, thumb, model.status) })); case 'ClickedSurpriseMe': var _v1 = model.status; @@ -6702,7 +6702,7 @@ var $author$project$PhotoGroove$update = F2( model, A2( $elm$random$Random$generate, - $author$project$PhotoGroove$GotRandomPhoto, + $author$project$PhotoGroove$Internal$GotRandomPhoto, A2($elm$random$Random$uniform, photo, morePhotos))); } else { return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none); @@ -6722,37 +6722,37 @@ var $author$project$PhotoGroove$update = F2( case 'ChangedFilter': var f = msg.a; var val = msg.b; - return $author$project$PhotoGroove$applyFilters( + return $author$project$PhotoGroove$Internal$applyFilters( _Utils_update( model, { - filterValues: A3($author$project$PhotoGroove$setFilterValue, f, val, model.filterValues) + filterValues: A3($author$project$PhotoGroove$Internal$setFilterValue, f, val, model.filterValues) })); case 'GotRandomPhoto': var photo = msg.a; - return $author$project$PhotoGroove$applyFilters( + return $author$project$PhotoGroove$Internal$applyFilters( _Utils_update( model, { - status: A2($author$project$PhotoGroove$selectUrl, photo.url, model.status) + status: A2($author$project$PhotoGroove$Internal$selectUrl, photo.url, model.status) })); case 'GotPhotos': if (msg.a.$ === 'Ok') { if (msg.a.a.b) { var photos = msg.a.a; var firstPhoto = photos.a; - return $author$project$PhotoGroove$applyFilters( + return $author$project$PhotoGroove$Internal$applyFilters( _Utils_update( model, { - status: A2($author$project$PhotoGroove$Loaded, photos, firstPhoto.url) + status: A2($author$project$PhotoGroove$Internal$Loaded, photos, firstPhoto.url) })); } else { return _Utils_Tuple2( _Utils_update( model, { - status: $author$project$PhotoGroove$Errored('No photos!') + status: $author$project$PhotoGroove$Internal$Errored('No photos!') }), $elm$core$Platform$Cmd$none); } @@ -6762,8 +6762,8 @@ var $author$project$PhotoGroove$update = F2( _Utils_update( model, { - status: $author$project$PhotoGroove$Errored( - 'Failed to load photos: ' + $author$project$PhotoGroove$httpErrorToString(httpError)) + status: $author$project$PhotoGroove$Internal$Errored( + 'Failed to load photos: ' + $author$project$PhotoGroove$Internal$httpErrorToString(httpError)) }), $elm$core$Platform$Cmd$none); } @@ -6787,9 +6787,9 @@ var $elm$html$Html$Attributes$class = $elm$html$Html$Attributes$stringProperty(' var $elm$html$Html$div = _VirtualDom_node('div'); var $elm$virtual_dom$VirtualDom$text = _VirtualDom_text; var $elm$html$Html$text = $elm$virtual_dom$VirtualDom$text; -var $author$project$PhotoGroove$ClickedSurpriseMe = {$: 'ClickedSurpriseMe'}; -var $author$project$PhotoGroove$Large = {$: 'Large'}; -var $author$project$PhotoGroove$Small = {$: 'Small'}; +var $author$project$PhotoGroove$Internal$ClickedSurpriseMe = {$: 'ClickedSurpriseMe'}; +var $author$project$PhotoGroove$Internal$Large = {$: 'Large'}; +var $author$project$PhotoGroove$Internal$Small = {$: 'Small'}; var $elm$html$Html$button = _VirtualDom_node('button'); var $elm$html$Html$canvas = _VirtualDom_node('canvas'); var $elm$html$Html$h1 = _VirtualDom_node('h1'); @@ -6813,7 +6813,7 @@ var $elm$html$Html$Events$onClick = function (msg) { 'click', $elm$json$Json$Decode$succeed(msg)); }; -var $author$project$PhotoGroove$sizeToClass = function (size) { +var $author$project$PhotoGroove$Internal$sizeToClass = function (size) { switch (size.$) { case 'Small': return 'small'; @@ -6829,14 +6829,14 @@ var $elm$html$Html$Attributes$src = function (url) { 'src', _VirtualDom_noJavaScriptOrHtmlUri(url)); }; -var $author$project$PhotoGroove$ChangedFilter = F2( +var $author$project$PhotoGroove$Internal$ChangedFilter = F2( function (a, b) { return {$: 'ChangedFilter', a: a, b: b}; }); var $elm$json$Json$Encode$int = _Json_wrap; var $elm$html$Html$label = _VirtualDom_node('label'); var $elm$html$Html$Attributes$max = $elm$html$Html$Attributes$stringProperty('max'); -var $author$project$PhotoGroove$onSlide = function (toMsg) { +var $author$project$PhotoGroove$Internal$onSlide = function (toMsg) { return A2( $elm$html$Html$Events$on, 'slide', @@ -6862,8 +6862,8 @@ var $elm$virtual_dom$VirtualDom$node = function (tag) { _VirtualDom_noScript(tag)); }; var $elm$html$Html$node = $elm$virtual_dom$VirtualDom$node; -var $author$project$PhotoGroove$rangeSlider = $elm$html$Html$node('range-slider'); -var $author$project$PhotoGroove$viewFilter = F2( +var $author$project$PhotoGroove$Internal$rangeSlider = $elm$html$Html$node('range-slider'); +var $author$project$PhotoGroove$Internal$viewFilter = F2( function (filterType, magnitude) { return A2( $elm$html$Html$div, @@ -6879,10 +6879,10 @@ var $author$project$PhotoGroove$viewFilter = F2( _List_fromArray( [ $elm$html$Html$text( - $author$project$PhotoGroove$filterTypeToName(filterType)) + $author$project$PhotoGroove$Internal$filterTypeToName(filterType)) ])), A2( - $author$project$PhotoGroove$rangeSlider, + $author$project$PhotoGroove$Internal$rangeSlider, _List_fromArray( [ $elm$html$Html$Attributes$max('11'), @@ -6890,8 +6890,8 @@ var $author$project$PhotoGroove$viewFilter = F2( $elm$html$Html$Attributes$property, 'val', $elm$json$Json$Encode$int(magnitude)), - $author$project$PhotoGroove$onSlide( - $author$project$PhotoGroove$ChangedFilter(filterType)) + $author$project$PhotoGroove$Internal$onSlide( + $author$project$PhotoGroove$Internal$ChangedFilter(filterType)) ]), _List_Nil), A2( @@ -6904,12 +6904,12 @@ var $author$project$PhotoGroove$viewFilter = F2( ])) ])); }); -var $author$project$PhotoGroove$ClickedSize = function (a) { +var $author$project$PhotoGroove$Internal$ClickedSize = function (a) { return {$: 'ClickedSize', a: a}; }; var $elm$html$Html$input = _VirtualDom_node('input'); var $elm$html$Html$Attributes$name = $elm$html$Html$Attributes$stringProperty('name'); -var $author$project$PhotoGroove$sizeToString = function (size) { +var $author$project$PhotoGroove$Internal$sizeToString = function (size) { switch (size.$) { case 'Small': return 'small'; @@ -6920,7 +6920,7 @@ var $author$project$PhotoGroove$sizeToString = function (size) { } }; var $elm$html$Html$Attributes$type_ = $elm$html$Html$Attributes$stringProperty('type'); -var $author$project$PhotoGroove$viewSizeChooser = function (size) { +var $author$project$PhotoGroove$Internal$viewSizeChooser = function (size) { return A2( $elm$html$Html$label, _List_Nil, @@ -6933,14 +6933,14 @@ var $author$project$PhotoGroove$viewSizeChooser = function (size) { $elm$html$Html$Attributes$type_('radio'), $elm$html$Html$Attributes$name('size'), $elm$html$Html$Events$onClick( - $author$project$PhotoGroove$ClickedSize(size)) + $author$project$PhotoGroove$Internal$ClickedSize(size)) ]), _List_Nil), $elm$html$Html$text( - $author$project$PhotoGroove$sizeToString(size)) + $author$project$PhotoGroove$Internal$sizeToString(size)) ])); }; -var $author$project$PhotoGroove$ClickedThumbnail = function (a) { +var $author$project$PhotoGroove$Internal$ClickedThumbnail = function (a) { return {$: 'ClickedThumbnail', a: a}; }; var $elm$core$List$filter = F2( @@ -6969,14 +6969,14 @@ var $elm$html$Html$Attributes$classList = function (classes) { A2($elm$core$List$filter, $elm$core$Tuple$second, classes)))); }; var $elm$html$Html$Attributes$title = $elm$html$Html$Attributes$stringProperty('title'); -var $author$project$PhotoGroove$viewThumbnail = F2( +var $author$project$PhotoGroove$Internal$viewThumbnail = F2( function (selectedUrl, thumb) { return A2( $elm$html$Html$img, _List_fromArray( [ $elm$html$Html$Attributes$src( - _Utils_ap($author$project$PhotoGroove$urlPrefix, thumb.url)), + _Utils_ap($author$project$PhotoGroove$Internal$urlPrefix, thumb.url)), $elm$html$Html$Attributes$title( thumb.title + (' [' + ($elm$core$String$fromInt(thumb.size) + ' KB]'))), $elm$html$Html$Attributes$classList( @@ -6987,11 +6987,11 @@ var $author$project$PhotoGroove$viewThumbnail = F2( _Utils_eq(selectedUrl, thumb.url)) ])), $elm$html$Html$Events$onClick( - $author$project$PhotoGroove$ClickedThumbnail(thumb.url)) + $author$project$PhotoGroove$Internal$ClickedThumbnail(thumb.url)) ]), _List_Nil); }); -var $author$project$PhotoGroove$viewLoaded = F3( +var $author$project$PhotoGroove$Internal$viewLoaded = F3( function (model, photos, selected) { return _List_fromArray( [ @@ -7006,7 +7006,7 @@ var $author$project$PhotoGroove$viewLoaded = F3( $elm$html$Html$button, _List_fromArray( [ - $elm$html$Html$Events$onClick($author$project$PhotoGroove$ClickedSurpriseMe) + $elm$html$Html$Events$onClick($author$project$PhotoGroove$Internal$ClickedSurpriseMe) ]), _List_fromArray( [ @@ -7030,9 +7030,9 @@ var $author$project$PhotoGroove$viewLoaded = F3( ]), _List_fromArray( [ - A2($author$project$PhotoGroove$viewFilter, $author$project$PhotoGroove$Hue, model.filterValues.hue), - A2($author$project$PhotoGroove$viewFilter, $author$project$PhotoGroove$Ripple, model.filterValues.ripple), - A2($author$project$PhotoGroove$viewFilter, $author$project$PhotoGroove$Noise, model.filterValues.noise) + A2($author$project$PhotoGroove$Internal$viewFilter, $author$project$PhotoGroove$Internal$Hue, model.filterValues.hue), + A2($author$project$PhotoGroove$Internal$viewFilter, $author$project$PhotoGroove$Internal$Ripple, model.filterValues.ripple), + A2($author$project$PhotoGroove$Internal$viewFilter, $author$project$PhotoGroove$Internal$Noise, model.filterValues.noise) ])), A2( $elm$html$Html$h3, @@ -7049,27 +7049,27 @@ var $author$project$PhotoGroove$viewLoaded = F3( ]), A2( $elm$core$List$map, - $author$project$PhotoGroove$viewSizeChooser, + $author$project$PhotoGroove$Internal$viewSizeChooser, _List_fromArray( - [$author$project$PhotoGroove$Small, $author$project$PhotoGroove$Medium, $author$project$PhotoGroove$Large]))), + [$author$project$PhotoGroove$Internal$Small, $author$project$PhotoGroove$Internal$Medium, $author$project$PhotoGroove$Internal$Large]))), A2( $elm$html$Html$div, _List_fromArray( [ $elm$html$Html$Attributes$id('thumbnails'), $elm$html$Html$Attributes$class( - $author$project$PhotoGroove$sizeToClass(model.chosenSize)) + $author$project$PhotoGroove$Internal$sizeToClass(model.chosenSize)) ]), A2( $elm$core$List$map, - $author$project$PhotoGroove$viewThumbnail(selected), + $author$project$PhotoGroove$Internal$viewThumbnail(selected), photos)), A2( $elm$html$Html$img, _List_fromArray( [ $elm$html$Html$Attributes$class('large'), - $elm$html$Html$Attributes$src($author$project$PhotoGroove$urlPrefix + ('large/' + selected)) + $elm$html$Html$Attributes$src($author$project$PhotoGroove$Internal$urlPrefix + ('large/' + selected)) ]), _List_Nil), A2( @@ -7082,7 +7082,7 @@ var $author$project$PhotoGroove$viewLoaded = F3( _List_Nil) ]); }); -var $author$project$PhotoGroove$view = function (model) { +var $author$project$PhotoGroove$Internal$view = function (model) { return A2( $elm$html$Html$div, _List_fromArray( @@ -7097,7 +7097,7 @@ var $author$project$PhotoGroove$view = function (model) { case 'Loaded': var photos = _v0.a; var selected = _v0.b; - return A3($author$project$PhotoGroove$viewLoaded, model, photos, selected); + return A3($author$project$PhotoGroove$Internal$viewLoaded, model, photos, selected); default: var error = _v0.a; return _List_fromArray( @@ -7107,6 +7107,7 @@ var $author$project$PhotoGroove$view = function (model) { } }()); }; -var $author$project$PhotoGroove$main = $elm$browser$Browser$element( - {init: $author$project$PhotoGroove$init, subscriptions: $author$project$PhotoGroove$subscriptions, update: $author$project$PhotoGroove$update, view: $author$project$PhotoGroove$view}); +var $author$project$PhotoGroove$Internal$main = $elm$browser$Browser$element( + {init: $author$project$PhotoGroove$Internal$init, subscriptions: $author$project$PhotoGroove$Internal$subscriptions, update: $author$project$PhotoGroove$Internal$update, view: $author$project$PhotoGroove$Internal$view}); +var $author$project$PhotoGroove$main = $author$project$PhotoGroove$Internal$main; _Platform_export({'PhotoGroove':{'init':$author$project$PhotoGroove$main($elm$json$Json$Decode$float)(0)}});}(this)); \ No newline at end of file diff --git a/src/PhotoGroove.elm b/src/PhotoGroove.elm index 6b7ec49..2cf1a3c 100644 --- a/src/PhotoGroove.elm +++ b/src/PhotoGroove.elm @@ -1,370 +1,8 @@ -port module PhotoGroove exposing (main, photoDecoder) +module PhotoGroove exposing (main) -import Browser -import Html exposing (Attribute, Html, button, canvas, div, h1, h3, img, input, label, node, text) -import Html.Attributes as Attr exposing (..) -import Html.Events exposing (on, onClick) -import Http -import Json.Decode as D exposing (Decoder) -import Json.Decode.Pipeline as D -import Json.Encode -import Random +import PhotoGroove.Internal as Internal -type Status - = Loading - | Loaded (List Photo) String - | Errored String - - -type alias FilterValues = - { hue : Int - , ripple : Int - , noise : Int - } - - -type alias FilterOptions = - { url : String - , filters : List { name : String, amount : Float } - } - - -port setFilters : FilterOptions -> Cmd msg - - -port activityChanges : (String -> msg) -> Sub msg - - -type alias Model = - { status : Status - , chosenSize : ThumbnailSize - , filterValues : FilterValues - , activity : String - } - - -type alias Photo = - { url : String - , size : Int - , title : String - } - - -photoDecoder : Decoder Photo -photoDecoder = - D.succeed Photo - |> D.required "url" D.string - |> D.required "size" D.int - |> D.optional "title" D.string "(untitled)" - - -type ThumbnailSize - = Small - | Medium - | Large - - -initialModel : Model -initialModel = - { status = Loading - , chosenSize = Medium - , filterValues = { hue = 0, ripple = 0, noise = 0 } - , activity = "" - } - - -initialCommand : Cmd Message -initialCommand = - Http.get - { url = "list" - , expect = Http.expectJson GotPhotos (D.list photoDecoder) - } - - -view : Model -> Html Message -view model = - div [ class "content" ] <| - case model.status of - Loading -> - [] - - Loaded photos selected -> - viewLoaded model photos selected - - Errored error -> - [ text ("Error: " ++ error) ] - - -viewLoaded : Model -> List Photo -> String -> List (Html Message) -viewLoaded model photos selected = - [ h1 [] [ text "Photo Groove" ] - , button [ onClick ClickedSurpriseMe ] [ text "Surprise me!" ] - , div [ class "activity" ] [ text model.activity ] - , div [ class "filters" ] - [ viewFilter Hue model.filterValues.hue - , viewFilter Ripple model.filterValues.ripple - , viewFilter Noise model.filterValues.noise - ] - , h3 [] [ text "Thumbnail Size:" ] - , div [ id "choose-size" ] - (List.map viewSizeChooser [ Small, Medium, Large ]) - , div - [ id "thumbnails" - , class (sizeToClass model.chosenSize) - ] - (List.map (viewThumbnail selected) photos) - , img [ class "large", src (urlPrefix ++ "large/" ++ selected) ] [] - , canvas [ id "canvas-main", class "large" ] [] - ] - - -viewThumbnail : String -> Photo -> Html Message -viewThumbnail selectedUrl thumb = - img - [ src (urlPrefix ++ thumb.url) - , title (thumb.title ++ " [" ++ String.fromInt thumb.size ++ " KB]") - , classList [ ( "selected", selectedUrl == thumb.url ) ] - , onClick (ClickedThumbnail thumb.url) - ] - [] - - -viewSizeChooser : ThumbnailSize -> Html Message -viewSizeChooser size = - label [] - [ input - [ type_ "radio" - , name "size" - , onClick (ClickedSize size) - ] - [] - , text (sizeToString size) - ] - - -viewFilter : FilterType -> Int -> Html Message -viewFilter filterType magnitude = - div - [ class "filter-slider" - ] - [ label [] [ text <| filterTypeToName filterType ] - , rangeSlider - [ Attr.max "11" - , property "val" (Json.Encode.int magnitude) - , onSlide (ChangedFilter filterType) - ] - [] - , label [] [ text (String.fromInt magnitude) ] - ] - - -sizeToString : ThumbnailSize -> String -sizeToString size = - case size of - Small -> - "small" - - Medium -> - "medium" - - Large -> - "large" - - -sizeToClass : ThumbnailSize -> String -sizeToClass size = - case size of - Small -> - "small" - - Medium -> - "med" - - Large -> - "large" - - -type Message - = ClickedThumbnail String - | ClickedSurpriseMe - | ClickedSize ThumbnailSize - | ChangedFilter FilterType Int - | GotRandomPhoto Photo - | GotPhotos (Result Http.Error (List Photo)) - | GotActivity String - - -type FilterType - = Hue - | Ripple - | Noise - - -filterTypeToName : FilterType -> String -filterTypeToName t = - case t of - Hue -> - "Hue" - - Ripple -> - "Ripple" - - Noise -> - "Noise" - - -update : Message -> Model -> ( Model, Cmd Message ) -update msg model = - case msg of - ClickedThumbnail thumb -> - applyFilters { model | status = selectUrl thumb model.status } - - ClickedSurpriseMe -> - case model.status of - Loaded (photo :: morePhotos) _ -> - Random.uniform photo morePhotos - |> Random.generate GotRandomPhoto - |> Tuple.pair model - - Loaded [] _ -> - ( model, Cmd.none ) - - Loading -> - ( model, Cmd.none ) - - Errored _ -> - ( model, Cmd.none ) - - ClickedSize size -> - ( { model | chosenSize = size }, Cmd.none ) - - ChangedFilter f val -> - applyFilters { model | filterValues = setFilterValue f val model.filterValues } - - GotRandomPhoto photo -> - applyFilters { model | status = selectUrl photo.url model.status } - - GotPhotos (Ok ((firstPhoto :: _) as photos)) -> - applyFilters { model | status = Loaded photos firstPhoto.url } - - GotPhotos (Ok []) -> - ( { model | status = Errored "No photos!" }, Cmd.none ) - - GotPhotos (Err httpError) -> - ( { model | status = Errored <| ("Failed to load photos: " ++ httpErrorToString httpError) }, Cmd.none ) - - GotActivity activity -> - ( { model | activity = activity }, Cmd.none ) - - -subscriptions : Model -> Sub Message -subscriptions _ = - activityChanges GotActivity - - -init : Float -> ( Model, Cmd Message ) -init flags = - let - activity = - "Initializing Pasta v" ++ String.fromFloat flags - in - ( { initialModel | activity = activity }, initialCommand ) - - -setFilterValue : FilterType -> Int -> FilterValues -> FilterValues -setFilterValue filterType val values = - case filterType of - Hue -> - { values | hue = val } - - Ripple -> - { values | ripple = val } - - Noise -> - { values | noise = val } - - -applyFilters : Model -> ( Model, Cmd msg ) -applyFilters model = - case model.status of - Loaded photos selectedUrl -> - let - inPecent v = - toFloat v / 11 - - filters = - [ { name = filterTypeToName Hue, amount = inPecent model.filterValues.hue } - , { name = filterTypeToName Ripple, amount = inPecent model.filterValues.ripple } - , { name = filterTypeToName Noise, amount = inPecent model.filterValues.noise } - ] - - url = - urlPrefix ++ "large/" ++ selectedUrl - in - ( model, setFilters { url = url, filters = filters } ) - - Loading -> - ( model, Cmd.none ) - - Errored _ -> - ( model, Cmd.none ) - - -selectUrl : String -> Status -> Status -selectUrl url status = - case status of - Loading -> - status - - Loaded photos _ -> - Loaded photos url - - Errored _ -> - status - - -httpErrorToString : Http.Error -> String -httpErrorToString err = - case err of - Http.BadUrl msg -> - "bad URL: " ++ msg - - Http.Timeout -> - "timeout" - - Http.NetworkError -> - "network error" - - Http.BadStatus status -> - "bad status: " ++ String.fromInt status - - Http.BadBody msg -> - "bad body: " ++ msg - - -urlPrefix : String -urlPrefix = - "http://elm-in-action.com/" - - -main : Program Float Model Message +main : Program Float Internal.Model Internal.Message main = - Browser.element - { init = init - , subscriptions = subscriptions - , view = view - , update = update - } - - -rangeSlider : List (Html.Attribute msg) -> List (Html msg) -> Html msg -rangeSlider = - node "range-slider" - - -onSlide : (Int -> msg) -> Attribute msg -onSlide toMsg = - D.at [ "detail", "userSlidTo" ] D.int - |> D.map toMsg - |> on "slide" + Internal.main diff --git a/src/PhotoGroove/Internal.elm b/src/PhotoGroove/Internal.elm new file mode 100644 index 0000000..3680bd4 --- /dev/null +++ b/src/PhotoGroove/Internal.elm @@ -0,0 +1,370 @@ +port module PhotoGroove.Internal exposing (..) + +import Browser +import Html exposing (Attribute, Html, button, canvas, div, h1, h3, img, input, label, node, text) +import Html.Attributes as Attr exposing (..) +import Html.Events exposing (on, onClick) +import Http +import Json.Decode as D exposing (Decoder) +import Json.Decode.Pipeline as D +import Json.Encode +import Random + + +type Status + = Loading + | Loaded (List Photo) String + | Errored String + + +type alias FilterValues = + { hue : Int + , ripple : Int + , noise : Int + } + + +type alias FilterOptions = + { url : String + , filters : List { name : String, amount : Float } + } + + +port setFilters : FilterOptions -> Cmd msg + + +port activityChanges : (String -> msg) -> Sub msg + + +type alias Model = + { status : Status + , chosenSize : ThumbnailSize + , filterValues : FilterValues + , activity : String + } + + +type alias Photo = + { url : String + , size : Int + , title : String + } + + +photoDecoder : Decoder Photo +photoDecoder = + D.succeed Photo + |> D.required "url" D.string + |> D.required "size" D.int + |> D.optional "title" D.string "(untitled)" + + +type ThumbnailSize + = Small + | Medium + | Large + + +initialModel : Model +initialModel = + { status = Loading + , chosenSize = Medium + , filterValues = { hue = 0, ripple = 0, noise = 0 } + , activity = "" + } + + +initialCommand : Cmd Message +initialCommand = + Http.get + { url = "list" + , expect = Http.expectJson GotPhotos (D.list photoDecoder) + } + + +view : Model -> Html Message +view model = + div [ class "content" ] <| + case model.status of + Loading -> + [] + + Loaded photos selected -> + viewLoaded model photos selected + + Errored error -> + [ text ("Error: " ++ error) ] + + +viewLoaded : Model -> List Photo -> String -> List (Html Message) +viewLoaded model photos selected = + [ h1 [] [ text "Photo Groove" ] + , button [ onClick ClickedSurpriseMe ] [ text "Surprise me!" ] + , div [ class "activity" ] [ text model.activity ] + , div [ class "filters" ] + [ viewFilter Hue model.filterValues.hue + , viewFilter Ripple model.filterValues.ripple + , viewFilter Noise model.filterValues.noise + ] + , h3 [] [ text "Thumbnail Size:" ] + , div [ id "choose-size" ] + (List.map viewSizeChooser [ Small, Medium, Large ]) + , div + [ id "thumbnails" + , class (sizeToClass model.chosenSize) + ] + (List.map (viewThumbnail selected) photos) + , img [ class "large", src (urlPrefix ++ "large/" ++ selected) ] [] + , canvas [ id "canvas-main", class "large" ] [] + ] + + +viewThumbnail : String -> Photo -> Html Message +viewThumbnail selectedUrl thumb = + img + [ src (urlPrefix ++ thumb.url) + , title (thumb.title ++ " [" ++ String.fromInt thumb.size ++ " KB]") + , classList [ ( "selected", selectedUrl == thumb.url ) ] + , onClick (ClickedThumbnail thumb.url) + ] + [] + + +viewSizeChooser : ThumbnailSize -> Html Message +viewSizeChooser size = + label [] + [ input + [ type_ "radio" + , name "size" + , onClick (ClickedSize size) + ] + [] + , text (sizeToString size) + ] + + +viewFilter : FilterType -> Int -> Html Message +viewFilter filterType magnitude = + div + [ class "filter-slider" + ] + [ label [] [ text <| filterTypeToName filterType ] + , rangeSlider + [ Attr.max "11" + , property "val" (Json.Encode.int magnitude) + , onSlide (ChangedFilter filterType) + ] + [] + , label [] [ text (String.fromInt magnitude) ] + ] + + +sizeToString : ThumbnailSize -> String +sizeToString size = + case size of + Small -> + "small" + + Medium -> + "medium" + + Large -> + "large" + + +sizeToClass : ThumbnailSize -> String +sizeToClass size = + case size of + Small -> + "small" + + Medium -> + "med" + + Large -> + "large" + + +type Message + = ClickedThumbnail String + | ClickedSurpriseMe + | ClickedSize ThumbnailSize + | ChangedFilter FilterType Int + | GotRandomPhoto Photo + | GotPhotos (Result Http.Error (List Photo)) + | GotActivity String + + +type FilterType + = Hue + | Ripple + | Noise + + +filterTypeToName : FilterType -> String +filterTypeToName t = + case t of + Hue -> + "Hue" + + Ripple -> + "Ripple" + + Noise -> + "Noise" + + +update : Message -> Model -> ( Model, Cmd Message ) +update msg model = + case msg of + ClickedThumbnail thumb -> + applyFilters { model | status = selectUrl thumb model.status } + + ClickedSurpriseMe -> + case model.status of + Loaded (photo :: morePhotos) _ -> + Random.uniform photo morePhotos + |> Random.generate GotRandomPhoto + |> Tuple.pair model + + Loaded [] _ -> + ( model, Cmd.none ) + + Loading -> + ( model, Cmd.none ) + + Errored _ -> + ( model, Cmd.none ) + + ClickedSize size -> + ( { model | chosenSize = size }, Cmd.none ) + + ChangedFilter f val -> + applyFilters { model | filterValues = setFilterValue f val model.filterValues } + + GotRandomPhoto photo -> + applyFilters { model | status = selectUrl photo.url model.status } + + GotPhotos (Ok ((firstPhoto :: _) as photos)) -> + applyFilters { model | status = Loaded photos firstPhoto.url } + + GotPhotos (Ok []) -> + ( { model | status = Errored "No photos!" }, Cmd.none ) + + GotPhotos (Err httpError) -> + ( { model | status = Errored <| ("Failed to load photos: " ++ httpErrorToString httpError) }, Cmd.none ) + + GotActivity activity -> + ( { model | activity = activity }, Cmd.none ) + + +subscriptions : Model -> Sub Message +subscriptions _ = + activityChanges GotActivity + + +init : Float -> ( Model, Cmd Message ) +init flags = + let + activity = + "Initializing Pasta v" ++ String.fromFloat flags + in + ( { initialModel | activity = activity }, initialCommand ) + + +setFilterValue : FilterType -> Int -> FilterValues -> FilterValues +setFilterValue filterType val values = + case filterType of + Hue -> + { values | hue = val } + + Ripple -> + { values | ripple = val } + + Noise -> + { values | noise = val } + + +applyFilters : Model -> ( Model, Cmd msg ) +applyFilters model = + case model.status of + Loaded photos selectedUrl -> + let + inPecent v = + toFloat v / 11 + + filters = + [ { name = filterTypeToName Hue, amount = inPecent model.filterValues.hue } + , { name = filterTypeToName Ripple, amount = inPecent model.filterValues.ripple } + , { name = filterTypeToName Noise, amount = inPecent model.filterValues.noise } + ] + + url = + urlPrefix ++ "large/" ++ selectedUrl + in + ( model, setFilters { url = url, filters = filters } ) + + Loading -> + ( model, Cmd.none ) + + Errored _ -> + ( model, Cmd.none ) + + +selectUrl : String -> Status -> Status +selectUrl url status = + case status of + Loading -> + status + + Loaded photos _ -> + Loaded photos url + + Errored _ -> + status + + +httpErrorToString : Http.Error -> String +httpErrorToString err = + case err of + Http.BadUrl msg -> + "bad URL: " ++ msg + + Http.Timeout -> + "timeout" + + Http.NetworkError -> + "network error" + + Http.BadStatus status -> + "bad status: " ++ String.fromInt status + + Http.BadBody msg -> + "bad body: " ++ msg + + +urlPrefix : String +urlPrefix = + "http://elm-in-action.com/" + + +main : Program Float Model Message +main = + Browser.element + { init = init + , subscriptions = subscriptions + , view = view + , update = update + } + + +rangeSlider : List (Html.Attribute msg) -> List (Html msg) -> Html msg +rangeSlider = + node "range-slider" + + +onSlide : (Int -> msg) -> Attribute msg +onSlide toMsg = + D.at [ "detail", "userSlidTo" ] D.int + |> D.map toMsg + |> on "slide" diff --git a/tests/PhotoGrooveTest.elm b/tests/PhotoGrooveTest.elm index e93ae28..342e11a 100644 --- a/tests/PhotoGrooveTest.elm +++ b/tests/PhotoGrooveTest.elm @@ -4,7 +4,7 @@ import Expect exposing (Expectation) import Fuzz exposing (Fuzzer, int, list, string) import Json.Decode as J import Json.Encode as Encode exposing (Value) -import PhotoGroove as Testee +import PhotoGroove.Internal as Testee import Test exposing (..)