Merge branch 'stack_redesign' into 'master'

Stack redesign

See merge request alatiera/Hammond!4
This commit is contained in:
Jordan Petridis 2017-12-13 16:28:06 +00:00
commit da57a966d5
21 changed files with 494 additions and 595 deletions

View File

@ -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 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! # Issues, issues and more issues!
There are many ways you can contribute to Hammond, and all of them involve creating 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 ## Pull Request Process
1. Ensure your code compiles. Run `make` before creating the pull request. 1. Ensure your code compiles. Run `make` before creating the pull request.
2. If you're adding new API, it must be properly documented. 2. Ensure the test suit passes. Run `cargo test -- --test-threads=1`.
3. The commit message is formatted as follows: 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: <summary> component: <summary>
@ -78,7 +86,7 @@ Steps to reproduce:
<link to the bug ticket> <link to the bug ticket>
``` ```
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. do not have permission to do that, you may request the second reviewer to merge it for you.
## Code of Conduct ## Code of Conduct

78
Cargo.lock generated
View File

@ -91,7 +91,7 @@ dependencies = [
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.6.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hammond-data 0.1.0", "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)", "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)", "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)", "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]] [[package]]
name = "hyper" name = "hyper"
version = "0.11.7" version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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)", "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 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)", "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)", "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)", "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)", "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-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-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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"futures 0.1.17 (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)",
"native-tls 0.1.4 (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-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-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)", "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" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"openssl 0.9.22 (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.8 (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 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)", "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)", "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]] [[package]]
name = "openssl" name = "openssl"
version = "0.9.22" version = "0.9.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.22" version = "0.9.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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 = [ dependencies = [
"bytes 0.4.5 (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 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)", "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)", "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)", "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)", "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)", "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 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.7 (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)", "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-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)", "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)", "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]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.8" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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 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)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1281,18 +1281,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.23" version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.7" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]
@ -1302,7 +1302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "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_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)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1409,10 +1409,10 @@ dependencies = [
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "0.3.4" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1429,7 +1429,7 @@ dependencies = [
[[package]] [[package]]
name = "tokio-core" name = "tokio-core"
version = "0.1.10" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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-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-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 = [ dependencies = [
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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-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 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 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 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.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 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" "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 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 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 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 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 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" "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-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 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 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 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854"
"checksum openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5483bdc56756041ba6aa37c9cb59cc2219f012a2a1377d97ad35556ac6676ee7" "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 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 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" "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-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 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 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 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 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 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 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 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 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 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
"checksum serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ea28ea0cca944668919bec6af209864a8dfe769fd2b0b723f36b22e20c1bf69f" "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 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 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" "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 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 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 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 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-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-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" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"

View File

@ -8,8 +8,7 @@ This is a prototype of a podcast client written in Rust.
![podcast_widget](./assets/podcast_widget.png) ![podcast_widget](./assets/podcast_widget.png)
## Getting in Touch ## Getting in Touch
If you have any questions regarding the 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)
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: Sidenote:
@ -70,14 +69,6 @@ cd Hammond/
cargo build --all 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 ## Contributing
There alot of thins yet to be done. There alot of thins yet to be done.

View File

@ -81,7 +81,6 @@ pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result<NewEpisode> {
.unwrap()) .unwrap())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs::File; use std::fs::File;

View File

@ -6,7 +6,7 @@ workspace = "../"
[dependencies] [dependencies]
error-chain = "0.11.0" error-chain = "0.11.0"
hyper = "0.11.7" hyper = "0.11.9"
log = "0.3.8" log = "0.3.8"
mime_guess = "1.8.3" mime_guess = "1.8.3"
reqwest = "0.8.1" reqwest = "0.8.1"
@ -14,7 +14,7 @@ tempdir = "0.3.5"
[dependencies.diesel] [dependencies.diesel]
features = ["sqlite"] features = ["sqlite"]
version = "0.99" version = "0.99.0"
[dependencies.hammond-data] [dependencies.hammond-data]
path = "../hammond-data" path = "../hammond-data"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.1 --> <!-- Generated with glade 3.20.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.20"/> <requires lib="gtk+" version="3.20"/>
<object class="GtkBox" id="episode_box"> <object class="GtkBox" id="episode_box">
@ -11,26 +11,23 @@
<property name="margin_bottom">5</property> <property name="margin_bottom">5</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<object class="GtkButton" id="play_button"> <object class="GtkButton" id="delete_button">
<property name="name">delete_button</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="halign">end</property> <property name="halign">end</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-media-play</property> <property name="icon_name">edit-delete-symbolic</property>
<property name="use_fallback">True</property>
</object> </object>
</child> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="padding">5</property>
<property name="pack_type">end</property> <property name="pack_type">end</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
@ -49,8 +46,7 @@
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-save</property> <property name="icon_name">document-save-symbolic</property>
<property name="use_fallback">True</property>
</object> </object>
</child> </child>
</object> </object>
@ -63,23 +59,25 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="delete_button"> <object class="GtkButton" id="play_button">
<property name="name">delete_button</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="halign">end</property> <property name="halign">end</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-delete</property> <property name="icon_name">media-playback-start-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="padding">5</property>
<property name="pack_type">end</property> <property name="pack_type">end</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
@ -95,7 +93,7 @@
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-undo</property> <property name="icon_name">edit-undo-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
@ -118,7 +116,7 @@
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-apply</property> <property name="icon_name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </object>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.1 --> <!-- Generated with glade 3.20.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.20"/> <requires lib="gtk+" version="3.20"/>
<object class="GtkPopover" id="add-popover"> <object class="GtkPopover" id="add-popover">
@ -109,24 +109,141 @@
</object> </object>
</child> </child>
</object> </object>
<object class="GtkHeaderBar" id="headerbar1"> <object class="GtkBox" id="back_view">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="has_subtitle">False</property>
<property name="show_close_button">True</property>
<child> <child>
<object class="GtkMenuButton" id="add-toggle-button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child type="center">
<object class="GtkLabel" id="show_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Show Title</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
<object class="GtkHeaderBar" id="headerbar">
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<child type="title">
<object class="GtkStack" id="headerbar_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkBox" id="normal_view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="menu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ref_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">view-refresh-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="add_toggle_button">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Add a new feed</property> <property name="tooltip_text" translatable="yes">Add a new feed</property>
<property name="valign">center</property>
<child> <child>
<object class="GtkImage" id="add-button-image"> <object class="GtkImage" id="add-button-image1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-add</property> <property name="icon_name">list-add-symbolic</property>
<property name="use_fallback">True</property>
<property name="icon_size">1</property> <property name="icon_size">1</property>
</object> </object>
</child> </child>
@ -135,40 +252,23 @@
</style> </style>
</object> </object>
<packing> <packing>
<property name="position">1</property> <property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child type="center">
<object class="GtkStackSwitcher" id="switch"> <object class="GtkStackSwitcher" id="switch">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
<property name="icon_size">0</property>
</object> </object>
<packing> <packing>
<property name="position">2</property> <property name="expand">False</property>
</packing> <property name="fill">True</property>
</child> <property name="position">4</property>
<child>
<object class="GtkButton" id="refbutton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="use_underline">True</property>
<property name="always_show_image">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-refresh</property>
<property name="use_fallback">True</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">-1</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.1 --> <!-- Generated with glade 3.20.2 -->
<interface domain="gnome-music"> <interface domain="gnome-music">
<requires lib="gtk+" version="3.12"/> <requires lib="gtk+" version="3.12"/>
<object class="GtkBox" id="podcast_widget"> <object class="GtkBox" id="podcast_widget">
@ -35,8 +35,6 @@
<property name="margin_right">1</property> <property name="margin_right">1</property>
<property name="margin_start">1</property> <property name="margin_start">1</property>
<property name="margin_end">1</property> <property name="margin_end">1</property>
<property name="stock">gtk-missing-image</property>
<property name="use_fallback">True</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -95,7 +93,7 @@
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Unsubrscribe from this Podcast. <property name="tooltip_text" translatable="yes">Unsubrscribe from this Podcast.
Warn: This will delete downloaded content associated with this Podcast.</property> Warn: This will delete downloaded content associated with this Podcast.</property>
<property name="stock">gtk-delete</property> <property name="icon_name">edit-delete-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
@ -118,7 +116,7 @@ Warn: This will delete downloaded content associated with this Podcast.</propert
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-apply</property> <property name="icon_name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </object>

View File

@ -3,10 +3,10 @@
<gresource prefix="/org/gnome/hammond/"> <gresource prefix="/org/gnome/hammond/">
<file>banner.png</file> <file>banner.png</file>
<file preprocess="xml-stripblanks">gtk/episode_widget.ui</file> <file preprocess="xml-stripblanks">gtk/episode_widget.ui</file>
<file preprocess="xml-stripblanks">gtk/podcast_widget.ui</file> <file preprocess="xml-stripblanks">gtk/show_widget.ui</file>
<file preprocess="xml-stripblanks">gtk/empty_view.ui</file> <file preprocess="xml-stripblanks">gtk/empty_view.ui</file>
<file preprocess="xml-stripblanks">gtk/podcasts_view.ui</file> <file preprocess="xml-stripblanks">gtk/shows_view.ui</file>
<file preprocess="xml-stripblanks">gtk/podcasts_child.ui</file> <file preprocess="xml-stripblanks">gtk/shows_child.ui</file>
<file preprocess="xml-stripblanks">gtk/headerbar.ui</file> <file preprocess="xml-stripblanks">gtk/headerbar.ui</file>
</gresource> </gresource>
</gresources> </gresources>

View File

@ -4,412 +4,174 @@ use gtk::prelude::*;
use hammond_data::Podcast; use hammond_data::Podcast;
use hammond_data::dbqueries; use hammond_data::dbqueries;
use widgets::podcast::PodcastWidget; use views::shows::ShowsPopulated;
use views::podcasts::PopulatedView;
use views::empty::EmptyView; use views::empty::EmptyView;
#[derive(Debug)] use widgets::show::ShowWidget;
use headerbar::Header;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct Content { pub struct Content {
pub stack: gtk::Stack, pub stack: gtk::Stack,
pub widget: PodcastWidget, pub shows: Rc<ShowStack>,
pub podcasts: PopulatedView, episodes: Rc<EpisodeStack>,
pub empty: EmptyView,
} }
impl Content { impl Content {
pub fn new() -> Content { pub fn new(header: Rc<Header>) -> Rc<Content> {
let stack = gtk::Stack::new(); let stack = gtk::Stack::new();
let shows = ShowStack::new(header);
let episodes = EpisodeStack::new();
let widget = PodcastWidget::new(); stack.add_titled(&episodes.stack, "episodes", "Episodes");
let podcasts = PopulatedView::new(); stack.add_titled(&shows.stack, "shows", "Shows");
let empty = EmptyView::new();
stack.add_titled(&widget.container, "widget", "Episodes"); Rc::new(Content {
stack.add_titled(&podcasts.container, "podcasts", "Shows");
stack.add_named(&empty.container, "empty");
Content {
stack, stack,
widget, shows,
empty, episodes,
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<S> {
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<ContentState<PodcastsView>> for ContentState<Empty> {
fn into(self) -> ContentState<PodcastsView> {
self.content.stack.set_visible_child_name("podcasts");
ContentState {
content: self.content,
state: PodcastsView {},
}
}
}
impl UpdateView for ContentState<Empty> {
fn update(&mut self) {}
}
impl Into<ContentState<Empty>> for ContentState<PodcastsView> {
fn into(self) -> ContentState<Empty> {
self.content.stack.set_visible_child_name("empty");
ContentState {
content: self.content,
state: Empty {},
}
}
}
impl Into<ContentState<WidgetsView>> for ContentState<PodcastsView> {
fn into(self) -> ContentState<WidgetsView> {
self.content.stack.set_visible_child_name("widget");
ContentState {
content: self.content,
state: WidgetsView {},
}
}
}
impl UpdateView for ContentState<PodcastsView> {
fn update(&mut self) {
let pop = PopulatedView::new_initialized(&self.content.stack);
self.content.replace_podcasts(pop)
}
}
impl Into<ContentState<PodcastsView>> for ContentState<WidgetsView> {
fn into(self) -> ContentState<PodcastsView> {
self.content.stack.set_visible_child_name("podcasts");
ContentState {
content: self.content,
state: PodcastsView {},
}
}
}
impl Into<ContentState<Empty>> for ContentState<WidgetsView> {
fn into(self) -> ContentState<Empty> {
self.content.stack.set_visible_child_name("empty");
ContentState {
content: self.content,
state: Empty {},
}
}
}
impl UpdateView for ContentState<WidgetsView> {
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::<i32>().unwrap()).unwrap();
let pdw = PodcastWidget::new_initialized(&self.content.stack, &pd);
self.content.replace_widget(pdw);
}
}
impl ContentState<PodcastsView> {
#[allow(dead_code)]
pub fn new() -> Result<ContentState<PodcastsView>, ContentState<Empty>> {
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 {},
}) })
} }
#[allow(dead_code)] pub fn update(&self) {
self.shows.update();
self.episodes.update();
}
pub fn get_stack(&self) -> gtk::Stack { pub fn get_stack(&self) -> gtk::Stack {
self.content.stack.clone() self.stack.clone()
} }
} }
fn replace_widget(stack: &gtk::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: &gtk::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: &gtk::Stack) {
stack.set_visible_child_name("widget")
}
pub fn show_podcasts(stack: &gtk::Stack) {
stack.set_visible_child_name("podcasts")
}
pub fn show_empty(stack: &gtk::Stack) {
stack.set_visible_child_name("empty")
}
pub fn update_podcasts(stack: &gtk::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: &gtk::Stack, pd: &Podcast) {
let pdw = PodcastWidget::new_initialized(stack, pd);
replace_widget(stack, &pdw);
}
pub fn update_podcasts_preserve_vis(stack: &gtk::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: &gtk::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: &gtk::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<S, T> {
// shows: ShowsMachine<S>,
// episodes: EpisodesMachine<S>,
// stack: gtk::Stack,
// state: T,
// }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct ShowsMachine<S> { pub struct ShowStack {
populated: ShowsPopulated, pub stack: gtk::Stack,
empty: ShowsEmpty, header: Rc<Header>,
}
impl ShowStack {
fn new(header: Rc<Header>) -> Rc<ShowStack> {
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::<i32>().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, stack: gtk::Stack,
state: S,
} }
#[derive(Debug)] impl EpisodeStack {
struct EpisodesMachine<S> { fn new() -> Rc<EpisodeStack> {
populated: EpisodesPopulated, let _pop = RecentEpisodes {};
empty: EpisodesEmpty, let empty = EmptyView::new();
stack: gtk::Stack, let stack = gtk::Stack::new();
state: S,
}
// impl Into<StackStateMachine<Populated, Shows>> for StackStateMachine<Populated, Episodes> { // stack.add_named(&pop.container, "populated");
// fn into(self) -> StackStateMachine<Populated, Shows> { stack.add_named(&empty.container, "empty");
// self.stack.set_visible_child_name("shows"); // FIXME:
stack.set_visible_child_name("empty");
// StackStateMachine { Rc::new(EpisodeStack {
// shows: self.shows, // empty,
// episodes: self.episodes, // populated: pop,
// stack: self.stack, stack,
// state: Shows {}, })
// } }
// }
// }
// impl Into<StackStateMachine<Populated, Episodes>> for StackStateMachine<Populated, Shows> { fn update(&self) {
// fn into(self) -> StackStateMachine<Populated, Episodes> { // unimplemented!()
// self.stack.set_visible_child_name("episodes");
// StackStateMachine {
// shows: self.shows,
// episodes: self.episodes,
// stack: self.stack,
// state: Episodes {},
// }
// }
// }
impl Into<ShowsMachine<Populated>> for ShowsMachine<Empty> {
fn into(self) -> ShowsMachine<Populated> {
self.stack.set_visible_child_name("populated");
ShowsMachine {
populated: self.populated,
empty: self.empty,
stack: self.stack,
state: Populated {},
}
}
}
impl Into<ShowsMachine<Empty>> for ShowsMachine<Populated> {
fn into(self) -> ShowsMachine<Empty> {
self.stack.set_visible_child_name("empty");
ShowsMachine {
populated: self.populated,
empty: self.empty,
stack: self.stack,
state: Empty {},
}
}
}
impl Into<EpisodesMachine<Populated>> for EpisodesMachine<Empty> {
fn into(self) -> EpisodesMachine<Populated> {
self.stack.set_visible_child_name("populated");
EpisodesMachine {
populated: self.populated,
empty: self.empty,
stack: self.stack,
state: Populated {},
}
}
}
impl Into<EpisodesMachine<Empty>> for EpisodesMachine<Populated> {
fn into(self) -> EpisodesMachine<Empty> {
self.stack.set_visible_child_name("empty");
EpisodesMachine {
populated: self.populated,
empty: self.empty,
stack: self.stack,
state: Empty {},
}
}
}
// enum StackStateWrapper<S> {
// Shows(StackStateMachine<S, Shows>),
// Episodes(StackStateMachine<S, Episodes>),
// }
enum ShowStateWrapper {
Populated(EpisodesMachine<Populated>),
Empty(EpisodesMachine<Empty>),
}
enum EpisodeStateWrapper {
Populated(EpisodesMachine<Populated>),
Empty(EpisodesMachine<Empty>),
}
// impl <S>StackStateWrapper<S> {
// 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()),
}
} }
} }

View File

@ -4,8 +4,10 @@ use gtk::prelude::*;
use hammond_data::Source; use hammond_data::Source;
use hammond_data::utils::url_cleaner; use hammond_data::utils::url_cleaner;
use std::rc::Rc;
use utils; use utils;
// use content; use content::Content;
#[derive(Debug)] #[derive(Debug)]
pub struct Header { pub struct Header {
@ -13,47 +15,69 @@ pub struct Header {
refresh: gtk::Button, refresh: gtk::Button,
add_toggle: gtk::MenuButton, add_toggle: gtk::MenuButton,
switch: gtk::StackSwitcher, switch: gtk::StackSwitcher,
stack: gtk::Stack,
back_button: gtk::Button,
show_title: gtk::Label,
} }
impl Header { impl Header {
pub fn new() -> Header { pub fn new() -> Rc<Header> {
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui");
let header: gtk::HeaderBar = builder.get_object("headerbar1").unwrap(); let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap();
let refresh: gtk::Button = builder.get_object("refbutton").unwrap(); let refresh: gtk::Button = builder.get_object("ref_button").unwrap();
let add_toggle: gtk::MenuButton = builder.get_object("add-toggle-button").unwrap(); let add_toggle: gtk::MenuButton = builder.get_object("add_toggle_button").unwrap();
let switch: gtk::StackSwitcher = builder.get_object("switch").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.set_halign(gtk::Align::Center);
switch.show(); 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, container: header,
refresh, refresh,
add_toggle, add_toggle,
switch, switch,
} stack,
back_button,
show_title,
})
} }
pub fn new_initialized(stack: &gtk::Stack) -> Header { // pub fn new_initialized(content: Rc<Content>) -> Rc<Header> {
let header = Header::new(); // let header = Header::new();
header.init(stack); // header.init(content);
header // header
} // }
fn init(&self, stack: &gtk::Stack) { pub fn init(&self, content: Rc<Content>) {
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); 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 add_popover: gtk::Popover = builder.get_object("add-popover").unwrap();
let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); let new_url: gtk::Entry = builder.get_object("new-url").unwrap();
let add_button: gtk::Button = builder.get_object("add-button").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| { new_url.connect_changed(move |url| {
println!("{:?}", url.get_text()); println!("{:?}", url.get_text());
}); });
add_button.connect_clicked(clone!(stack, add_popover, new_url => move |_| { add_button.connect_clicked(clone!(content, add_popover, new_url => move |_| {
on_add_bttn_clicked(&stack, &new_url); on_add_bttn_clicked(content.clone(), &new_url);
// TODO: lock the button instead of hiding and add notification of feed added. // TODO: lock the button instead of hiding and add notification of feed added.
// TODO: map the spinner // TODO: map the spinner
@ -62,13 +86,32 @@ impl Header {
self.add_toggle.set_popover(&add_popover); self.add_toggle.set_popover(&add_popover);
// FIXME: There appears to be a memmory leak here. // FIXME: There appears to be a memmory leak here.
self.refresh.connect_clicked(clone!(stack => move |_| { self.refresh.connect_clicked(clone!(content => move |_| {
utils::refresh_feed(&stack, None, None); 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: &gtk::Stack, entry: &gtk::Entry) { fn on_add_bttn_clicked(content: Rc<Content>, entry: &gtk::Entry) {
let url = entry.get_text().unwrap_or_default(); let url = entry.get_text().unwrap_or_default();
let url = url_cleaner(&url); let url = url_cleaner(&url);
let source = Source::from_url(&url); let source = Source::from_url(&url);
@ -76,7 +119,7 @@ fn on_add_bttn_clicked(stack: &gtk::Stack, entry: &gtk::Entry) {
if let Ok(s) = source { if let Ok(s) = source {
info!("{:?} feed added", url); info!("{:?} feed added", url);
// update the db // update the db
utils::refresh_feed(stack, Some(vec![s]), None); utils::refresh_feed(content, Some(vec![s]), None);
} else { } else {
error!("Feed probably already exists."); error!("Feed probably already exists.");
error!("Error: {:?}", source.unwrap_err()); error!("Error: {:?}", source.unwrap_err());

View File

@ -1,3 +1,5 @@
#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
extern crate gdk; extern crate gdk;
extern crate gdk_pixbuf; extern crate gdk_pixbuf;
extern crate gio; extern crate gio;
@ -67,9 +69,14 @@ fn build_ui(app: &gtk::Application) {
// let ct = content::ContentState::new().unwrap(); // let ct = content::ContentState::new().unwrap();
// let stack = ct.get_stack(); // let stack = ct.get_stack();
let ct = content::Content::new_initialized(); // let ct = content::Content::new_initialized();
let stack = ct.stack;
window.add(&stack); // 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, _| { window.connect_delete_event(|w, _| {
w.destroy(); w.destroy();
@ -92,8 +99,8 @@ fn build_ui(app: &gtk::Application) {
app.add_action(&check); app.add_action(&check);
// queue a db update 1 minute after the startup. // queue a db update 1 minute after the startup.
gtk::idle_add(clone!(stack => move || { gtk::idle_add(clone!(ct => move || {
utils::refresh_feed(&stack, None, Some(60)); utils::refresh_feed(ct.clone(), None, Some(60));
glib::Continue(false) glib::Continue(false)
})); }));
@ -102,10 +109,6 @@ fn build_ui(app: &gtk::Application) {
glib::Continue(false) glib::Continue(false)
}); });
// Get the headerbar
let header = headerbar::Header::new_initialized(&stack);
window.set_titlebar(&header.container);
window.show_all(); window.show_all();
window.activate(); window.activate();
app.connect_activate(move |_| ()); app.connect_activate(move |_| ());

View File

@ -1,5 +1,4 @@
use glib; use glib;
use gtk;
use gdk_pixbuf::Pixbuf; use gdk_pixbuf::Pixbuf;
use hammond_data::feed; use hammond_data::feed;
@ -9,12 +8,12 @@ use hammond_downloader::downloader;
use std::{thread, time}; use std::{thread, time};
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};
use std::borrow::Cow;
use content; use content::Content;
use regex::Regex;
type Foo = RefCell<Option<(gtk::Stack, Receiver<bool>)>>; use std::rc::Rc;
type Foo = RefCell<Option<(Rc<Content>, Receiver<bool>)>>;
// Create a thread local storage that will store the arguments to be transfered. // Create a thread local storage that will store the arguments to be transfered.
thread_local!(static GLOBAL: Foo = RefCell::new(None)); 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. /// 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. /// `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. /// When It's done,it queues up a `podcast_view` refresh.
pub fn refresh_feed(stack: &gtk::Stack, source: Option<Vec<Source>>, delay: Option<u64>) { pub fn refresh_feed(content: Rc<Content>, source: Option<Vec<Source>>, delay: Option<u64>) {
// Create a async channel. // Create a async channel.
let (sender, receiver) = channel(); let (sender, receiver) = channel();
// Pass the desired arguments into the Local Thread Storage. // Pass the desired arguments into the Local Thread Storage.
GLOBAL.with(clone!(stack => move |global| { GLOBAL.with(clone!(content => move |global| {
*global.borrow_mut() = Some((stack, receiver)); *global.borrow_mut() = Some((content.clone(), receiver));
})); }));
thread::spawn(move || { thread::spawn(move || {
@ -57,9 +56,9 @@ pub fn refresh_feed(stack: &gtk::Stack, source: Option<Vec<Source>>, delay: Opti
fn refresh_podcasts_view() -> glib::Continue { fn refresh_podcasts_view() -> glib::Continue {
GLOBAL.with(|global| { 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() { 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> {
Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() 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<str> {
s.trim();
s.replace('&', "&amp;");
s.replace('<', "&lt;");
s.replace('>', "&gt;");
let re = Regex::new("(?P<url>https?://[^\\s&,)(\"]+(&\\w=[\\w._-]?)*(#[\\w._-]+)?)").unwrap();
re.replace_all(s, "<a href=\"$url\">$url</a>")
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hammond_data::Source; use hammond_data::Source;

View File

@ -0,0 +1 @@

View File

@ -1,2 +1,3 @@
pub mod podcasts; pub mod shows;
pub mod episodes;
pub mod empty; pub mod empty;

View File

@ -7,18 +7,20 @@ use hammond_data::dbqueries;
use hammond_data::Podcast; use hammond_data::Podcast;
use utils::get_pixbuf_from_path; use utils::get_pixbuf_from_path;
use content::ShowStack;
use headerbar::Header;
use content; use std::rc::Rc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PopulatedView { pub struct ShowsPopulated {
pub container: gtk::Box, pub container: gtk::Box,
pub flowbox: gtk::FlowBox, flowbox: gtk::FlowBox,
viewport: gtk::Viewport, viewport: gtk::Viewport,
} }
#[derive(Debug)] #[derive(Debug)]
struct PodcastChild { struct ShowsChild {
container: gtk::Box, container: gtk::Box,
title: gtk::Label, title: gtk::Label,
cover: gtk::Image, cover: gtk::Image,
@ -27,14 +29,14 @@ struct PodcastChild {
child: gtk::FlowBoxChild, child: gtk::FlowBoxChild,
} }
impl PopulatedView { impl ShowsPopulated {
pub fn new() -> PopulatedView { pub fn new() -> ShowsPopulated {
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); 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 container: gtk::Box = builder.get_object("fb_parent").unwrap();
let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap();
let viewport: gtk::Viewport = builder.get_object("viewport").unwrap(); let viewport: gtk::Viewport = builder.get_object("viewport").unwrap();
PopulatedView { ShowsPopulated {
container, container,
flowbox, flowbox,
viewport, viewport,
@ -42,23 +44,27 @@ impl PopulatedView {
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn new_initialized(stack: &gtk::Stack) -> PopulatedView { pub fn new_initialized(show: Rc<ShowStack>, header: Rc<Header>) -> ShowsPopulated {
let pop = PopulatedView::new(); let pop = ShowsPopulated::new();
pop.init(stack); pop.init(show, header);
pop pop
} }
pub fn init(&self, stack: &gtk::Stack) { pub fn init(&self, show: Rc<ShowStack>, header: Rc<Header>) {
use gtk::WidgetExt; use gtk::WidgetExt;
// TODO: handle unwraps. // TODO: handle unwraps.
// TODO: implement back button.
self.flowbox self.flowbox
.connect_child_activated(clone!(stack => move |_, child| { .connect_child_activated(clone!(show => move |_, child| {
// This is such an ugly hack... // This is such an ugly hack...
// let id = child.get_name().unwrap().parse::<i32>().unwrap();
let id = WidgetExt::get_name(child).unwrap().parse::<i32>().unwrap(); let id = WidgetExt::get_name(child).unwrap().parse::<i32>().unwrap();
let parent = dbqueries::get_podcast_from_id(id).unwrap(); let pd = dbqueries::get_podcast_from_id(id).unwrap();
on_flowbox_child_activate(&stack, &parent);
show.replace_widget(&pd);
header.set_show_title(pd.title());
header.switch_to_back();
show.switch_widget_animated();
})); }));
// Populate the flowbox with the Podcasts. // Populate the flowbox with the Podcasts.
self.populate_flowbox(); self.populate_flowbox();
@ -69,17 +75,21 @@ impl PopulatedView {
if let Ok(pds) = podcasts { if let Ok(pds) = podcasts {
pds.iter().for_each(|parent| { 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.add(&flowbox_child.child);
}); });
self.flowbox.show_all(); self.flowbox.show_all();
} }
} }
pub fn is_empty(&self) -> bool {
self.flowbox.get_children().is_empty()
}
} }
impl PodcastChild { impl ShowsChild {
fn new() -> PodcastChild { fn new() -> ShowsChild {
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_child.ui");
// Copy of gnome-music AlbumWidget // Copy of gnome-music AlbumWidget
let container: gtk::Box = builder.get_object("fb_child").unwrap(); let container: gtk::Box = builder.get_object("fb_child").unwrap();
@ -91,7 +101,7 @@ impl PodcastChild {
let child = gtk::FlowBoxChild::new(); let child = gtk::FlowBoxChild::new();
child.add(&container); child.add(&container);
PodcastChild { ShowsChild {
container, container,
title, title,
cover, cover,
@ -113,8 +123,8 @@ impl PodcastChild {
self.configure_banner(pd); self.configure_banner(pd);
} }
pub fn new_initialized(pd: &Podcast) -> PodcastChild { pub fn new_initialized(pd: &Podcast) -> ShowsChild {
let child = PodcastChild::new(); let child = ShowsChild::new();
child.init(pd); child.init(pd);
child child
@ -138,7 +148,3 @@ impl PodcastChild {
} }
} }
} }
fn on_flowbox_child_activate(stack: &gtk::Stack, parent: &Podcast) {
content::on_podcasts_child_activate(stack, parent)
}

View File

@ -13,8 +13,6 @@ use hammond_data::utils::*;
use hammond_data::errors::*; use hammond_data::errors::*;
use hammond_data::utils::replace_extra_spaces; use hammond_data::utils::replace_extra_spaces;
// use utils::html_to_markup;
use std::thread; use std::thread;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};

View File

@ -1,2 +1,2 @@
pub mod podcast; pub mod show;
pub mod episode; pub mod episode;

View File

@ -10,10 +10,13 @@ use hammond_downloader::downloader;
use widgets::episode::episodes_listbox; use widgets::episode::episodes_listbox;
use utils::get_pixbuf_from_path; use utils::get_pixbuf_from_path;
use content; use content::ShowStack;
use headerbar::Header;
#[derive(Debug)] use std::rc::Rc;
pub struct PodcastWidget {
#[derive(Debug, Clone)]
pub struct ShowWidget {
pub container: gtk::Box, pub container: gtk::Box,
cover: gtk::Image, cover: gtk::Image,
title: gtk::Label, title: gtk::Label,
@ -23,10 +26,10 @@ pub struct PodcastWidget {
played: gtk::Button, played: gtk::Button,
} }
impl PodcastWidget { impl ShowWidget {
pub fn new() -> PodcastWidget { pub fn new() -> ShowWidget {
// Adapted from gnome-music AlbumWidget // 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 container: gtk::Box = builder.get_object("podcast_widget").unwrap();
let cover: gtk::Image = builder.get_object("cover").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 unsub: gtk::Button = builder.get_object("unsub_button").unwrap();
let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap();
PodcastWidget { ShowWidget {
container, container,
cover, cover,
title, title,
@ -47,18 +50,19 @@ impl PodcastWidget {
} }
} }
pub fn new_initialized(stack: &gtk::Stack, pd: &Podcast) -> PodcastWidget { pub fn new_initialized(shows: Rc<ShowStack>, header: Rc<Header>, pd: &Podcast) -> ShowWidget {
let pdw = PodcastWidget::new(); let pdw = ShowWidget::new();
pdw.init(stack, pd); pdw.init(shows, header, pd);
pdw pdw
} }
pub fn init(&self, stack: &gtk::Stack, pd: &Podcast) { pub fn init(&self, shows: Rc<ShowStack>, header: Rc<Header>, pd: &Podcast) {
WidgetExt::set_name(&self.container, &pd.id().to_string()); WidgetExt::set_name(&self.container, &pd.id().to_string());
// TODO: should spawn a thread to avoid locking the UI probably. // TODO: should spawn a thread to avoid locking the UI probably.
self.unsub.connect_clicked(clone!(stack, pd => move |bttn| { self.unsub.connect_clicked(clone!(shows, pd => move |bttn| {
on_unsub_button_clicked(&stack, &pd, bttn); on_unsub_button_clicked(shows.clone(), &pd, bttn);
header.switch_to_normal();
})); }));
self.title.set_text(pd.title()); self.title.set_text(pd.title());
@ -77,8 +81,8 @@ impl PodcastWidget {
self.cover.set_from_pixbuf(&i); self.cover.set_from_pixbuf(&i);
} }
self.played.connect_clicked(clone!(stack, pd => move |_| { self.played.connect_clicked(clone!(shows, pd => move |_| {
on_played_button_clicked(&stack, &pd); on_played_button_clicked(shows.clone(), &pd);
})); }));
self.show_played_button(pd); self.show_played_button(pd);
@ -95,7 +99,7 @@ impl PodcastWidget {
} }
} }
fn on_unsub_button_clicked(stack: &gtk::Stack, pd: &Podcast, unsub_button: &gtk::Button) { fn on_unsub_button_clicked(shows: Rc<ShowStack>, pd: &Podcast, unsub_button: &gtk::Button) {
let res = dbqueries::remove_feed(pd); let res = dbqueries::remove_feed(pd);
if res.is_ok() { if res.is_ok() {
info!("{} was removed succesfully.", pd.title()); info!("{} was removed succesfully.", pd.title());
@ -111,12 +115,12 @@ fn on_unsub_button_clicked(stack: &gtk::Stack, pd: &Podcast, unsub_button: &gtk:
} }
}; };
} }
content::update_podcasts(stack); shows.switch_podcasts_animated();
content::show_podcasts(stack); shows.update_podcasts();
} }
fn on_played_button_clicked(stack: &gtk::Stack, pd: &Podcast) { fn on_played_button_clicked(shows: Rc<ShowStack>, pd: &Podcast) {
let _ = dbqueries::update_none_to_played_now(pd); let _ = dbqueries::update_none_to_played_now(pd);
content::update_widget_preserve_vis(stack, pd); shows.update_widget();
} }