diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1f3d07..2e46fdc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,12 @@ It is recommended to add a pre-commit hook to run cargo test and cargo fmt cargo test -- --test-threads=1 && cargo fmt --all -- --write-mode=diff ``` +## Running the test suite + +The test suite sets a temporary sqlite database in the /tmp folder. Due to that it's not possible to run them in parrallel. + +In order to run the test suite use the following: `cargo test -- --test-threads=1` + # Issues, issues and more issues! There are many ways you can contribute to Hammond, and all of them involve creating issues @@ -67,8 +73,10 @@ Steps to reproduce: ## Pull Request Process 1. Ensure your code compiles. Run `make` before creating the pull request. -2. If you're adding new API, it must be properly documented. -3. The commit message is formatted as follows: +2. Ensure the test suit passes. Run `cargo test -- --test-threads=1`. +3. Ensure your code is properly formated. Run `cargo fmt --all`. +4. If you're adding new API, it must be properly documented. +5. The commit message is formatted as follows: ``` component: @@ -78,7 +86,7 @@ Steps to reproduce: ``` -4. You may merge the pull request in once you have the sign-off of the maintainers, or if you +6. You may merge the pull request in once you have the sign-off of the maintainers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. ## Code of Conduct diff --git a/Cargo.lock b/Cargo.lock index 910f55f..95d51b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "base64" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -590,7 +590,7 @@ dependencies = [ "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -636,10 +636,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -650,7 +650,7 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -663,9 +663,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -897,8 +897,8 @@ name = "native-tls" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -963,19 +963,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.22" +version = "0.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.22" +version = "0.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1144,7 +1144,7 @@ dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1168,16 +1168,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1220,13 +1220,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "schannel" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1281,18 +1281,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_json" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1302,7 +1302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1335,7 +1335,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1409,10 +1409,10 @@ dependencies = [ [[package]] name = "thread_local" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1429,7 +1429,7 @@ dependencies = [ [[package]] name = "tokio-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1464,7 +1464,7 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1484,7 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1619,7 +1619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" "checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" @@ -1672,7 +1672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "905fcfbaaad1b44ec0b4bba9e4d527d728284c62bc2ba41fccedace2b096766f" "checksum html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba3a1fd1857a714d410c191364c5d7bf8a6487c0ab5575146d37dd7eb17ef523" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4959ca95f55df4265bff2ad63066147255e6fa733682cf6d1cb5eaff6e53324b" +"checksum hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e0594792d2109069d0caffd176f674d770a84adf024c5bb48e686b1ee5ac7659" "checksum hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c81fa95203e2a6087242c38691a0210f23e9f3f8f944350bd676522132e2985" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" @@ -1709,8 +1709,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "419ef26bb651d72b6c5a603bcc4e4856a362460e62352dfffa53de91d2e81181" -"checksum openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5483bdc56756041ba6aa37c9cb59cc2219f012a2a1377d97ad35556ac6676ee7" +"checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" +"checksum openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2200ffec628e3f14c39fc0131a301db214f1a7d584e36507ee8700b0c7fb7a46" "checksum pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e81c404ab81ea7ea2fc2431a0a7672507b80e4b8bf4b41eac3fc83cc665104e" "checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" @@ -1738,15 +1738,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7554288337c1110e34d7a2433518d889374c1de1a45f856b7bcddb03702131fc" +"checksum schannel 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4330c2e874379fbd28fa67ba43239dbe8c7fb00662ceb1078bd37474f08bf5ce" "checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" "checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" "checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" -"checksum serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c37d7f192f00041e8a613e936717923a71bc0c9051fc4425a49b104140f05" -"checksum serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ea28ea0cca944668919bec6af209864a8dfe769fd2b0b723f36b22e20c1bf69f" +"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1" +"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" @@ -1761,9 +1761,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c843a027f7c1df5f81e7734a0df3f67bf329411781ebf36393ce67beef6071e3" +"checksum tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c87c27560184212c9dc45cd8f38623f37918248aad5b58fb65303b5d07a98c6e" "checksum tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "514aae203178929dbf03318ad7c683126672d4d96eccb77b29603d33c9e25743" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" diff --git a/README.md b/README.md index 89a8a06..4d25ca6 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,7 @@ This is a prototype of a podcast client written in Rust. ![podcast_widget](./assets/podcast_widget.png) ## Getting in Touch -If you have any questions regarding the -use or development of Hammond, want to discuss design or simply hang out, please join us in [#hammond on irc.gnome.org.](irc://irc.gnome.org/#hammond) +If you have any questions regarding the use or development of Hammond, want to discuss design or simply hang out, please join us in [#hammond on irc.gnome.org.](irc://irc.gnome.org/#hammond) Sidenote: @@ -70,14 +69,6 @@ cd Hammond/ cargo build --all ``` -## Call for designers - -Currently there no design plans or mockups. They are highly needed in order to advance the Gtk Client. - -There is the will for a complete client re-write if a someone contributes the mockups. - -If you happen to be a designer and want to contribute please hope on [#hammond](irc://irc.gnome.org/#hammond) and get in touch with us. - ## Contributing There alot of thins yet to be done. diff --git a/hammond-data/src/parser.rs b/hammond-data/src/parser.rs index 1be8064..393ac54 100644 --- a/hammond-data/src/parser.rs +++ b/hammond-data/src/parser.rs @@ -81,7 +81,6 @@ pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result { .unwrap()) } - #[cfg(test)] mod tests { use std::fs::File; diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index f063adc..ed50616 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../" [dependencies] error-chain = "0.11.0" -hyper = "0.11.7" +hyper = "0.11.9" log = "0.3.8" mime_guess = "1.8.3" reqwest = "0.8.1" @@ -14,7 +14,7 @@ tempdir = "0.3.5" [dependencies.diesel] features = ["sqlite"] -version = "0.99" +version = "0.99.0" [dependencies.hammond-data] path = "../hammond-data" diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index fdfacf7..6b85d48 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -1,5 +1,5 @@ - + @@ -11,26 +11,23 @@ 5 5 - + + delete_button True True end center - 5 - 5 True False - gtk-media-play - True + edit-delete-symbolic False False - 5 end 0 @@ -49,8 +46,7 @@ True False - gtk-save - True + document-save-symbolic @@ -63,23 +59,25 @@ - - delete_button + True True end center + 5 + 5 True False - gtk-delete + media-playback-start-symbolic False False + 5 end 0 @@ -95,7 +93,7 @@ True False - gtk-undo + edit-undo-symbolic @@ -118,7 +116,7 @@ True False - gtk-apply + object-select-symbolic diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index fc17ce5..b06d65e 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -1,5 +1,5 @@ - + @@ -109,24 +109,141 @@ - + True False - False - True - + + True + True + True + + + True + False + go-previous-symbolic + + + + + False + False + 0 + + + + + True + False + Show Title + + + + + + True + True + 1 + + + + + True + False + vertical + + + False + True + end + 2 + + + + + False + True + + + True + False + True + + + + + + + + True + False + 5 + + + True + False + vertical + + + False + True + end + 0 + + + + + True + True + True + + + True + False + open-menu-symbolic + + + + + False + False + end + 1 + + + + + True + True + True + True + True + + + True + False + view-refresh-symbolic + + + + + False + False + end + 2 + + + + True True False Add a new feed - center - + True False - gtk-add - True + list-add-symbolic 1 @@ -135,40 +252,23 @@ - 1 + False + False + 3 - + True False center True + 0 - 2 - - - - - True - True - True - center - True - True - - - True - False - gtk-refresh - True - - - - - end - -1 + False + True + 4 diff --git a/hammond-gtk/resources/gtk/podcast_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui similarity index 96% rename from hammond-gtk/resources/gtk/podcast_widget.ui rename to hammond-gtk/resources/gtk/show_widget.ui index 0241f05..9fd63c6 100644 --- a/hammond-gtk/resources/gtk/podcast_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -1,5 +1,5 @@ - + @@ -35,8 +35,6 @@ 1 1 1 - gtk-missing-image - True False @@ -95,7 +93,7 @@ False Unsubrscribe from this Podcast. Warn: This will delete downloaded content associated with this Podcast. - gtk-delete + edit-delete-symbolic @@ -118,7 +116,7 @@ Warn: This will delete downloaded content associated with this Podcast. True False - gtk-apply + object-select-symbolic diff --git a/hammond-gtk/resources/gtk/podcasts_child.ui b/hammond-gtk/resources/gtk/shows_child.ui similarity index 100% rename from hammond-gtk/resources/gtk/podcasts_child.ui rename to hammond-gtk/resources/gtk/shows_child.ui diff --git a/hammond-gtk/resources/gtk/podcasts_view.ui b/hammond-gtk/resources/gtk/shows_view.ui similarity index 100% rename from hammond-gtk/resources/gtk/podcasts_view.ui rename to hammond-gtk/resources/gtk/shows_view.ui diff --git a/hammond-gtk/resources/resources.xml b/hammond-gtk/resources/resources.xml index df3f3cd..e8bdc73 100644 --- a/hammond-gtk/resources/resources.xml +++ b/hammond-gtk/resources/resources.xml @@ -3,10 +3,10 @@ banner.png gtk/episode_widget.ui - gtk/podcast_widget.ui + gtk/show_widget.ui gtk/empty_view.ui - gtk/podcasts_view.ui - gtk/podcasts_child.ui + gtk/shows_view.ui + gtk/shows_child.ui gtk/headerbar.ui diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index be7a491..c87f88f 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -4,412 +4,174 @@ use gtk::prelude::*; use hammond_data::Podcast; use hammond_data::dbqueries; -use widgets::podcast::PodcastWidget; -use views::podcasts::PopulatedView; +use views::shows::ShowsPopulated; use views::empty::EmptyView; -#[derive(Debug)] +use widgets::show::ShowWidget; +use headerbar::Header; + +use std::rc::Rc; + +#[derive(Debug, Clone)] pub struct Content { pub stack: gtk::Stack, - pub widget: PodcastWidget, - pub podcasts: PopulatedView, - pub empty: EmptyView, + pub shows: Rc, + episodes: Rc, } impl Content { - pub fn new() -> Content { + pub fn new(header: Rc
) -> Rc { let stack = gtk::Stack::new(); + let shows = ShowStack::new(header); + let episodes = EpisodeStack::new(); - let widget = PodcastWidget::new(); - let podcasts = PopulatedView::new(); - let empty = EmptyView::new(); + stack.add_titled(&episodes.stack, "episodes", "Episodes"); + stack.add_titled(&shows.stack, "shows", "Shows"); - stack.add_titled(&widget.container, "widget", "Episodes"); - stack.add_titled(&podcasts.container, "podcasts", "Shows"); - stack.add_named(&empty.container, "empty"); - - Content { + Rc::new(Content { stack, - widget, - empty, - podcasts, - } - } - - pub fn new_initialized() -> Content { - let ct = Content::new(); - ct.init(); - ct - } - - pub fn init(&self) { - self.podcasts.init(&self.stack); - if self.podcasts.flowbox.get_children().is_empty() { - self.stack.set_visible_child_name("empty"); - return; - } - - self.stack.set_visible_child_name("podcasts"); - } - - fn replace_widget(&mut self, pdw: PodcastWidget) { - let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("widget").unwrap(); - self.stack.remove(&old); - - self.widget = pdw; - self.stack - .add_titled(&self.widget.container, "widget", "Episodes"); - self.stack.set_visible_child_name(&vis); - old.destroy(); - } - - fn replace_podcasts(&mut self, pop: PopulatedView) { - let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("podcasts").unwrap(); - self.stack.remove(&old); - - self.podcasts = pop; - self.stack - .add_titled(&self.podcasts.container, "podcasts", "Shows"); - self.stack.set_visible_child_name(&vis); - old.destroy(); - } -} - -#[derive(Debug)] -// Experiementing with Wrapping gtk::Stack into a State machine. -// Gonna revist it when TryInto trais is stabilized. -pub struct ContentState { - content: Content, - state: S, -} - -pub trait UpdateView { - fn update(&mut self); -} - -pub struct Empty; - -#[derive(Debug)] -pub struct PodcastsView {} - -#[derive(Debug)] -pub struct WidgetsView {} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("podcasts"); - - ContentState { - content: self.content, - state: PodcastsView {}, - } - } -} - -impl UpdateView for ContentState { - fn update(&mut self) {} -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("empty"); - ContentState { - content: self.content, - state: Empty {}, - } - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("widget"); - - ContentState { - content: self.content, - state: WidgetsView {}, - } - } -} - -impl UpdateView for ContentState { - fn update(&mut self) { - let pop = PopulatedView::new_initialized(&self.content.stack); - self.content.replace_podcasts(pop) - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("podcasts"); - ContentState { - content: self.content, - state: PodcastsView {}, - } - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("empty"); - ContentState { - content: self.content, - state: Empty {}, - } - } -} - -impl UpdateView for ContentState { - fn update(&mut self) { - let old = self.content.stack.get_child_by_name("widget").unwrap(); - let id = WidgetExt::get_name(&old).unwrap(); - let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); - - let pdw = PodcastWidget::new_initialized(&self.content.stack, &pd); - self.content.replace_widget(pdw); - } -} - -impl ContentState { - #[allow(dead_code)] - pub fn new() -> Result, ContentState> { - let content = Content::new(); - - content.podcasts.init(&content.stack); - if content.podcasts.flowbox.get_children().is_empty() { - content.stack.set_visible_child_name("empty"); - return Err(ContentState { - content, - state: Empty {}, - }); - } - - content.stack.set_visible_child_name("podcasts"); - Ok(ContentState { - content, - state: PodcastsView {}, + shows, + episodes, }) } - #[allow(dead_code)] + pub fn update(&self) { + self.shows.update(); + self.episodes.update(); + } + pub fn get_stack(&self) -> gtk::Stack { - self.content.stack.clone() + self.stack.clone() } } -fn replace_widget(stack: >k::Stack, pdw: &PodcastWidget) { - let old = stack.get_child_by_name("widget").unwrap(); - stack.remove(&old); - stack.add_titled(&pdw.container, "widget", "Episode"); - old.destroy(); -} - -fn replace_podcasts(stack: >k::Stack, pop: &PopulatedView) { - let old = stack.get_child_by_name("podcasts").unwrap(); - stack.remove(&old); - stack.add_titled(&pop.container, "podcasts", "Shows"); - old.destroy(); -} - -#[allow(dead_code)] -pub fn show_widget(stack: >k::Stack) { - stack.set_visible_child_name("widget") -} - -pub fn show_podcasts(stack: >k::Stack) { - stack.set_visible_child_name("podcasts") -} - -pub fn show_empty(stack: >k::Stack) { - stack.set_visible_child_name("empty") -} - -pub fn update_podcasts(stack: >k::Stack) { - let pods = PopulatedView::new_initialized(stack); - - if pods.flowbox.get_children().is_empty() { - show_empty(stack) - } - - replace_podcasts(stack, &pods); -} - -pub fn update_widget(stack: >k::Stack, pd: &Podcast) { - let pdw = PodcastWidget::new_initialized(stack, pd); - replace_widget(stack, &pdw); -} - -pub fn update_podcasts_preserve_vis(stack: >k::Stack) { - let vis = stack.get_visible_child_name().unwrap(); - update_podcasts(stack); - if vis != "empty" { - stack.set_visible_child_name(&vis) - } -} - -pub fn update_widget_preserve_vis(stack: >k::Stack, pd: &Podcast) { - let vis = stack.get_visible_child_name().unwrap(); - update_widget(stack, pd); - stack.set_visible_child_name(&vis) -} - -pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { - update_widget(stack, pd); - stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); -} - -// FIXME: Rename and remove aliases -type ShowsPopulated = PopulatedView; -type ShowsEmpty = EmptyView; -type EpisodesPopulated = PodcastWidget; -type EpisodesEmpty = EmptyView; - -struct Populated; -// struct Empty; -// struct Shows; -// struct Episodes; - -// Thats probably too overengineered -// struct StackStateMachine { -// shows: ShowsMachine, -// episodes: EpisodesMachine, -// stack: gtk::Stack, -// state: T, -// } - #[derive(Debug, Clone)] -struct ShowsMachine { - populated: ShowsPopulated, - empty: ShowsEmpty, +pub struct ShowStack { + pub stack: gtk::Stack, + header: Rc
, +} + +impl ShowStack { + fn new(header: Rc
) -> Rc { + let stack = gtk::Stack::new(); + + let show = Rc::new(ShowStack { + stack, + header: header.clone(), + }); + + let pop = ShowsPopulated::new_initialized(show.clone(), header); + let widget = ShowWidget::new(); + let empty = EmptyView::new(); + + show.stack.add_named(&pop.container, "podcasts"); + show.stack.add_named(&widget.container, "widget"); + show.stack.add_named(&empty.container, "empty"); + + if pop.is_empty() { + show.stack.set_visible_child_name("empty") + } else { + show.stack.set_visible_child_name("podcasts") + } + + show + } + + // fn is_empty(&self) -> bool { + // self.podcasts.is_empty() + // } + + pub fn update(&self) { + self.update_podcasts(); + self.update_widget(); + } + + pub fn update_podcasts(&self) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("podcasts").unwrap(); + + let pop = ShowsPopulated::new(); + pop.init(Rc::new(self.clone()), self.header.clone()); + + self.stack.remove(&old); + self.stack.add_named(&pop.container, "podcasts"); + + if pop.is_empty() { + self.stack.set_visible_child_name("empty"); + } else if vis != "empty" { + self.stack.set_visible_child_name(&vis); + } else { + self.stack.set_visible_child_name("podcasts"); + } + + old.destroy(); + } + + pub fn replace_widget(&self, pd: &Podcast) { + let old = self.stack.get_child_by_name("widget").unwrap(); + let new = ShowWidget::new_initialized(Rc::new(self.clone()), self.header.clone(), pd); + + self.stack.remove(&old); + self.stack.add_named(&new.container, "widget"); + } + + pub fn update_widget(&self) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("widget").unwrap(); + + let id = WidgetExt::get_name(&old).unwrap(); + if id == "GtkBox" { + return; + } + + let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()); + if let Ok(pd) = pd { + self.replace_widget(&pd); + self.stack.set_visible_child_name(&vis); + old.destroy(); + } + } + + pub fn switch_podcasts_animated(&self) { + self.stack + .set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight); + } + + pub fn switch_widget_animated(&self) { + self.stack + .set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft) + } +} + +#[derive(Debug, Clone)] +struct RecentEpisodes; + +#[derive(Debug, Clone)] +struct EpisodeStack { + // populated: RecentEpisodes, + // empty: EmptyView, stack: gtk::Stack, - state: S, } -#[derive(Debug)] -struct EpisodesMachine { - populated: EpisodesPopulated, - empty: EpisodesEmpty, - stack: gtk::Stack, - state: S, -} +impl EpisodeStack { + fn new() -> Rc { + let _pop = RecentEpisodes {}; + let empty = EmptyView::new(); + let stack = gtk::Stack::new(); -// impl Into> for StackStateMachine { -// fn into(self) -> StackStateMachine { -// self.stack.set_visible_child_name("shows"); + // stack.add_named(&pop.container, "populated"); + stack.add_named(&empty.container, "empty"); + // FIXME: + stack.set_visible_child_name("empty"); -// StackStateMachine { -// shows: self.shows, -// episodes: self.episodes, -// stack: self.stack, -// state: Shows {}, -// } -// } -// } + Rc::new(EpisodeStack { + // empty, + // populated: pop, + stack, + }) + } -// impl Into> for StackStateMachine { -// fn into(self) -> StackStateMachine { -// self.stack.set_visible_child_name("episodes"); - -// StackStateMachine { -// shows: self.shows, -// episodes: self.episodes, -// stack: self.stack, -// state: Episodes {}, -// } -// } -// } - -impl Into> for ShowsMachine { - fn into(self) -> ShowsMachine { - self.stack.set_visible_child_name("populated"); - - ShowsMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Populated {}, - } - } -} - -impl Into> for ShowsMachine { - fn into(self) -> ShowsMachine { - self.stack.set_visible_child_name("empty"); - - ShowsMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Empty {}, - } - } -} - -impl Into> for EpisodesMachine { - fn into(self) -> EpisodesMachine { - self.stack.set_visible_child_name("populated"); - - EpisodesMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Populated {}, - } - } -} - -impl Into> for EpisodesMachine { - fn into(self) -> EpisodesMachine { - self.stack.set_visible_child_name("empty"); - - EpisodesMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Empty {}, - } - } -} - -// enum StackStateWrapper { -// Shows(StackStateMachine), -// Episodes(StackStateMachine), -// } - -enum ShowStateWrapper { - Populated(EpisodesMachine), - Empty(EpisodesMachine), -} - -enum EpisodeStateWrapper { - Populated(EpisodesMachine), - Empty(EpisodesMachine), -} - -// impl StackStateWrapper { -// fn switch(mut self) -> Self { -// match self { -// StackStateWrapper::Shows(val) => StackStateWrapper::Episodes(val.into()), -// StackStateWrapper::Episodes(val) => StackStateWrapper::Shows(val.into()) -// } -// } -// } - -impl ShowStateWrapper { - fn switch(self) -> Self { - match self { - ShowStateWrapper::Populated(val) => ShowStateWrapper::Empty(val.into()), - ShowStateWrapper::Empty(val) => ShowStateWrapper::Populated(val.into()), - } - } -} - -impl EpisodeStateWrapper { - fn switch(self) -> Self { - match self { - EpisodeStateWrapper::Populated(val) => EpisodeStateWrapper::Empty(val.into()), - EpisodeStateWrapper::Empty(val) => EpisodeStateWrapper::Populated(val.into()), - } + fn update(&self) { + // unimplemented!() } } diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 7bcd41e..0aa98a9 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -4,8 +4,10 @@ use gtk::prelude::*; use hammond_data::Source; use hammond_data::utils::url_cleaner; +use std::rc::Rc; + use utils; -// use content; +use content::Content; #[derive(Debug)] pub struct Header { @@ -13,47 +15,69 @@ pub struct Header { refresh: gtk::Button, add_toggle: gtk::MenuButton, switch: gtk::StackSwitcher, + stack: gtk::Stack, + back_button: gtk::Button, + show_title: gtk::Label, } impl Header { - pub fn new() -> Header { + pub fn new() -> Rc
{ let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); - let header: gtk::HeaderBar = builder.get_object("headerbar1").unwrap(); - let refresh: gtk::Button = builder.get_object("refbutton").unwrap(); - let add_toggle: gtk::MenuButton = builder.get_object("add-toggle-button").unwrap(); + let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap(); + let refresh: gtk::Button = builder.get_object("ref_button").unwrap(); + let add_toggle: gtk::MenuButton = builder.get_object("add_toggle_button").unwrap(); let switch: gtk::StackSwitcher = builder.get_object("switch").unwrap(); + let stack: gtk::Stack = builder.get_object("headerbar_stack").unwrap(); + let normal_view: gtk::Box = builder.get_object("normal_view").unwrap(); + let back_view: gtk::Box = builder.get_object("back_view").unwrap(); + let back_button: gtk::Button = builder.get_object("back_button").unwrap(); + let show_title: gtk::Label = builder.get_object("show_title").unwrap(); + + let stack = stack.clone(); + back_button.connect_clicked(clone!(stack => move |_| { + stack.set_visible_child_name("normal_view"); + })); + switch.set_halign(gtk::Align::Center); switch.show(); - Header { + stack.add_named(&normal_view, "normal_view"); + stack.add_named(&back_view, "back_view"); + stack.set_transition_type(gtk::StackTransitionType::Crossfade); + stack.set_visible_child_name("normal_view"); + + Rc::new(Header { container: header, refresh, add_toggle, switch, - } + stack, + back_button, + show_title, + }) } - pub fn new_initialized(stack: >k::Stack) -> Header { - let header = Header::new(); - header.init(stack); - header - } + // pub fn new_initialized(content: Rc) -> Rc
{ + // let header = Header::new(); + // header.init(content); + // header + // } - fn init(&self, stack: >k::Stack) { + pub fn init(&self, content: Rc) { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); let add_button: gtk::Button = builder.get_object("add-button").unwrap(); - self.switch.set_stack(stack); + self.switch.set_stack(&content.stack); new_url.connect_changed(move |url| { println!("{:?}", url.get_text()); }); - add_button.connect_clicked(clone!(stack, add_popover, new_url => move |_| { - on_add_bttn_clicked(&stack, &new_url); + add_button.connect_clicked(clone!(content, add_popover, new_url => move |_| { + on_add_bttn_clicked(content.clone(), &new_url); // TODO: lock the button instead of hiding and add notification of feed added. // TODO: map the spinner @@ -62,13 +86,32 @@ impl Header { self.add_toggle.set_popover(&add_popover); // FIXME: There appears to be a memmory leak here. - self.refresh.connect_clicked(clone!(stack => move |_| { - utils::refresh_feed(&stack, None, None); + self.refresh.connect_clicked(clone!(content => move |_| { + utils::refresh_feed(content.clone(), None, None); })); + + let stack = self.stack.clone(); + self.back_button + .connect_clicked(clone!(content => move |_| { + content.shows.stack.set_visible_child_full("podcasts", gtk::StackTransitionType::SlideLeft); + stack.set_visible_child_name("normal_view") + })); + } + + pub fn switch_to_normal(&self) { + self.stack.set_visible_child_name("normal_view") + } + + pub fn switch_to_back(&self) { + self.stack.set_visible_child_name("back_view") + } + + pub fn set_show_title(&self, title: &str) { + self.show_title.set_text(title) } } -fn on_add_bttn_clicked(stack: >k::Stack, entry: >k::Entry) { +fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) { let url = entry.get_text().unwrap_or_default(); let url = url_cleaner(&url); let source = Source::from_url(&url); @@ -76,7 +119,7 @@ fn on_add_bttn_clicked(stack: >k::Stack, entry: >k::Entry) { if let Ok(s) = source { info!("{:?} feed added", url); // update the db - utils::refresh_feed(stack, Some(vec![s]), None); + utils::refresh_feed(content, Some(vec![s]), None); } else { error!("Feed probably already exists."); error!("Error: {:?}", source.unwrap_err()); diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index f4fd89b..0c594b9 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))] + extern crate gdk; extern crate gdk_pixbuf; extern crate gio; @@ -67,9 +69,14 @@ fn build_ui(app: >k::Application) { // let ct = content::ContentState::new().unwrap(); // let stack = ct.get_stack(); - let ct = content::Content::new_initialized(); - let stack = ct.stack; - window.add(&stack); + // let ct = content::Content::new_initialized(); + + // Get the headerbar + let header = headerbar::Header::new(); + let ct = content::Content::new(header.clone()); + header.init(ct.clone()); + window.set_titlebar(&header.container); + window.add(&ct.get_stack()); window.connect_delete_event(|w, _| { w.destroy(); @@ -92,8 +99,8 @@ fn build_ui(app: >k::Application) { app.add_action(&check); // queue a db update 1 minute after the startup. - gtk::idle_add(clone!(stack => move || { - utils::refresh_feed(&stack, None, Some(60)); + gtk::idle_add(clone!(ct => move || { + utils::refresh_feed(ct.clone(), None, Some(60)); glib::Continue(false) })); @@ -102,10 +109,6 @@ fn build_ui(app: >k::Application) { glib::Continue(false) }); - // Get the headerbar - let header = headerbar::Header::new_initialized(&stack); - window.set_titlebar(&header.container); - window.show_all(); window.activate(); app.connect_activate(move |_| ()); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 5402b90..7327854 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -1,5 +1,4 @@ use glib; -use gtk; use gdk_pixbuf::Pixbuf; use hammond_data::feed; @@ -9,12 +8,12 @@ use hammond_downloader::downloader; use std::{thread, time}; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; -use std::borrow::Cow; -use content; -use regex::Regex; +use content::Content; -type Foo = RefCell)>>; +use std::rc::Rc; + +type Foo = RefCell, Receiver)>>; // Create a thread local storage that will store the arguments to be transfered. thread_local!(static GLOBAL: Foo = RefCell::new(None)); @@ -23,13 +22,13 @@ thread_local!(static GLOBAL: Foo = RefCell::new(None)); /// If `source` is None, Fetches all the `Source` entries in the database and updates them. /// `delay` represents the desired time in seconds for the thread to sleep before executing. /// When It's done,it queues up a `podcast_view` refresh. -pub fn refresh_feed(stack: >k::Stack, source: Option>, delay: Option) { +pub fn refresh_feed(content: Rc, source: Option>, delay: Option) { // Create a async channel. let (sender, receiver) = channel(); // Pass the desired arguments into the Local Thread Storage. - GLOBAL.with(clone!(stack => move |global| { - *global.borrow_mut() = Some((stack, receiver)); + GLOBAL.with(clone!(content => move |global| { + *global.borrow_mut() = Some((content.clone(), receiver)); })); thread::spawn(move || { @@ -57,9 +56,9 @@ pub fn refresh_feed(stack: >k::Stack, source: Option>, delay: Opti fn refresh_podcasts_view() -> glib::Continue { GLOBAL.with(|global| { - if let Some((ref stack, ref reciever)) = *global.borrow() { + if let Some((ref content, ref reciever)) = *global.borrow() { if reciever.try_recv().is_ok() { - content::update_podcasts_preserve_vis(stack); + content.update(); } } }); @@ -71,18 +70,6 @@ pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() } -#[allow(dead_code)] -// WIP: parse html to markup -pub fn html_to_markup(s: &mut str) -> Cow { - s.trim(); - s.replace('&', "&"); - s.replace('<', "<"); - s.replace('>', ">"); - - let re = Regex::new("(?Phttps?://[^\\s&,)(\"]+(&\\w=[\\w._-]?)*(#[\\w._-]+)?)").unwrap(); - re.replace_all(s, "$url") -} - #[cfg(test)] mod tests { use hammond_data::Source; diff --git a/hammond-gtk/src/views/episodes.rs b/hammond-gtk/src/views/episodes.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/hammond-gtk/src/views/episodes.rs @@ -0,0 +1 @@ + diff --git a/hammond-gtk/src/views/mod.rs b/hammond-gtk/src/views/mod.rs index 9c47e7d..a9ea1bf 100644 --- a/hammond-gtk/src/views/mod.rs +++ b/hammond-gtk/src/views/mod.rs @@ -1,2 +1,3 @@ -pub mod podcasts; +pub mod shows; +pub mod episodes; pub mod empty; diff --git a/hammond-gtk/src/views/podcasts.rs b/hammond-gtk/src/views/shows.rs similarity index 72% rename from hammond-gtk/src/views/podcasts.rs rename to hammond-gtk/src/views/shows.rs index 711be87..affbb15 100644 --- a/hammond-gtk/src/views/podcasts.rs +++ b/hammond-gtk/src/views/shows.rs @@ -7,18 +7,20 @@ use hammond_data::dbqueries; use hammond_data::Podcast; use utils::get_pixbuf_from_path; +use content::ShowStack; +use headerbar::Header; -use content; +use std::rc::Rc; #[derive(Debug, Clone)] -pub struct PopulatedView { +pub struct ShowsPopulated { pub container: gtk::Box, - pub flowbox: gtk::FlowBox, + flowbox: gtk::FlowBox, viewport: gtk::Viewport, } #[derive(Debug)] -struct PodcastChild { +struct ShowsChild { container: gtk::Box, title: gtk::Label, cover: gtk::Image, @@ -27,14 +29,14 @@ struct PodcastChild { child: gtk::FlowBoxChild, } -impl PopulatedView { - pub fn new() -> PopulatedView { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); +impl ShowsPopulated { + pub fn new() -> ShowsPopulated { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_view.ui"); let container: gtk::Box = builder.get_object("fb_parent").unwrap(); let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); let viewport: gtk::Viewport = builder.get_object("viewport").unwrap(); - PopulatedView { + ShowsPopulated { container, flowbox, viewport, @@ -42,23 +44,27 @@ impl PopulatedView { } #[allow(dead_code)] - pub fn new_initialized(stack: >k::Stack) -> PopulatedView { - let pop = PopulatedView::new(); - pop.init(stack); + pub fn new_initialized(show: Rc, header: Rc
) -> ShowsPopulated { + let pop = ShowsPopulated::new(); + pop.init(show, header); pop } - pub fn init(&self, stack: >k::Stack) { + pub fn init(&self, show: Rc, header: Rc
) { use gtk::WidgetExt; // TODO: handle unwraps. + // TODO: implement back button. self.flowbox - .connect_child_activated(clone!(stack => move |_, child| { + .connect_child_activated(clone!(show => move |_, child| { // This is such an ugly hack... - // let id = child.get_name().unwrap().parse::().unwrap(); let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); - let parent = dbqueries::get_podcast_from_id(id).unwrap(); - on_flowbox_child_activate(&stack, &parent); + let pd = dbqueries::get_podcast_from_id(id).unwrap(); + + show.replace_widget(&pd); + header.set_show_title(pd.title()); + header.switch_to_back(); + show.switch_widget_animated(); })); // Populate the flowbox with the Podcasts. self.populate_flowbox(); @@ -69,17 +75,21 @@ impl PopulatedView { if let Ok(pds) = podcasts { pds.iter().for_each(|parent| { - let flowbox_child = PodcastChild::new_initialized(parent); + let flowbox_child = ShowsChild::new_initialized(parent); self.flowbox.add(&flowbox_child.child); }); self.flowbox.show_all(); } } + + pub fn is_empty(&self) -> bool { + self.flowbox.get_children().is_empty() + } } -impl PodcastChild { - fn new() -> PodcastChild { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); +impl ShowsChild { + fn new() -> ShowsChild { + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_child.ui"); // Copy of gnome-music AlbumWidget let container: gtk::Box = builder.get_object("fb_child").unwrap(); @@ -91,7 +101,7 @@ impl PodcastChild { let child = gtk::FlowBoxChild::new(); child.add(&container); - PodcastChild { + ShowsChild { container, title, cover, @@ -113,8 +123,8 @@ impl PodcastChild { self.configure_banner(pd); } - pub fn new_initialized(pd: &Podcast) -> PodcastChild { - let child = PodcastChild::new(); + pub fn new_initialized(pd: &Podcast) -> ShowsChild { + let child = ShowsChild::new(); child.init(pd); child @@ -138,7 +148,3 @@ impl PodcastChild { } } } - -fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { - content::on_podcasts_child_activate(stack, parent) -} diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 7166d0c..e69efd1 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -13,8 +13,6 @@ use hammond_data::utils::*; use hammond_data::errors::*; use hammond_data::utils::replace_extra_spaces; -// use utils::html_to_markup; - use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; diff --git a/hammond-gtk/src/widgets/mod.rs b/hammond-gtk/src/widgets/mod.rs index 5752aa3..d33f990 100644 --- a/hammond-gtk/src/widgets/mod.rs +++ b/hammond-gtk/src/widgets/mod.rs @@ -1,2 +1,2 @@ -pub mod podcast; +pub mod show; pub mod episode; diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/show.rs similarity index 73% rename from hammond-gtk/src/widgets/podcast.rs rename to hammond-gtk/src/widgets/show.rs index 206ffd9..99da2b8 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -10,10 +10,13 @@ use hammond_downloader::downloader; use widgets::episode::episodes_listbox; use utils::get_pixbuf_from_path; -use content; +use content::ShowStack; +use headerbar::Header; -#[derive(Debug)] -pub struct PodcastWidget { +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub struct ShowWidget { pub container: gtk::Box, cover: gtk::Image, title: gtk::Label, @@ -23,10 +26,10 @@ pub struct PodcastWidget { played: gtk::Button, } -impl PodcastWidget { - pub fn new() -> PodcastWidget { +impl ShowWidget { + pub fn new() -> ShowWidget { // Adapted from gnome-music AlbumWidget - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcast_widget.ui"); + let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); let container: gtk::Box = builder.get_object("podcast_widget").unwrap(); let cover: gtk::Image = builder.get_object("cover").unwrap(); @@ -36,7 +39,7 @@ impl PodcastWidget { let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); - PodcastWidget { + ShowWidget { container, cover, title, @@ -47,18 +50,19 @@ impl PodcastWidget { } } - pub fn new_initialized(stack: >k::Stack, pd: &Podcast) -> PodcastWidget { - let pdw = PodcastWidget::new(); - pdw.init(stack, pd); + pub fn new_initialized(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { + let pdw = ShowWidget::new(); + pdw.init(shows, header, pd); pdw } - pub fn init(&self, stack: >k::Stack, pd: &Podcast) { + pub fn init(&self, shows: Rc, header: Rc
, pd: &Podcast) { WidgetExt::set_name(&self.container, &pd.id().to_string()); // TODO: should spawn a thread to avoid locking the UI probably. - self.unsub.connect_clicked(clone!(stack, pd => move |bttn| { - on_unsub_button_clicked(&stack, &pd, bttn); + self.unsub.connect_clicked(clone!(shows, pd => move |bttn| { + on_unsub_button_clicked(shows.clone(), &pd, bttn); + header.switch_to_normal(); })); self.title.set_text(pd.title()); @@ -77,8 +81,8 @@ impl PodcastWidget { self.cover.set_from_pixbuf(&i); } - self.played.connect_clicked(clone!(stack, pd => move |_| { - on_played_button_clicked(&stack, &pd); + self.played.connect_clicked(clone!(shows, pd => move |_| { + on_played_button_clicked(shows.clone(), &pd); })); self.show_played_button(pd); @@ -95,7 +99,7 @@ impl PodcastWidget { } } -fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k::Button) { +fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: >k::Button) { let res = dbqueries::remove_feed(pd); if res.is_ok() { info!("{} was removed succesfully.", pd.title()); @@ -111,12 +115,12 @@ fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k: } }; } - content::update_podcasts(stack); - content::show_podcasts(stack); + shows.switch_podcasts_animated(); + shows.update_podcasts(); } -fn on_played_button_clicked(stack: >k::Stack, pd: &Podcast) { +fn on_played_button_clicked(shows: Rc, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); - content::update_widget_preserve_vis(stack, pd); + shows.update_widget(); }