mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c5d3699c0 | ||
|
|
a94f95874b | ||
|
|
4a3a01729b | ||
|
|
aadc285d7f | ||
|
|
2df0b9ba3d | ||
|
|
868155c532 | ||
|
|
3f981c09d5 | ||
|
|
b79fec13f4 | ||
|
|
6588291997 | ||
|
|
be96602c76 | ||
|
|
b59f9a6c17 | ||
|
|
9afe2ab69e | ||
|
|
2edc892dc2 | ||
|
|
45eb6915c2 | ||
|
|
706c912b13 | ||
|
|
e523eb5517 | ||
|
|
0bef2ffddc | ||
|
|
279594c425 | ||
|
|
8c1df334d8 | ||
|
|
e2bf2a09a4 | ||
|
|
1d48ce144f | ||
|
|
082b52c58b | ||
|
|
c1966442a7 | ||
|
|
4d88214c1d | ||
|
|
de99e09f5e | ||
|
|
e717d75324 | ||
|
|
a545863473 | ||
|
|
85ffe94266 | ||
|
|
7adbf951bc | ||
|
|
78dc217642 | ||
|
|
64137473b3 | ||
|
|
c08effb445 | ||
|
|
65410defe2 | ||
|
|
ed71c8148b | ||
|
|
13a79af27e | ||
|
|
f6564c3c71 | ||
|
|
8e42f81ea3 | ||
|
|
ada5b48ba5 | ||
|
|
a6a59877a8 | ||
|
|
6aa455490b | ||
|
|
f81738bc8b | ||
|
|
a57effd073 | ||
|
|
c180f6e58e | ||
|
|
1290b8f32f | ||
|
|
9e765a3575 | ||
|
|
65a0c33007 | ||
|
|
7add81e8b6 | ||
|
|
1a69822d3f | ||
|
|
c370d9febd | ||
|
|
24002827ed | ||
|
|
a835ac4e07 | ||
|
|
a68e466040 | ||
|
|
bfbe437ab1 | ||
|
|
574ffe09c2 | ||
|
|
529a68f291 | ||
|
|
266fbfed1f | ||
|
|
fb8053ef60 | ||
|
|
34e66f9ae0 | ||
|
|
10fc88364f | ||
|
|
2e5a15eec7 | ||
|
|
42aa4deb0d | ||
|
|
82f41940c7 | ||
|
|
6c3aeab041 | ||
|
|
609c83ed34 | ||
|
|
5a0ff019e9 | ||
|
|
ad89830c51 | ||
|
|
da2c3853b0 | ||
|
|
94735bc453 | ||
|
|
42e7fa4356 | ||
|
|
9ea4da9d21 | ||
|
|
a6cbd89ff1 | ||
|
|
aa9365b2fd | ||
|
|
bffb4842b1 | ||
|
|
fcec36ec68 | ||
|
|
483d846233 | ||
|
|
11841ca3d7 | ||
|
|
01139f76e7 | ||
|
|
fdbdc513f1 | ||
|
|
880fe10bfd | ||
|
|
5b62474c27 | ||
|
|
cdf642d9f3 | ||
|
|
e3955239f3 | ||
|
|
5842239e26 | ||
|
|
86512a44d2 | ||
|
|
d1b579ac4c | ||
|
|
5040767296 | ||
|
|
2b6a892a50 | ||
|
|
5aa837e5ef | ||
|
|
f1c978d167 | ||
|
|
34ec942e7b | ||
|
|
630fa2877f | ||
|
|
ad0b611bcb | ||
|
|
68d814d996 | ||
|
|
08767c5589 | ||
|
|
1f53ffbda9 | ||
|
|
8dc0cf7051 | ||
|
|
ae53e5dc35 | ||
|
|
213ac7c278 | ||
|
|
ab02abbf4e | ||
|
|
a1d5cda998 | ||
|
|
a6b5498f55 | ||
|
|
a52788e72f | ||
|
|
4b63882c70 | ||
|
|
549a915b24 | ||
|
|
19d0c1b108 | ||
|
|
269d48d250 | ||
|
|
a088a7a0a2 | ||
|
|
b9ade5f243 | ||
|
|
e100484810 | ||
|
|
b1aa623b29 | ||
|
|
e36e064374 | ||
|
|
d59f9c7506 | ||
|
|
49f713d82c | ||
|
|
1aefb04eb5 | ||
|
|
dca3f2c773 | ||
|
|
fc0b995bac | ||
|
|
5a8108384f | ||
|
|
7191e02f99 | ||
|
|
0ca372b73f | ||
|
|
c4ecdb7a78 | ||
|
|
1719f8cc2e | ||
|
|
3580854479 | ||
|
|
28e926eb86 | ||
|
|
5a449d4133 | ||
|
|
f8d5542af5 | ||
|
|
9bb73f28b7 | ||
|
|
7e2b3bc712 | ||
|
|
f8e7bcdf39 | ||
|
|
a807cfd8f6 | ||
|
|
f6fcd21404 | ||
|
|
208c587ddf | ||
|
|
5d2a870319 | ||
|
|
942c7ce65f | ||
|
|
4c13cc98a1 | ||
|
|
622d4e3632 | ||
|
|
542cfcfd50 | ||
|
|
12fabc8f23 | ||
|
|
f7f317cf8b | ||
|
|
6572dd4eab | ||
|
|
466c029be6 | ||
|
|
3da5b43e0a | ||
|
|
38ad7c46a8 | ||
|
|
05b5af41ba | ||
|
|
049d84e261 | ||
|
|
bf51fddc4d | ||
|
|
007e6d8f9d | ||
|
|
68d35f0104 | ||
|
|
39959c7a10 | ||
|
|
c592b8d3ce | ||
|
|
acb851d4f6 | ||
|
|
a08cfc7fb8 | ||
|
|
1ea4da3baf | ||
|
|
a817423e7e | ||
|
|
46f0b9608b | ||
|
|
ac479f80ee | ||
|
|
f13662747c | ||
|
|
f8d1909737 | ||
|
|
7628582fd7 | ||
|
|
b1ff0921c3 | ||
|
|
0755b20cf0 | ||
|
|
7dca788c01 | ||
|
|
853c36d19b | ||
|
|
ee5b5a894b | ||
|
|
8f411d4c5e | ||
|
|
0303c53a72 | ||
|
|
c7282a3290 | ||
|
|
2abe0c4582 | ||
|
|
c2081e93b8 | ||
|
|
c9d7f5df09 | ||
|
|
c910e37d00 | ||
|
|
c0debc038a | ||
|
|
c3e2c75b60 | ||
|
|
f4c7814061 | ||
|
|
3a163fb939 | ||
|
|
e41ac8f367 | ||
|
|
04da45e278 | ||
|
|
b1562b4796 | ||
|
|
b5adc73a6d | ||
|
|
4fc76ecbd9 | ||
|
|
fb296786a5 | ||
|
|
e41cee61cf | ||
|
|
c9d0c414d0 | ||
|
|
b156f666ef | ||
|
|
baf61ca9bc | ||
|
|
1685691d2f | ||
|
|
e531eb85e3 | ||
|
|
ccad82aa6d | ||
|
|
836fac2bb7 | ||
|
|
216f96caef | ||
|
|
c5c8df0b5e | ||
|
|
b9a25cc941 | ||
|
|
bbb89b7e6b | ||
|
|
bf1ac5fc2c | ||
|
|
73557d30f2 | ||
|
|
0de157f3e2 | ||
|
|
9529f74c48 | ||
|
|
378c3ac4bf | ||
|
|
e4a4b7eeb1 | ||
|
|
7653de2cee | ||
|
|
53697ef0c4 | ||
|
|
8c9d2031c2 | ||
|
|
a006d0558a | ||
|
|
278c06170b | ||
|
|
a2f37e6b9f | ||
|
|
93fa038b36 | ||
|
|
9f10f1d2e4 | ||
|
|
dd76dcfc98 | ||
|
|
b35c3a0e61 | ||
|
|
47a83a8bfe | ||
|
|
de2978138a | ||
|
|
abb1bd4718 | ||
|
|
ec553bf429 | ||
|
|
488fe352cd | ||
|
|
7fdc939450 | ||
|
|
ae08c7c937 | ||
|
|
4ee74a6789 | ||
|
|
5804f42211 | ||
|
|
29c3b2f2f1 | ||
|
|
20bf1cedd0 | ||
|
|
8a24c50448 | ||
|
|
3b761f9589 | ||
|
|
20306ec83e | ||
|
|
930e05cc58 | ||
|
|
acc308379c | ||
|
|
65941a8304 | ||
|
|
c58cf94181 | ||
|
|
88228bfad7 | ||
|
|
550ffdf92d | ||
|
|
89be2dfa43 | ||
|
|
03323172ea | ||
|
|
74cbad5127 | ||
|
|
0c71c4db29 | ||
|
|
6189fb497e | ||
|
|
00549bbcba | ||
|
|
9fd0d5f2e2 | ||
|
|
567200cfe4 | ||
|
|
0404f7be90 | ||
|
|
afe9f77869 | ||
|
|
72f78e5c6b | ||
|
|
ffd1fc1551 | ||
|
|
9d6dbc8d31 | ||
|
|
6400d1d395 | ||
|
|
dc680231ea | ||
|
|
97e6f8b7f5 | ||
|
|
22d0db1d78 | ||
|
|
bdc0000476 | ||
|
|
64b5010a44 | ||
|
|
92eec290b1 | ||
|
|
a7c840d532 | ||
|
|
80ba3644f7 | ||
|
|
a0c6ceef15 | ||
|
|
8b8c443bd1 | ||
|
|
72f71b2153 | ||
|
|
7349ee6c5e | ||
|
|
04c4ef25d2 | ||
|
|
b5da3d3ac4 | ||
|
|
28a6fecab3 | ||
|
|
7eb25e45b3 | ||
|
|
e9dc166e1e | ||
|
|
a7427f3632 | ||
|
|
9b38e2c63e | ||
|
|
61cbc212b5 | ||
|
|
27156b5070 | ||
|
|
b8bb6d41f9 | ||
|
|
794d132086 | ||
|
|
608b7e9311 | ||
|
|
b0b2283ca5 | ||
|
|
38787b45c1 | ||
|
|
f9ebe84012 | ||
|
|
f34cb8eb3c | ||
|
|
148104880e | ||
|
|
f559c60154 | ||
|
|
82032109dd | ||
|
|
7d3d746c4d | ||
|
|
a9a4aa9737 | ||
|
|
eebe691419 | ||
|
|
6926f87747 | ||
|
|
971379b773 | ||
|
|
ad3bdff823 | ||
|
|
9c137ada9f | ||
|
|
0f4a70b204 | ||
|
|
f58f851151 | ||
|
|
be26b3e1dc | ||
|
|
9ca8ec65c4 | ||
|
|
1156824463 | ||
|
|
f48a46d0e4 | ||
|
|
738aa1132a | ||
|
|
80e49ad85a | ||
|
|
f9c4650ace | ||
|
|
891721bf45 | ||
|
|
f694eb4f4d | ||
|
|
f3257660ca | ||
|
|
7f5d205e4b | ||
|
|
524a791629 | ||
|
|
1d0716d47f | ||
|
|
04029d50db | ||
|
|
5ba7ee746c | ||
|
|
a6f772f4de | ||
|
|
f8f7aba3a8 | ||
|
|
88c7bb6bca | ||
|
|
8ef0d103e4 | ||
|
|
96ae6338a7 | ||
|
|
9b76d42707 | ||
|
|
5998a7e66d | ||
|
|
c8f7a29812 | ||
|
|
13f1cc6455 | ||
|
|
bf72cd2061 | ||
|
|
253321f3c2 | ||
|
|
9baaf38a49 | ||
|
|
5c5f08afc0 | ||
|
|
5f4c63ee49 | ||
|
|
af7e027350 | ||
|
|
db8fe3ce8d | ||
|
|
55a827330f | ||
|
|
6fa63fdcff | ||
|
|
b6d019ace7 | ||
|
|
84240c94c6 | ||
|
|
09f35579dc | ||
|
|
8c7e2c9bb0 | ||
|
|
f3d64d23b2 | ||
|
|
37ede31227 | ||
|
|
08b4274ca2 | ||
|
|
fa0f300dcd | ||
|
|
1fafd04190 | ||
|
|
f295b3b224 | ||
|
|
e6d0671816 | ||
|
|
4bf2e6c768 | ||
|
|
94751519ac | ||
|
|
673474a51f | ||
|
|
a82915c0ca | ||
|
|
bceeb01194 | ||
|
|
2c757a6b35 | ||
|
|
9a4de03cac | ||
|
|
c38fe8b10f | ||
|
|
60a67f86b6 | ||
|
|
ae21e9e5ca | ||
|
|
964fdfbc05 | ||
|
|
dc92bf1ab1 | ||
|
|
5460ed2a6c | ||
|
|
187791f895 | ||
|
|
0638539f3c | ||
|
|
69d256e008 | ||
|
|
d603a343ca | ||
|
|
a26f881160 | ||
|
|
eb1ac3341f | ||
|
|
ae1fbb1687 | ||
|
|
a0a95ce372 | ||
|
|
fb2008b07a | ||
|
|
74528f4a14 | ||
|
|
2d45fd614e | ||
|
|
1da35e901a | ||
|
|
5de8787368 | ||
|
|
e3e621e55f | ||
|
|
fdb5752408 | ||
|
|
c91c58ac69 | ||
|
|
0110de8104 | ||
|
|
1a59b5e3e1 | ||
|
|
5ef79148bd | ||
|
|
1806e0d147 | ||
|
|
4cfab17413 | ||
|
|
48758b4f3d | ||
|
|
fe69e90749 | ||
|
|
3c29dafd51 | ||
|
|
9ffb793dfd | ||
|
|
e9a6471b6d | ||
|
|
53fcf4790a | ||
|
|
865ecfb5bf | ||
|
|
d0569f4645 | ||
|
|
3db474c763 | ||
|
|
5f7c3e3786 | ||
|
|
e27224d9a8 | ||
|
|
e5e5fe7ee7 | ||
|
|
18820b79f4 | ||
|
|
a205ebfa2b | ||
|
|
703dc17794 | ||
|
|
046ec8ee8c | ||
|
|
7cfe44ed13 | ||
|
|
5352bd5182 | ||
|
|
db710c55c4 | ||
|
|
555c2fe626 | ||
|
|
7b4f58dd78 | ||
|
|
b2deab0d7c | ||
|
|
39c3a69a11 | ||
|
|
8c67ec4808 | ||
|
|
c2216e4917 | ||
|
|
cfd1a2f2b8 | ||
|
|
af49acf4d9 | ||
|
|
7e97cbea1b | ||
|
|
6b3a3b31d6 | ||
|
|
2044ea273b | ||
|
|
aef560942f | ||
|
|
2ba06c779f | ||
|
|
040ad844f5 | ||
|
|
76dce66a4a | ||
|
|
8d8e0bb7ac | ||
|
|
995953b823 | ||
|
|
e8208b7934 | ||
|
|
de11eb98c0 | ||
|
|
a8b43ca3fb | ||
|
|
6f8db0b9b1 | ||
|
|
a882a73b8e | ||
|
|
33d25d3c25 | ||
|
|
37c5ebbf2e | ||
|
|
f04e54d59b | ||
|
|
332b6f666c | ||
|
|
e0f900366a | ||
|
|
4edf316b5e | ||
|
|
d32e5a5ce3 | ||
|
|
46bf23171f | ||
|
|
ca3a9e900f | ||
|
|
f370aef0a7 | ||
|
|
af7a4d03d2 | ||
|
|
0ddd0286a5 | ||
|
|
46f1ea9880 | ||
|
|
31ed6230ba | ||
|
|
c981f0900a | ||
|
|
d013afbf50 | ||
|
|
a6d63748fb | ||
|
|
5b1bf943e9 | ||
|
|
2427f8cbf5 | ||
|
|
cf41889017 | ||
|
|
8134db90d6 | ||
|
|
d493e3e87b | ||
|
|
c37537bd67 | ||
|
|
62026abd71 | ||
|
|
41a34ce524 | ||
|
|
6e06e16493 | ||
|
|
d3def31c82 | ||
|
|
6c78d17faf | ||
|
|
dbae12a4e4 | ||
|
|
3722ec3b05 | ||
|
|
44910389e3 | ||
|
|
0dfd7e6250 | ||
|
|
4705ff6915 | ||
|
|
ab811e4ead | ||
|
|
8df2334cd6 | ||
|
|
b169af4883 | ||
|
|
06633625ba | ||
|
|
ef51f671b7 | ||
|
|
a15e789e70 | ||
|
|
31fe18e4b5 | ||
|
|
07db0378c5 | ||
|
|
4c83cd2e21 | ||
|
|
4fa2f13834 | ||
|
|
decc24ea2a | ||
|
|
38d21b98a0 | ||
|
|
7d970b9287 | ||
|
|
386c087946 | ||
|
|
bfeeff5372 | ||
|
|
7be9965352 | ||
|
|
f6ca069896 | ||
|
|
68fbd4fc1a | ||
|
|
a8f3c5eb77 | ||
|
|
c929e94d0e | ||
|
|
271719c651 | ||
|
|
bf1ce64553 | ||
|
|
9199765c61 | ||
|
|
124def913a | ||
|
|
0c961005fc | ||
|
|
c06b54a3c3 | ||
|
|
0438b8a51f | ||
|
|
02dd0a5a78 | ||
|
|
68f124ca98 | ||
|
|
f1a78a1f47 | ||
|
|
b2285a691d | ||
|
|
791a9c206f | ||
|
|
2ec3826d63 | ||
|
|
24ab1b0990 | ||
|
|
44497b8c3d | ||
|
|
c58997460c | ||
|
|
f055d96e5a | ||
|
|
4556d2d975 | ||
|
|
62f8a4a534 | ||
|
|
e9eba47429 | ||
|
|
2fac5814d8 | ||
|
|
b850c7a41d | ||
|
|
19a0649cb3 | ||
|
|
59771bd0b3 | ||
|
|
fde0159a21 | ||
|
|
4c3731c23e | ||
|
|
4f206abdc6 | ||
|
|
45b51ad65a | ||
|
|
2fbb2a2733 | ||
|
|
b91a7c1ff8 | ||
|
|
e524a62b77 | ||
|
|
e391ef6109 | ||
|
|
328810fccf | ||
|
|
2d898f1c7b | ||
|
|
8d123441b1 | ||
|
|
58839c3714 | ||
|
|
64357697bd | ||
|
|
e59cf9e58a | ||
|
|
e5b9c7a132 | ||
|
|
b7f7f0b477 | ||
|
|
ca92f8581e | ||
|
|
e06b1bcb11 | ||
|
|
cfdba41ed5 | ||
|
|
a7eb805f6d | ||
|
|
7eb388f63a | ||
|
|
04fc4fd3aa | ||
|
|
1c766abd24 | ||
|
|
9930fc9bde | ||
|
|
628a01b530 | ||
|
|
e9424ad997 | ||
|
|
8b1901fd48 | ||
|
|
0a124a36e6 | ||
|
|
8eb551fde6 | ||
|
|
ad073724cb | ||
|
|
68bae19b1a | ||
|
|
810fa5b85c | ||
|
|
69b3e4f70b | ||
|
|
1c6d22ccf9 | ||
|
|
886a27b016 | ||
|
|
5dba44c1db | ||
|
|
54e03e1de2 | ||
|
|
2413ec2be1 | ||
|
|
4e9b312ae5 | ||
|
|
b071131ba3 | ||
|
|
57eb0a7a38 | ||
|
|
753a3c823f | ||
|
|
c6aae706f9 | ||
|
|
6631f1e745 | ||
|
|
46e92424d4 | ||
|
|
648da0094a | ||
|
|
d776b87232 | ||
|
|
81074941b0 | ||
|
|
1c7ce3f726 | ||
|
|
4e0aa1481b | ||
|
|
0ba26d4d75 | ||
|
|
c4abf214f6 | ||
|
|
71c9e2c298 | ||
|
|
0ef2a09e8a | ||
|
|
63a759e499 | ||
|
|
52c77181c8 | ||
|
|
ad194ba5df | ||
|
|
75374ca4d9 | ||
|
|
1d753ba81f | ||
|
|
e38ee6384e | ||
|
|
f89a462216 | ||
|
|
747a7620b0 | ||
|
|
3935765491 | ||
|
|
704dac6a75 | ||
|
|
8164384498 | ||
|
|
6b39a6759a | ||
|
|
58fe352e30 | ||
|
|
41cf2f3a5d | ||
|
|
a7bccd3b53 | ||
|
|
f943268035 | ||
|
|
3cd8516d88 | ||
|
|
4b050e21f0 | ||
|
|
b87f2a6e72 | ||
|
|
d4ac615a8d | ||
|
|
9e557ebcf5 |
No files matched your search
@@ -0,0 +1,10 @@
|
||||
# indicate this is the root of the project
|
||||
root = true
|
||||
|
||||
[*.{kt,java,xml,gradle,md}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
@@ -0,0 +1,76 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v**
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.ref_name }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
|
||||
- name: Assemble Artifacts
|
||||
run: |
|
||||
./gradlew assembleRelease
|
||||
./gradlew bundleRelease
|
||||
|
||||
- name: Sign APK
|
||||
uses: r0adkll/sign-android-release@v1
|
||||
id: sign_apk
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/release
|
||||
signingKeyBase64: ${{ secrets.KEY_STORE }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
alias: ${{ secrets.KEY_ALIAS }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Sign Bundle
|
||||
uses: r0adkll/sign-android-release@v1
|
||||
id: sign_bundle
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/bundle/release
|
||||
signingKeyBase64: ${{ secrets.KEY_STORE }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
alias: ${{ secrets.KEY_ALIAS }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Rename Artifacts
|
||||
run: |
|
||||
mv ${{steps.sign_apk.outputs.signedReleaseFile}} app/build/outputs/apk/release/look4sat.apk
|
||||
mv ${{steps.sign_bundle.outputs.signedReleaseFile}} app/build/outputs/apk/release/look4sat.aab
|
||||
|
||||
- name: Deploy Bundle
|
||||
uses: r0adkll/upload-google-play@v1
|
||||
with:
|
||||
serviceAccountJsonPlainText: ${{secrets.SERVICE_ACCOUNT_JSON}}
|
||||
packageName: com.rtbishop.look4sat
|
||||
releaseFiles: app/build/outputs/apk/release/look4sat.aab
|
||||
track: production
|
||||
whatsNewDirectory: fastlane/metadata/android/en-US/whatsnew
|
||||
|
||||
- name: Create Release
|
||||
run: |
|
||||
gh release create $TAG_NAME --title=$TAG_NAME --generate-notes
|
||||
gh release upload $TAG_NAME app/build/outputs/apk/release/look4sat.apk
|
||||
@@ -38,6 +38,9 @@ captures/
|
||||
# Keystore files
|
||||
# Uncomment the following line if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
/*.properties
|
||||
/keystore.properties
|
||||
/app/keystore.jks
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
@@ -56,3 +59,8 @@ fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
/app/release/app-release.aab
|
||||
/app/release/app-release.apk
|
||||
/app/release/output-metadata.json
|
||||
/app/release/
|
||||
/.kotlin/sessions/
|
||||
@@ -1,281 +1,622 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
0. Definitions.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
1. Source Code.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
2. Basic Permissions.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
14. Revised Versions of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
NO WARRANTY
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
@@ -303,37 +644,31 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -1,33 +1,35 @@
|
||||
# Look4Sat: Radio satellite tracker
|
||||
# Look4Sat: Satellite tracker
|
||||
|
||||
[](https://github.com/rt-bishop/Look4Sat/actions/workflows/release.yml)
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/packages/com.rtbishop.look4sat/)
|
||||
[<img src="https://play.google.com/intl/en_gb/badges/static/images/badges/en_badge_web_generic.png" alt="Get it on Google Play" height="80">](https://play.google.com/store/apps/details?id=com.rtbishop.look4sat)
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/packages/com.rtbishop.look4sat/)
|
||||
|
||||
Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
|
||||
The very app creation and design is hugely inspired by the open-source [Gpredict](http://gpredict.oz9aec.net/) desktop satellite tracking application, created by [Alexandru Csete, OZ9AEC](https://github.com/csete) and contributors, supported by the [Libre Space Foundation](https://libre.space/).
|
||||
|
||||
The [Libre Space Foundation](https://libre.space/) team is also behind the epic [SatNOGS](https://satnogs.org/) project that provides an extremely easy to use [API](https://db.satnogs.org/api/) and [DB](https://db.satnogs.org/) with a huge amount of information about satellites, their telemetry and transmitters, which the app uses under the hood.
|
||||
|
||||
For TLE data calculation and passes prediction Look4Sat uses the mavenized version of [predict4java](https://github.com/davidmoten/predict4java) library, created by [David A. B. Johnson, G4DPZ](https://github.com/g4dpz) and [Dave Moten](https://github.com/davidmoten). Thank you guys for your hard work making this lib efficient and easy to use!
|
||||
|
||||
Also, I'd like to mention Dr T.S. Kelso for his invaluable contribution to the industry and for his [Celestrak](https://celestrak.com) website, that stores, updates and provides access to TLE data.
|
||||
|
||||
The app is built using Dagger2, Retrofit2, Kotlin and Kotlin coroutines, Architecture Components and Jetpack Navigation.
|
||||
### Radio satellite tracker and pass predictor for Android, inspired by Gpredict
|
||||
|
||||
<p float="left">
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" width="250"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" width="250"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" width="250"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" width="192"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" width="192"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" width="192"/>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" width="192">
|
||||
</p>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" width="750">
|
||||
|
||||
### Track satellite passes with ease!
|
||||
|
||||
Thanks to [Celestrak](https://celestrak.com/) and [SatNOGS](https://satnogs.org/) you have access to over 9000 active satellites.\
|
||||
You can search the entire database by NORAD Catalog Number or the satellite's name.
|
||||
|
||||
Orbital positions and passes are calculated relative to your location.\
|
||||
To get reliable data make sure to set the station position via the app Settings.
|
||||
|
||||
The application is built using Kotlin, Coroutines, Jetpack Compose and Navigation.\
|
||||
It is now and always will be completely ad-free and open-source.
|
||||
|
||||
## Main features:
|
||||
|
||||
* Calculating satellite passes for up to one week (168 hours)
|
||||
* Calculating passes for the current or manually entered location
|
||||
* Predicting satellite positions and passes for up to 10 days
|
||||
* Showing the list of currently active and upcoming satellite passes
|
||||
* Showing the active pass progress, polar trajectory and transceivers info
|
||||
* Showing the satellite positional data, footprint and ground track on a map
|
||||
* Offline first: passes predictions are made offline.
|
||||
Weekly updates of TLEs and transceivers DB are recommended.
|
||||
* Showing the satellite positional data, footprint and ground track on the map
|
||||
* Custom TLE satellite data import is available via Three Line Element .txt files
|
||||
* Offline first: calculations are made offline. Weekly TLE data update is recommended.
|
||||
@@ -1 +1,2 @@
|
||||
/build
|
||||
/release
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: "androidx.navigation.safeargs.kotlin"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
defaultConfig {
|
||||
applicationId "com.rtbishop.look4sat"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 18
|
||||
versionName '1.4.8'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
postprocessing {
|
||||
removeUnusedCode true
|
||||
removeUnusedResources true
|
||||
obfuscate false
|
||||
optimizeCode true
|
||||
}
|
||||
}
|
||||
}
|
||||
configurations {
|
||||
all {
|
||||
exclude module: 'commons-logging'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "com.google.android.material:material:$material_version"
|
||||
implementation "androidx.appcompat:appcompat:$app_compat_version"
|
||||
implementation "androidx.legacy:legacy-support-v4:$support_lib_version"
|
||||
implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version"
|
||||
implementation "androidx.core:core-ktx:$ktx_version"
|
||||
implementation "androidx.preference:preference:$preference_version"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
||||
implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
||||
implementation "com.google.dagger:dagger:$dagger_version"
|
||||
kapt "com.google.dagger:dagger-compiler:$dagger_version"
|
||||
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||
|
||||
implementation "org.osmdroid:osmdroid-android:$openStreetMap_version"
|
||||
|
||||
implementation "com.github.davidmoten:predict4java:$predict4java_version"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
alias(libs.plugins.convention.applicationPlugin)
|
||||
}
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,50 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.rtbishop.look4sat">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:name="com.rtbishop.look4sat.Look4SatApp"
|
||||
android:allowBackup="false"
|
||||
android:name=".MainApplication"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
android:roundIcon="@mipmap/ic_launcher_round">
|
||||
|
||||
<activity
|
||||
android:name="com.rtbishop.look4sat.ui.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Splash">
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Look4Sat.SplashScreen">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<meta-data
|
||||
android:name="android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED"
|
||||
android:value="com.rtbishop.look4sat" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat
|
||||
|
||||
import android.app.Application
|
||||
import com.rtbishop.look4sat.dagger.AppComponent
|
||||
import com.rtbishop.look4sat.dagger.DaggerAppComponent
|
||||
|
||||
class Look4SatApp : Application() {
|
||||
|
||||
val appComponent: AppComponent by lazy {
|
||||
DaggerAppComponent.factory().create(applicationContext)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2026 Arty Bishop and contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import com.rtbishop.look4sat.core.presentation.MainTheme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun attachBaseContext(newBase: Context?) {
|
||||
val config = Configuration(newBase?.resources?.configuration)
|
||||
applyOverrideConfiguration(config.apply { fontScale = 1.0f })
|
||||
super.attachBaseContext(newBase)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
MainTheme(isDarkTheme = true) { MainScreen() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2026 Arty Bishop and contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat
|
||||
|
||||
import android.app.Application
|
||||
import com.rtbishop.look4sat.core.data.injection.MainContainer
|
||||
import com.rtbishop.look4sat.core.domain.repository.IContainerProvider
|
||||
import com.rtbishop.look4sat.core.domain.repository.IMainContainer
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class MainApplication : Application(), IContainerProvider {
|
||||
|
||||
private lateinit var container: IMainContainer
|
||||
|
||||
override fun getMainContainer(): IMainContainer = container
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
container = MainContainer(this)
|
||||
// trigger automatic update every 48 hours
|
||||
container.appScope.launch { checkAutoUpdate() }
|
||||
// load satellite data on every app start
|
||||
container.appScope.launch { container.satelliteRepo.initRepository() }
|
||||
}
|
||||
|
||||
private suspend fun checkAutoUpdate(timeNow: Long = System.currentTimeMillis()) {
|
||||
if (container.settingsRepo.otherSettings.value.stateOfAutoUpdate) {
|
||||
val timeDelta = timeNow - container.settingsRepo.databaseState.value.updateTimestamp
|
||||
if (timeDelta > 172_800_000L) { // 48 hours in ms
|
||||
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
|
||||
println("Started periodic data update on ${sdf.format(Date())}")
|
||||
container.databaseRepo.updateFromRemote()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||
* Copyright (C) 2019-2026 Arty Bishop and contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteDefaults
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
||||
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.rtbishop.look4sat.core.presentation.Screen
|
||||
import com.rtbishop.look4sat.core.presentation.hasEnoughHeight
|
||||
import com.rtbishop.look4sat.core.presentation.hasEnoughWidth
|
||||
import com.rtbishop.look4sat.core.domain.repository.IContainerProvider
|
||||
import com.rtbishop.look4sat.feature.map.mapDestination
|
||||
import com.rtbishop.look4sat.feature.passes.passesDestination
|
||||
import com.rtbishop.look4sat.feature.radar.radarDestination
|
||||
import com.rtbishop.look4sat.feature.radiocontrol.radioControlDestination
|
||||
import com.rtbishop.look4sat.feature.satellites.satellitesDestination
|
||||
import com.rtbishop.look4sat.feature.settings.settingsDestination
|
||||
|
||||
@Composable
|
||||
fun MainScreen(navController: NavHostController = rememberNavController()) {
|
||||
val items = listOf(Screen.Satellites, Screen.Passes, Screen.Radar, Screen.Map, Screen.Settings)
|
||||
val currentDestination = navController.currentBackStackEntryAsState().value?.destination?.route
|
||||
val startDestination = Screen.Passes.route
|
||||
|
||||
// Observe radio tracking state for the status bar
|
||||
val context = LocalContext.current
|
||||
val container = (context.applicationContext as IContainerProvider).getMainContainer()
|
||||
val trackingState by container.radioTrackingService.state.collectAsStateWithLifecycle()
|
||||
|
||||
NavigationSuiteScaffold(
|
||||
navigationSuiteItems = {
|
||||
items.forEach {
|
||||
item(
|
||||
icon = { Icon(painterResource(it.iconResId), stringResource(it.titleResId)) },
|
||||
label = { Text(stringResource(it.titleResId)) },
|
||||
selected = currentDestination?.contains(it.route) ?: false,
|
||||
onClick = {
|
||||
if (currentDestination?.contains(it.route) ?: false) return@item
|
||||
navController.navigate(it.route) {
|
||||
popUpTo(startDestination) { saveState = false }
|
||||
launchSingleTop = true
|
||||
restoreState = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}, navigationSuiteColors = NavigationSuiteDefaults.colors(
|
||||
navigationRailContainerColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
), layoutType = when {
|
||||
!hasEnoughHeight() && hasEnoughWidth() -> NavigationSuiteType.NavigationRail
|
||||
!hasEnoughWidth() -> NavigationSuiteType.ShortNavigationBarCompact
|
||||
else -> NavigationSuiteType.ShortNavigationBarMedium
|
||||
}
|
||||
) {
|
||||
Column {
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = startDestination,
|
||||
enterTransition = { fadeIn(animationSpec = tween(350)) },
|
||||
exitTransition = { fadeOut(animationSpec = tween(350)) },
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
satellitesDestination { navController.navigateUp() }
|
||||
passesDestination { catNum: Int, aosTime: Long ->
|
||||
val radarRoute = "${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}"
|
||||
navController.navigate(radarRoute)
|
||||
}
|
||||
radarDestination(
|
||||
navigateUp = { navController.navigateUp() },
|
||||
navigateToRadioControl = { catNum, aosTime ->
|
||||
val route = "${Screen.RadioControl.route}?catNum=$catNum&aosTime=$aosTime"
|
||||
navController.navigate(route)
|
||||
}
|
||||
)
|
||||
radioControlDestination { navController.navigateUp() }
|
||||
mapDestination()
|
||||
settingsDestination()
|
||||
}
|
||||
|
||||
// Radio tracking status banner (above bottom navigation)
|
||||
if (trackingState.isActive) {
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "trackingPulse")
|
||||
val alpha by infiniteTransition.animateFloat(
|
||||
initialValue = 1f, targetValue = 0.4f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(1000, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Reverse
|
||||
), label = "pulseAlpha"
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.primaryContainer)
|
||||
.clickable {
|
||||
val pass = trackingState.currentPass
|
||||
if (pass != null) {
|
||||
val route = "${Screen.RadioControl.route}?catNum=${pass.catNum}&aosTime=${pass.aosTime}"
|
||||
navController.navigate(route)
|
||||
}
|
||||
}
|
||||
.padding(horizontal = 12.dp, vertical = 6.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(8.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color(0xFF4CAF50).copy(alpha = alpha))
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "Tracking: ${trackingState.currentPass?.name ?: ""}",
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
val txOk = if (trackingState.txConnected) "TX" else ""
|
||||
val rxOk = if (trackingState.rxConnected) "RX" else ""
|
||||
Text(
|
||||
text = listOf(txOk, rxOk).filter { it.isNotBlank() }.joinToString("/"),
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
}
|
||||
}
|
||||
} // end Column
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.dagger
|
||||
|
||||
import android.content.Context
|
||||
import com.rtbishop.look4sat.dagger.modules.*
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.fragments.MapOsmFragment
|
||||
import com.rtbishop.look4sat.ui.fragments.MapViewFragment
|
||||
import com.rtbishop.look4sat.ui.fragments.PassListFragment
|
||||
import com.rtbishop.look4sat.ui.fragments.PolarViewFragment
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(
|
||||
modules = [NetworkModule::class, PersistenceModule::class,
|
||||
RepoModule::class, UtilityModule::class, ViewModelModule::class]
|
||||
)
|
||||
interface AppComponent {
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(@BindsInstance context: Context): AppComponent
|
||||
}
|
||||
|
||||
fun inject(mainActivity: MainActivity)
|
||||
fun inject(mapViewFragment: MapViewFragment)
|
||||
fun inject(passListFragment: PassListFragment)
|
||||
fun inject(polarViewFragment: PolarViewFragment)
|
||||
fun inject(mapOsmFragment: MapOsmFragment)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.rtbishop.look4sat.dagger
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ViewModelFactory @Inject constructor(
|
||||
private val creators: Map<Class<out ViewModel>,
|
||||
@JvmSuppressWildcards Provider<ViewModel>>
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
|
||||
modelClass.isAssignableFrom(it.key)
|
||||
}?.value ?: throw IllegalArgumentException("Unsupported ViewModel class: $modelClass")
|
||||
try {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return creator.get() as T
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.rtbishop.look4sat.dagger
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.MapKey
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MapKey
|
||||
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import com.rtbishop.look4sat.network.RemoteDataSource
|
||||
import com.rtbishop.look4sat.network.RemoteSource
|
||||
import com.rtbishop.look4sat.network.TransmittersApi
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class NetworkModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideOkHttpClient(): OkHttpClient {
|
||||
return OkHttpClient()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideRemoteDataSource(api: TransmittersApi, client: OkHttpClient): RemoteSource {
|
||||
return RemoteDataSource(api, client)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTransmittersApi(): TransmittersApi {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl("https://db.satnogs.org/api/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(TransmittersApi::class.java)
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import com.rtbishop.look4sat.persistence.LocalDataSource
|
||||
import com.rtbishop.look4sat.persistence.LocalSource
|
||||
import com.rtbishop.look4sat.persistence.SatelliteDb
|
||||
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.SourcesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class PersistenceModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideEntriesDao(db: SatelliteDb): EntriesDao {
|
||||
return db.entriesDao()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTransmittersDao(db: SatelliteDb): TransmittersDao {
|
||||
return db.transmittersDao()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providesSourcesDao(db: SatelliteDb): SourcesDao {
|
||||
return db.sourcesDao()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideLocalDataSource(
|
||||
entriesDao: EntriesDao,
|
||||
transmittersDao: TransmittersDao,
|
||||
sourcesDao: SourcesDao
|
||||
): LocalSource {
|
||||
return LocalDataSource(entriesDao, transmittersDao, sourcesDao)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSatelliteDb(context: Context): SatelliteDb {
|
||||
return Room.databaseBuilder(context, SatelliteDb::class.java, "satDb")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import com.rtbishop.look4sat.network.RemoteSource
|
||||
import com.rtbishop.look4sat.persistence.LocalSource
|
||||
import com.rtbishop.look4sat.repo.DefaultRepository
|
||||
import com.rtbishop.look4sat.repo.Repository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class RepoModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideContentResolver(context: Context): ContentResolver {
|
||||
return context.applicationContext.contentResolver
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideDefaultRepository(
|
||||
resolver: ContentResolver,
|
||||
localSource: LocalSource,
|
||||
remoteSource: RemoteSource
|
||||
): Repository {
|
||||
return DefaultRepository(resolver, localSource, remoteSource)
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.location.LocationManager
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
class UtilityModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSharedPreferences(context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideLocationManager(context: Context): LocationManager {
|
||||
return context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providePrefsManager(
|
||||
sharedPreferences: SharedPreferences,
|
||||
locationManager: LocationManager
|
||||
): PrefsManager {
|
||||
return PrefsManager(sharedPreferences, locationManager)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.rtbishop.look4sat.dagger.modules
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.dagger.ViewModelKey
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
abstract class ViewModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(SharedViewModel::class)
|
||||
abstract fun bindSharedViewModel(viewModel: SharedViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
sealed class Result<out T : Any> {
|
||||
data class Success<out T : Any>(val data: T) : Result<T>()
|
||||
data class Error(val exception: Exception) : Result<Nothing>()
|
||||
object InProgress : Result<Nothing>()
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
|
||||
@Entity(tableName = "entries")
|
||||
data class SatEntry(val tle: TLE, var isSelected: Boolean = false) {
|
||||
@PrimaryKey
|
||||
var catNum: Int = tle.catnum
|
||||
var name: String = tle.name
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import org.osmdroid.api.IGeoPoint
|
||||
import org.osmdroid.views.overlay.OverlayItem
|
||||
|
||||
data class SatItem(
|
||||
val name: String,
|
||||
val description: String,
|
||||
val position: IGeoPoint,
|
||||
val pass: SatPass
|
||||
) : OverlayItem(name, description, position)
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import com.github.amsacode.predict4java.SatPassTime
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
|
||||
data class SatPass(
|
||||
val tle: TLE,
|
||||
val predictor: PassPredictor,
|
||||
val pass: SatPassTime,
|
||||
var progress: Int = 0,
|
||||
var active: Boolean = false
|
||||
)
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "sources")
|
||||
data class TleSource(@PrimaryKey var url: String = String())
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Entity(tableName = "transmitters")
|
||||
data class Transmitter(
|
||||
@PrimaryKey @SerializedName("uuid") val uuid: String,
|
||||
@SerializedName("description") val description: String,
|
||||
@SerializedName("alive") val isAlive: Boolean,
|
||||
@SerializedName("uplink_low") val uplinkLow: Long?,
|
||||
@SerializedName("uplink_high") val uplinkHigh: Long?,
|
||||
@SerializedName("downlink_low") val downlinkLow: Long?,
|
||||
@SerializedName("downlink_high") val downlinkHigh: Long?,
|
||||
@SerializedName("mode") val mode: String?,
|
||||
@SerializedName("invert") val isInverted: Boolean,
|
||||
@SerializedName("norad_cat_id") val catNum: Int
|
||||
)
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.network
|
||||
|
||||
import android.util.Log
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
class RemoteDataSource @Inject constructor(
|
||||
private val api: TransmittersApi,
|
||||
private val client: OkHttpClient
|
||||
) : RemoteSource {
|
||||
|
||||
override suspend fun fetchTleStreams(urlList: List<TleSource>): List<InputStream> {
|
||||
val streams = mutableListOf<InputStream>()
|
||||
withContext(Dispatchers.IO) {
|
||||
urlList.withIndex().forEach {
|
||||
val request = Request.Builder().url(it.value.url).build()
|
||||
val stream = client.newCall(request).execute().body?.byteStream()
|
||||
stream?.let { inputStream -> streams.add(inputStream) }
|
||||
}
|
||||
}
|
||||
Log.d("myTag", urlList.toString())
|
||||
return streams
|
||||
}
|
||||
|
||||
override suspend fun fetchTransmitters(): List<Transmitter> {
|
||||
return api.fetchTransmitters()
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.rtbishop.look4sat.network
|
||||
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import java.io.InputStream
|
||||
|
||||
interface RemoteSource {
|
||||
|
||||
suspend fun fetchTleStreams(urlList: List<TleSource>): List<InputStream>
|
||||
|
||||
suspend fun fetchTransmitters(): List<Transmitter>
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.network
|
||||
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import retrofit2.http.GET
|
||||
|
||||
interface TransmittersApi {
|
||||
|
||||
@GET("transmitters/")
|
||||
suspend fun fetchTransmitters(): List<Transmitter>
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.persistence
|
||||
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.SourcesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||
import javax.inject.Inject
|
||||
|
||||
class LocalDataSource @Inject constructor(
|
||||
private val entriesDao: EntriesDao,
|
||||
private val transmittersDao: TransmittersDao,
|
||||
private val sourcesDao: SourcesDao
|
||||
) : LocalSource {
|
||||
|
||||
override suspend fun insertEntries(entries: List<SatEntry>) {
|
||||
entriesDao.insertEntries(entries)
|
||||
}
|
||||
|
||||
override suspend fun getAllEntries(): List<SatEntry> {
|
||||
return entriesDao.getAllEntries()
|
||||
}
|
||||
|
||||
override suspend fun getSelectedEntries(): List<SatEntry> {
|
||||
return entriesDao.getSelectedEntries()
|
||||
}
|
||||
|
||||
override suspend fun updateEntriesSelection(catNumList: List<Int>) {
|
||||
entriesDao.clearEntriesSelection()
|
||||
catNumList.forEach { entriesDao.updateEntrySelection(it) }
|
||||
}
|
||||
|
||||
override suspend fun clearEntries() {
|
||||
entriesDao.clearEntries()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun insertTransmitters(transmitters: List<Transmitter>) {
|
||||
transmittersDao.insertTransmitters(transmitters)
|
||||
}
|
||||
|
||||
override suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter> {
|
||||
return transmittersDao.getTransmittersByCatNum(catNum)
|
||||
}
|
||||
|
||||
override suspend fun clearTransmitters() {
|
||||
transmittersDao.clearTransmitters()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun insertSources(sources: List<TleSource>) {
|
||||
sourcesDao.insertSources(sources)
|
||||
}
|
||||
|
||||
override suspend fun getSources(): List<TleSource> {
|
||||
return sourcesDao.getSources()
|
||||
}
|
||||
|
||||
override suspend fun clearSources() {
|
||||
sourcesDao.clearSources()
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.rtbishop.look4sat.persistence
|
||||
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
|
||||
interface LocalSource {
|
||||
|
||||
suspend fun insertEntries(entries: List<SatEntry>)
|
||||
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
|
||||
suspend fun getSelectedEntries(): List<SatEntry>
|
||||
|
||||
suspend fun updateEntriesSelection(catNumList: List<Int>)
|
||||
|
||||
suspend fun clearEntries()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun insertTransmitters(transmitters: List<Transmitter>)
|
||||
|
||||
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||
|
||||
suspend fun clearTransmitters()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun insertSources(sources: List<TleSource>)
|
||||
|
||||
suspend fun getSources(): List<TleSource>
|
||||
|
||||
suspend fun clearSources()
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.persistence
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import com.rtbishop.look4sat.persistence.dao.EntriesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.SourcesDao
|
||||
import com.rtbishop.look4sat.persistence.dao.TransmittersDao
|
||||
import com.rtbishop.look4sat.utility.Converters
|
||||
|
||||
@Database(
|
||||
entities = [Transmitter::class, SatEntry::class, TleSource::class],
|
||||
version = 1,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class SatelliteDb : RoomDatabase() {
|
||||
|
||||
abstract fun entriesDao(): EntriesDao
|
||||
|
||||
abstract fun transmittersDao(): TransmittersDao
|
||||
|
||||
abstract fun sourcesDao(): SourcesDao
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.persistence.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
|
||||
@Dao
|
||||
interface EntriesDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertEntries(entries: List<SatEntry>)
|
||||
|
||||
@Query("SELECT * FROM entries ORDER BY name ASC")
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
|
||||
@Query("SELECT * FROM entries WHERE isSelected = 1 ORDER BY name ASC")
|
||||
suspend fun getSelectedEntries(): List<SatEntry>
|
||||
|
||||
@Query("UPDATE entries SET isSelected = 1 WHERE catNum == :catNum")
|
||||
suspend fun updateEntrySelection(catNum: Int)
|
||||
|
||||
@Query("UPDATE entries SET isSelected = 0")
|
||||
suspend fun clearEntriesSelection()
|
||||
|
||||
@Query("DELETE FROM entries")
|
||||
suspend fun clearEntries()
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.rtbishop.look4sat.persistence.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
|
||||
@Dao
|
||||
interface SourcesDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSources(sources: List<TleSource>)
|
||||
|
||||
@Query("SELECT * FROM sources")
|
||||
suspend fun getSources(): List<TleSource>
|
||||
|
||||
@Query("DELETE FROM sources")
|
||||
suspend fun clearSources()
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.rtbishop.look4sat.persistence.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
|
||||
@Dao
|
||||
interface TransmittersDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertTransmitters(transmitters: List<Transmitter>)
|
||||
|
||||
@Query("SELECT * FROM transmitters WHERE isAlive = 1 and catNum = :catNum")
|
||||
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||
|
||||
@Query("DELETE FROM transmitters")
|
||||
suspend fun clearTransmitters()
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.repo
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import com.rtbishop.look4sat.network.RemoteSource
|
||||
import com.rtbishop.look4sat.persistence.LocalSource
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
class DefaultRepository @Inject constructor(
|
||||
private val resolver: ContentResolver,
|
||||
private val localSource: LocalSource,
|
||||
private val remoteSource: RemoteSource
|
||||
) : Repository {
|
||||
|
||||
override suspend fun updateEntriesFromFile(tleUri: Uri) {
|
||||
withContext(Dispatchers.IO) {
|
||||
resolver.openInputStream(tleUri)?.use { stream ->
|
||||
val tleList = TLE.importSat(stream)
|
||||
val entries = tleList.map { SatEntry(it) }
|
||||
localSource.clearEntries()
|
||||
localSource.insertEntries(entries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateEntriesFromUrl(urlList: List<TleSource>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val streams = remoteSource.fetchTleStreams(urlList)
|
||||
val entries = mutableListOf<SatEntry>()
|
||||
streams.forEach {
|
||||
val list = TLE.importSat(it).map { tle -> SatEntry(tle) }
|
||||
entries.addAll(list)
|
||||
}
|
||||
localSource.clearEntries()
|
||||
localSource.insertEntries(entries)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAllEntries(): List<SatEntry> {
|
||||
return localSource.getAllEntries()
|
||||
}
|
||||
|
||||
override suspend fun getSelectedEntries(): List<SatEntry> {
|
||||
return localSource.getSelectedEntries()
|
||||
}
|
||||
|
||||
override suspend fun updateEntriesSelection(catNumList: List<Int>) {
|
||||
localSource.updateEntriesSelection(catNumList)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun updateTransmitters() {
|
||||
localSource.clearTransmitters()
|
||||
localSource.insertTransmitters(remoteSource.fetchTransmitters())
|
||||
}
|
||||
|
||||
override suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter> {
|
||||
return localSource.getTransmittersByCatNum(catNum)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override suspend fun updateSources(sources: List<TleSource>) {
|
||||
localSource.clearSources()
|
||||
localSource.insertSources(sources)
|
||||
}
|
||||
|
||||
override suspend fun getSources(): List<TleSource> {
|
||||
return localSource.getSources()
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.rtbishop.look4sat.repo
|
||||
|
||||
import android.net.Uri
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
|
||||
interface Repository {
|
||||
|
||||
suspend fun updateEntriesFromFile(tleUri: Uri)
|
||||
|
||||
suspend fun updateEntriesFromUrl(urlList: List<TleSource>)
|
||||
|
||||
suspend fun getAllEntries(): List<SatEntry>
|
||||
|
||||
suspend fun getSelectedEntries(): List<SatEntry>
|
||||
|
||||
suspend fun updateEntriesSelection(catNumList: List<Int>)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun updateTransmitters()
|
||||
|
||||
suspend fun getTransmittersByCatNum(catNum: Int): List<Transmitter>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun updateSources(sources: List<TleSource>)
|
||||
|
||||
suspend fun getSources(): List<TleSource>
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.databinding.ActivityMainBinding
|
||||
import com.rtbishop.look4sat.databinding.DrawerHeaderBinding
|
||||
import com.rtbishop.look4sat.ui.fragments.TleSourcesDialogFragment
|
||||
import com.rtbishop.look4sat.utility.Extensions.toast
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainActivity : AppCompatActivity(), TleSourcesDialogFragment.SourcesSubmitListener {
|
||||
|
||||
private val pickFileReqCode = 1001
|
||||
private val permissionsReqCode = 1000
|
||||
private val permissions = arrayOf(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var mainBinding: ActivityMainBinding
|
||||
private lateinit var drawerBinding: DrawerHeaderBinding
|
||||
private lateinit var appBarConfig: AppBarConfiguration
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(R.style.AppTheme)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mainBinding = ActivityMainBinding.inflate(layoutInflater)
|
||||
drawerBinding = DrawerHeaderBinding.inflate(layoutInflater, mainBinding.navView, true)
|
||||
setContentView(mainBinding.root)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
(application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(this, viewModelFactory).get(SharedViewModel::class.java)
|
||||
|
||||
setupComponents()
|
||||
setupObservers()
|
||||
setupDrawer()
|
||||
|
||||
viewModel.setDefaultTleSources()
|
||||
|
||||
if (!hasPermissions(this, permissions)) {
|
||||
ActivityCompat.requestPermissions(this, permissions, permissionsReqCode)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
private fun setupComponents() {
|
||||
val navController = findNavController(R.id.nav_host)
|
||||
val toolbar = mainBinding.includeAppBar.toolbar
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
appBarConfig = AppBarConfiguration(
|
||||
setOf(R.id.nav_pass_list, R.id.nav_map_view),
|
||||
mainBinding.drawerLayout
|
||||
)
|
||||
|
||||
setupActionBarWithNavController(navController, appBarConfig)
|
||||
mainBinding.navView.setupWithNavController(navController)
|
||||
|
||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
when (destination.id) {
|
||||
R.id.nav_pass_list -> {
|
||||
this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
toolbar.visibility = View.VISIBLE
|
||||
mainBinding.includeAppBar.toolbarLayout.visibility = View.VISIBLE
|
||||
}
|
||||
R.id.nav_map_view -> {
|
||||
this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
toolbar.visibility = View.GONE
|
||||
mainBinding.includeAppBar.toolbarLayout.visibility = View.GONE
|
||||
}
|
||||
R.id.nav_map_osm -> {
|
||||
this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
toolbar.visibility = View.GONE
|
||||
mainBinding.includeAppBar.toolbarLayout.visibility = View.GONE
|
||||
}
|
||||
else -> {
|
||||
this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
toolbar.visibility = View.VISIBLE
|
||||
mainBinding.includeAppBar.toolbarLayout.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.getGSP().observe(this, Observer { result ->
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
drawerBinding.drawerLatValue.text =
|
||||
String.format(getString(R.string.pat_location), result.data.latitude)
|
||||
drawerBinding.drawerLonValue.text =
|
||||
String.format(getString(R.string.pat_location), result.data.longitude)
|
||||
}
|
||||
is Result.Error -> {
|
||||
when (result.exception) {
|
||||
is SecurityException ->
|
||||
getString(R.string.err_no_permissions).toast(this)
|
||||
is IllegalArgumentException ->
|
||||
getString(R.string.update_loc_failure).toast(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
viewModel.getUpdateStatus().observe(this, Observer { result ->
|
||||
when (result) {
|
||||
is Result.Success -> getString(R.string.import_data_success).toast(this)
|
||||
is Result.Error -> getString(R.string.import_data_failure).toast(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupDrawer() {
|
||||
drawerBinding.drawerBtnLoc.setOnClickListener {
|
||||
viewModel.updatePosition()
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnTleFile.setOnClickListener {
|
||||
val openFileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "*/*"
|
||||
}
|
||||
startActivityForResult(openFileIntent, pickFileReqCode)
|
||||
mainBinding.drawerLayout.closeDrawers()
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnTleUrl.setOnClickListener {
|
||||
TleSourcesDialogFragment(viewModel.getTleSources()).apply {
|
||||
setSourcesListener(this@MainActivity)
|
||||
show(supportFragmentManager, "TleSourcesDialog")
|
||||
}
|
||||
mainBinding.drawerLayout.closeDrawers()
|
||||
it.lockButton()
|
||||
}
|
||||
drawerBinding.drawerBtnGithub.setOnClickListener {
|
||||
val gitHubUrl = "https://github.com/rt-bishop/LookingSat"
|
||||
val githubIntent = Intent(Intent.ACTION_VIEW, Uri.parse(gitHubUrl))
|
||||
startActivity(githubIntent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSourcesSubmit(list: List<TleSource>) {
|
||||
viewModel.updateSatData(list)
|
||||
}
|
||||
|
||||
private fun View.lockButton() {
|
||||
lifecycleScope.launch {
|
||||
this@lockButton.isEnabled = false
|
||||
delay(3000)
|
||||
this@lockButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasPermissions(context: Context, permissions: Array<String>): Boolean =
|
||||
permissions.all {
|
||||
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
val navController = findNavController(R.id.nav_host)
|
||||
return navController.navigateUp(appBarConfig) || super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == pickFileReqCode && resultCode == RESULT_OK) {
|
||||
data?.data?.also { uri ->
|
||||
viewModel.updateEntriesFromFile(uri)
|
||||
}
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.*
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.repo.Repository
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SharedViewModel @Inject constructor(
|
||||
private val prefsManager: PrefsManager,
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _satPassList = MutableLiveData<Result<MutableList<SatPass>>>()
|
||||
private val _updateStatus = MutableLiveData<Result<Int>>()
|
||||
private val _gsp = MutableLiveData<Result<GroundStationPosition>>().apply {
|
||||
value = Result.Success(prefsManager.getPosition())
|
||||
}
|
||||
private var calculationJob: Job? = null
|
||||
|
||||
fun getTransmittersForSat(id: Int) = liveData { emit(repository.getTransmittersByCatNum(id)) }
|
||||
fun getPassList(): LiveData<Result<MutableList<SatPass>>> = _satPassList
|
||||
fun getUpdateStatus(): LiveData<Result<Int>> = _updateStatus
|
||||
fun getGSP(): LiveData<Result<GroundStationPosition>> = _gsp
|
||||
|
||||
fun getCompass() = prefsManager.getCompass()
|
||||
fun getRefreshRate() = prefsManager.getRefreshRate()
|
||||
fun getHoursAhead() = prefsManager.getHoursAhead()
|
||||
fun getMinElevation() = prefsManager.getMinElevation()
|
||||
fun setPositionFromPref() = _gsp.postValue(Result.Success(prefsManager.getPosition()))
|
||||
suspend fun getAllEntries() = repository.getAllEntries()
|
||||
|
||||
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
||||
prefsManager.setHoursAhead(hoursAhead)
|
||||
prefsManager.setMinElevation(minEl)
|
||||
}
|
||||
|
||||
fun updatePosition() {
|
||||
val lastLoc = prefsManager.getLastKnownLocation()
|
||||
if (lastLoc == null) {
|
||||
_gsp.postValue(Result.Error(Exception()))
|
||||
} else {
|
||||
val gsp = GroundStationPosition(lastLoc.latitude, lastLoc.longitude, lastLoc.altitude)
|
||||
_gsp.postValue(Result.Success(gsp))
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEntriesFromFile(uri: Uri) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val selected = repository.getSelectedEntries().map { it.catNum }
|
||||
repository.updateEntriesFromFile(uri)
|
||||
repository.updateEntriesSelection(selected)
|
||||
_updateStatus.postValue(Result.Success(0))
|
||||
} catch (e: Exception) {
|
||||
_updateStatus.postValue(Result.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSatData(list: List<TleSource>) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val selected = repository.getSelectedEntries().map { it.catNum }
|
||||
repository.updateSources(list)
|
||||
repository.updateEntriesFromUrl(list)
|
||||
repository.updateTransmitters()
|
||||
repository.updateEntriesSelection(selected)
|
||||
_updateStatus.postValue(Result.Success(0))
|
||||
} catch (e: Exception) {
|
||||
_updateStatus.postValue(Result.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEntriesSelection(catNumList: MutableList<Int>) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.updateEntriesSelection(catNumList)
|
||||
calculatePasses()
|
||||
}
|
||||
}
|
||||
|
||||
fun calculatePasses() {
|
||||
_satPassList.postValue(Result.InProgress)
|
||||
calculationJob?.cancel()
|
||||
var passList = mutableListOf<SatPass>()
|
||||
val dateNow = Date()
|
||||
val gsp = prefsManager.getPosition()
|
||||
calculationJob = viewModelScope.launch(Dispatchers.Default) {
|
||||
repository.getSelectedEntries().forEach {
|
||||
passList.addAll(getPassesForEntries(it, dateNow, gsp))
|
||||
}
|
||||
passList = filterAndSortPasses(passList, dateNow, getHoursAhead())
|
||||
_satPassList.postValue(Result.Success(passList))
|
||||
}
|
||||
}
|
||||
|
||||
fun setDefaultTleSources() {
|
||||
if (prefsManager.isFirstLaunch()) {
|
||||
viewModelScope.launch {
|
||||
val defSourcesList = listOf(
|
||||
TleSource("https://celestrak.com/NORAD/elements/active.txt"),
|
||||
TleSource("https://amsat.org/tle/current/nasabare.txt")
|
||||
)
|
||||
repository.updateSources(defSourcesList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTleSources(): List<TleSource> = runBlocking {
|
||||
return@runBlocking repository.getSources()
|
||||
}
|
||||
|
||||
private fun getPassesForEntries(
|
||||
entry: SatEntry,
|
||||
dateNow: Date,
|
||||
gsp: GroundStationPosition
|
||||
): MutableList<SatPass> {
|
||||
val predictor = PassPredictor(entry.tle, gsp)
|
||||
val passes = predictor.getPasses(dateNow, getHoursAhead(), true)
|
||||
val passList = passes.map { SatPass(entry.tle, predictor, it) }
|
||||
return passList as MutableList<SatPass>
|
||||
}
|
||||
|
||||
private fun filterAndSortPasses(
|
||||
passes: MutableList<SatPass>,
|
||||
dateNow: Date,
|
||||
hoursAhead: Int
|
||||
): MutableList<SatPass> {
|
||||
val dateFuture = Calendar.getInstance().let {
|
||||
it.time = dateNow
|
||||
it.add(Calendar.HOUR, hoursAhead)
|
||||
it.time
|
||||
}
|
||||
passes.removeAll { it.pass.startTime.after(dateFuture) }
|
||||
passes.removeAll { it.pass.endTime.before(dateNow) }
|
||||
passes.removeAll { it.pass.maxEl < getMinElevation() }
|
||||
passes.sortBy { it.pass.startTime }
|
||||
return passes
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.databinding.ItemSatEntryBinding
|
||||
|
||||
class SatEntryAdapter(private var entries: MutableList<SatEntry>) :
|
||||
RecyclerView.Adapter<SatEntryAdapter.SatEntryHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatEntryHolder {
|
||||
val binding = ItemSatEntryBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return SatEntryHolder(binding.root, binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SatEntryHolder, position: Int) {
|
||||
holder.bind(entries[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return entries.size
|
||||
}
|
||||
|
||||
fun setEntries(list: MutableList<SatEntry>) {
|
||||
entries = list
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getEntries(): MutableList<SatEntry> {
|
||||
return entries
|
||||
}
|
||||
|
||||
inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(satEntry: SatEntry) {
|
||||
binding.satEntryCheckbox.text = satEntry.name
|
||||
binding.satEntryCheckbox.isChecked = satEntry.isSelected
|
||||
itemView.setOnClickListener {
|
||||
satEntry.isSelected = binding.satEntryCheckbox.isChecked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.ItemPassGeoBinding
|
||||
import com.rtbishop.look4sat.databinding.ItemPassLeoBinding
|
||||
import com.rtbishop.look4sat.ui.fragments.PassListFragmentDirections
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class SatPassAdapter(
|
||||
private var satPassList: MutableList<SatPass>,
|
||||
private val prefsManager: PrefsManager
|
||||
) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
fun setList(list: MutableList<SatPass>) {
|
||||
satPassList = list
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun updateRecycler() {
|
||||
val timeNow = Date()
|
||||
val iterator = satPassList.listIterator()
|
||||
while (iterator.hasNext()) {
|
||||
val satPass = iterator.next()
|
||||
if (satPass.progress < 100) {
|
||||
val timeStart = satPass.pass.startTime
|
||||
val timeEnd = satPass.pass.endTime
|
||||
if (timeNow.after(timeStart)) {
|
||||
satPass.active = true
|
||||
val index = satPassList.indexOf(satPass)
|
||||
val deltaTotal = timeEnd.time.minus(timeStart.time)
|
||||
val deltaNow = timeNow.time.minus(timeStart.time)
|
||||
satPass.progress = ((deltaNow.toFloat() / deltaTotal.toFloat()) * 100).toInt()
|
||||
notifyItemChanged(index)
|
||||
}
|
||||
} else {
|
||||
val index = satPassList.indexOf(satPass)
|
||||
iterator.remove()
|
||||
notifyItemRemoved(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return satPassList.size
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (satPassList[position].tle.isDeepspace) 1
|
||||
else 0
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return if (viewType == 0) {
|
||||
val bindingLeo = ItemPassLeoBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
SatPassLeoHolder(bindingLeo.root, bindingLeo)
|
||||
} else {
|
||||
val bindingGeo = ItemPassGeoBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
SatPassGeoHolder(bindingGeo.root, bindingGeo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder.itemViewType == 0) {
|
||||
(holder as SatPassLeoHolder).bind(satPassList[position])
|
||||
} else {
|
||||
(holder as SatPassGeoHolder).bind(satPassList[position])
|
||||
}
|
||||
}
|
||||
|
||||
inner class SatPassLeoHolder(itemView: View, private val binding: ItemPassLeoBinding) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(satPass: SatPass) {
|
||||
val context: Context = itemView.context
|
||||
if (satPass.active) binding.passLeoImg.setImageResource(R.drawable.ic_pass_active)
|
||||
else binding.passLeoImg.setImageResource(R.drawable.ic_pass_inactive)
|
||||
|
||||
binding.passLeoSatName.text = satPass.tle.name
|
||||
binding.passLeoSatId.text =
|
||||
String.format(context.getString(R.string.pass_satId), satPass.tle.catnum)
|
||||
binding.passLeoMaxEl.text =
|
||||
String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl)
|
||||
binding.passLeoAosAz.text =
|
||||
String.format(context.getString(R.string.pass_aos_az), satPass.pass.aosAzimuth)
|
||||
binding.passLeoLosAz.text =
|
||||
String.format(context.getString(R.string.pass_los_az), satPass.pass.losAzimuth)
|
||||
binding.passLeoProgress.progress = satPass.progress
|
||||
|
||||
val dateFormat =
|
||||
SimpleDateFormat(context.getString(R.string.pass_dateTime), Locale.getDefault())
|
||||
if (prefsManager.isTimeUTC()) dateFormat.timeZone = TimeZone.getTimeZone("UTC")
|
||||
binding.passLeoAosTime.text = dateFormat.format(satPass.pass.startTime)
|
||||
binding.passLeoLosTime.text = dateFormat.format(satPass.pass.endTime)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
val passIndex = satPassList.indexOf(satPass)
|
||||
val action = PassListFragmentDirections.actionPassToPolar(passIndex)
|
||||
itemView.findNavController().navigate(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class SatPassGeoHolder(itemView: View, private val binding: ItemPassGeoBinding) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(satPass: SatPass) {
|
||||
val context: Context = itemView.context
|
||||
val satPos = satPass.predictor.getSatPos(satPass.pass.startTime)
|
||||
val azimuth = satPos.azimuth * 180 / Math.PI
|
||||
|
||||
binding.passGeoName.text = satPass.tle.name
|
||||
binding.passGeoId.text =
|
||||
String.format(context.getString(R.string.pass_satId), satPass.tle.catnum)
|
||||
binding.passGeoAz.text = String.format(context.getString(R.string.pat_azimuth), azimuth)
|
||||
binding.passGeoEl.text =
|
||||
String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
val passIndex = satPassList.indexOf(satPass)
|
||||
val action = PassListFragmentDirections.actionPassToPolar(passIndex)
|
||||
itemView.findNavController().navigate(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.adapters
|
||||
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.databinding.ItemTleSourceBinding
|
||||
|
||||
class TleSourcesAdapter(private var sources: MutableList<TleSource>) :
|
||||
RecyclerView.Adapter<TleSourcesAdapter.TleSourceHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TleSourceHolder {
|
||||
val binding = ItemTleSourceBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return TleSourceHolder(binding.root, binding, TleSourceWatcher())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TleSourceHolder, position: Int) {
|
||||
holder.textWatcher.updatePosition(position)
|
||||
holder.bind(sources[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return sources.size
|
||||
}
|
||||
|
||||
fun getSources(): MutableList<TleSource> {
|
||||
return sources
|
||||
}
|
||||
|
||||
fun setSources(list: MutableList<TleSource>) {
|
||||
sources = list
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
inner class TleSourceHolder(
|
||||
itemView: View,
|
||||
val binding: ItemTleSourceBinding,
|
||||
val textWatcher: TleSourceWatcher
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(source: TleSource) {
|
||||
binding.tleSourceUrl.setText(source.url)
|
||||
binding.tleSourceUrl.addTextChangedListener(textWatcher)
|
||||
binding.tleSourceBtnDel.setOnClickListener {
|
||||
sources.remove(source)
|
||||
notifyItemRemoved(adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class TleSourceWatcher : TextWatcher {
|
||||
|
||||
private var position = 0
|
||||
|
||||
fun updatePosition(position: Int) {
|
||||
this.position = position
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
sources[position].url = s.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.Transmitter
|
||||
import com.rtbishop.look4sat.databinding.ItemTransmitterBinding
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
import java.util.*
|
||||
|
||||
class TransmitterAdapter : RecyclerView.Adapter<TransmitterAdapter.TransmitterHolder>() {
|
||||
|
||||
private var transmittersList = emptyList<Transmitter>()
|
||||
private lateinit var predictor: PassPredictor
|
||||
|
||||
fun setPredictor(predict: PassPredictor) {
|
||||
predictor = predict
|
||||
}
|
||||
|
||||
fun setList(list: List<Transmitter>) {
|
||||
transmittersList = list
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return transmittersList.size
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransmitterHolder {
|
||||
val binding = ItemTransmitterBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return TransmitterHolder(binding.root, binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TransmitterHolder, position: Int) {
|
||||
holder.bind(transmittersList[position])
|
||||
}
|
||||
|
||||
inner class TransmitterHolder(itemView: View, private val binding: ItemTransmitterBinding) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bind(transmitter: Transmitter) {
|
||||
val context: Context = itemView.context
|
||||
val freqDivider = 1000000f
|
||||
|
||||
binding.transDescription.text = transmitter.description
|
||||
|
||||
if (transmitter.downlinkLow != null && transmitter.downlinkHigh == null) {
|
||||
binding.transDownlink.text = String
|
||||
.format(
|
||||
context.getString(R.string.trans_down_low),
|
||||
transmitter.downlinkLow / freqDivider
|
||||
)
|
||||
binding.transDownlinkDoppler.text = String
|
||||
.format(
|
||||
context.getString(R.string.trans_down_low_doppler),
|
||||
predictor.getDownlinkFreq(transmitter.downlinkLow, Date()) / freqDivider
|
||||
)
|
||||
} else if (transmitter.downlinkLow != null && transmitter.downlinkHigh != null) {
|
||||
binding.transDownlink.text = String
|
||||
.format(
|
||||
context.getString(R.string.trans_down_lowHigh),
|
||||
transmitter.downlinkLow / freqDivider,
|
||||
transmitter.downlinkHigh / freqDivider
|
||||
)
|
||||
binding.transDownlinkDoppler.text = String
|
||||
.format(
|
||||
context.getString(R.string.trans_down_lowHigh_doppler),
|
||||
predictor.getDownlinkFreq(transmitter.downlinkLow, Date()) / freqDivider,
|
||||
predictor.getDownlinkFreq(transmitter.downlinkHigh, Date()) / freqDivider
|
||||
)
|
||||
} else {
|
||||
binding.transDownlink.text = context.getString(R.string.no_downlink)
|
||||
binding.transDownlinkDoppler.text = context.getString(R.string.no_downlink_doppler)
|
||||
}
|
||||
|
||||
if (transmitter.uplinkLow != null && transmitter.uplinkHigh == null) {
|
||||
binding.transUplink.text = String.format(
|
||||
context.getString(R.string.trans_up_low),
|
||||
transmitter.uplinkLow / freqDivider
|
||||
)
|
||||
binding.transUplinkDoppler.text = String.format(
|
||||
context.getString(R.string.trans_up_low_doppler),
|
||||
predictor.getUplinkFreq(transmitter.uplinkLow, Date()) / freqDivider
|
||||
)
|
||||
} else if (transmitter.uplinkLow != null && transmitter.uplinkHigh != null) {
|
||||
binding.transUplink.text = String.format(
|
||||
context.getString(R.string.trans_up_lowHigh),
|
||||
transmitter.uplinkLow / freqDivider,
|
||||
transmitter.uplinkHigh / freqDivider
|
||||
)
|
||||
binding.transUplinkDoppler.text = String.format(
|
||||
context.getString(R.string.trans_up_lowHigh_doppler),
|
||||
predictor.getUplinkFreq(transmitter.uplinkLow, Date()) / freqDivider,
|
||||
predictor.getUplinkFreq(transmitter.uplinkHigh, Date()) / freqDivider
|
||||
)
|
||||
} else {
|
||||
binding.transUplink.text = context.getString(R.string.no_uplink)
|
||||
binding.transUplinkDoppler.text = context.getString(R.string.no_uplink_doppler)
|
||||
}
|
||||
|
||||
if (transmitter.mode != null) {
|
||||
binding.transMode.text =
|
||||
String.format(context.getString(R.string.trans_mode), transmitter.mode)
|
||||
} else {
|
||||
binding.transMode.text = context.getString(R.string.no_mode)
|
||||
}
|
||||
if (transmitter.isInverted) {
|
||||
binding.transInverted.text = String.format(
|
||||
context.getString(R.string.trans_inverted),
|
||||
context.getString(R.string.btn_yes)
|
||||
)
|
||||
} else {
|
||||
binding.transInverted.text = String.format(
|
||||
context.getString(R.string.trans_inverted),
|
||||
context.getString(R.string.btn_no)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.rtbishop.look4sat.BuildConfig
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.databinding.FragmentAboutBinding
|
||||
|
||||
class AboutFragment : Fragment(R.layout.fragment_about) {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val binding = FragmentAboutBinding.bind(view)
|
||||
binding.tvAboutVersion.text =
|
||||
String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME)
|
||||
binding.tvAboutMessage.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatItem
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapOsmBinding
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.osmdroid.config.Configuration
|
||||
import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase
|
||||
import org.osmdroid.tileprovider.tilesource.TileSourcePolicy
|
||||
import org.osmdroid.tileprovider.tilesource.XYTileSource
|
||||
import org.osmdroid.util.BoundingBox
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.CustomZoomButtonsController
|
||||
import org.osmdroid.views.overlay.*
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class MapOsmFragment : Fragment(R.layout.fragment_map_osm) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var binding: FragmentMapOsmBinding
|
||||
private lateinit var trackPaint: Paint
|
||||
private lateinit var footprintPaint: Paint
|
||||
private lateinit var selectedPass: SatPass
|
||||
private val dateNow = Date(System.currentTimeMillis())
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentMapOsmBinding.bind(view)
|
||||
mainActivity = requireActivity() as MainActivity
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(mainActivity.applicationContext)
|
||||
Configuration.getInstance().load(mainActivity.applicationContext, prefs)
|
||||
|
||||
trackPaint = Paint().apply {
|
||||
strokeWidth = 2f
|
||||
style = Paint.Style.STROKE
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satTrack)
|
||||
strokeCap = Paint.Cap.ROUND
|
||||
strokeJoin = Paint.Join.ROUND
|
||||
isAntiAlias = true
|
||||
}
|
||||
|
||||
footprintPaint = Paint().apply {
|
||||
style = Paint.Style.FILL_AND_STROKE
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satOsmTemp)
|
||||
isAntiAlias = true
|
||||
}
|
||||
|
||||
setupMapView()
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
private fun setupMapView() {
|
||||
binding.mapView.apply {
|
||||
setMultiTouchControls(true)
|
||||
setTileSource(getWikimediaTileSource())
|
||||
minZoomLevel = 2.5
|
||||
maxZoomLevel = 6.0
|
||||
controller.setZoom(minZoomLevel)
|
||||
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||
isHorizontalMapRepetitionEnabled = false
|
||||
isVerticalMapRepetitionEnabled = false
|
||||
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
|
||||
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
|
||||
setScrollableAreaLimitDouble(BoundingBox(85.05, 180.0, -85.05, -180.0))
|
||||
|
||||
// apply filter
|
||||
val tilesFilter = getColorFilter(Color.parseColor("#D50000"))
|
||||
overlayManager.tilesOverlay.setColorFilter(tilesFilter)
|
||||
|
||||
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
|
||||
val layers = listOf(FolderOverlay(), FolderOverlay(), FolderOverlay(), FolderOverlay())
|
||||
overlays.addAll(layers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWikimediaTileSource(): OnlineTileSourceBase {
|
||||
return XYTileSource(
|
||||
"wikimedia",
|
||||
2,
|
||||
6,
|
||||
256,
|
||||
".png",
|
||||
arrayOf("https://maps.wikimedia.org/osm-intl/"),
|
||||
resources.getString(R.string.osmCopyright),
|
||||
TileSourcePolicy(
|
||||
1, TileSourcePolicy.FLAG_NO_BULK and TileSourcePolicy.FLAG_NO_PREVENTIVE and
|
||||
TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL and TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { stationPosition ->
|
||||
when (stationPosition) {
|
||||
is Result.Success -> {
|
||||
setupPosOverlay(stationPosition.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.getPassList().observe(viewLifecycleOwner, { satPasses ->
|
||||
when (satPasses) {
|
||||
is Result.Success -> {
|
||||
if (satPasses.data.isNotEmpty()) {
|
||||
val filteredPasses = satPasses.data.distinctBy { it.tle }
|
||||
selectedPass = filteredPasses[0]
|
||||
setupSatOverlay(filteredPasses)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupPosOverlay(gsp: GroundStationPosition) {
|
||||
Marker(binding.mapView).apply {
|
||||
setInfoWindow(null)
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
icon = ResourcesCompat.getDrawable(resources, R.drawable.ic_map_pos, mainActivity.theme)
|
||||
position = GeoPoint(gsp.latitude, gsp.longitude)
|
||||
binding.mapView.overlays[0] = this
|
||||
binding.mapView.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSatOverlay(passList: List<SatPass>) {
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
dateNow.time = System.currentTimeMillis()
|
||||
binding.mapView.overlays[3] = getSatIcons(passList)
|
||||
binding.mapView.overlays[2] = getSatFootprint(selectedPass)
|
||||
setSatInfo(selectedPass)
|
||||
binding.mapView.invalidate()
|
||||
delay(3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSatIcons(passList: List<SatPass>): Overlay =
|
||||
withContext(Dispatchers.Default) {
|
||||
val icon =
|
||||
ResourcesCompat.getDrawable(resources, R.drawable.ic_map_sat, mainActivity.theme)
|
||||
val items = mutableListOf<SatItem>()
|
||||
|
||||
passList.forEach {
|
||||
val satPos = it.predictor.getSatPos(dateNow)
|
||||
var lat = Math.toDegrees(satPos.latitude)
|
||||
var lon = Math.toDegrees(satPos.longitude)
|
||||
|
||||
if (lat > 85.05) lat = 85.05
|
||||
else if (lat < -85.05) lat = -85.05
|
||||
if (lon > 180.0) lon -= 360.0
|
||||
|
||||
SatItem(it.tle.name, it.tle.name, GeoPoint(lat, lon), it).apply {
|
||||
markerHotspot = OverlayItem.HotspotPlace.CENTER
|
||||
items.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
val listener = object : ItemizedIconOverlay.OnItemGestureListener<SatItem> {
|
||||
override fun onItemLongPress(index: Int, item: SatItem): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onItemSingleTapUp(index: Int, item: SatItem): Boolean {
|
||||
selectedPass = item.pass
|
||||
setSatDetails(item.pass)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return@withContext ItemizedIconOverlay(items, icon, listener, mainActivity)
|
||||
}
|
||||
|
||||
private fun setSatDetails(satPass: SatPass) {
|
||||
setSatInfo(satPass)
|
||||
binding.mapView.overlays[1] = getSatTrack(satPass)
|
||||
binding.mapView.overlays[2] = getSatFootprint(satPass)
|
||||
binding.mapView.invalidate()
|
||||
}
|
||||
|
||||
private fun setSatInfo(satPass: SatPass) {
|
||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||
val satLat = Math.toDegrees(satPos.latitude).toFloat()
|
||||
var satLon = Math.toDegrees(satPos.longitude).toFloat()
|
||||
if (satLon > 180f) satLon -= 360f
|
||||
|
||||
binding.idName.text =
|
||||
String.format(
|
||||
mainActivity.getString(R.string.pat_osm_idName),
|
||||
satPass.tle.catnum,
|
||||
satPass.tle.name
|
||||
)
|
||||
binding.altitude.text =
|
||||
String.format(mainActivity.getString(R.string.pat_altitude), satPos.altitude)
|
||||
binding.distance.text =
|
||||
String.format(mainActivity.getString(R.string.pat_distance), satPos.range)
|
||||
binding.velocity.text =
|
||||
String.format(
|
||||
mainActivity.getString(R.string.pat_osm_vel),
|
||||
getSatVelocity(satPos.altitude)
|
||||
)
|
||||
binding.latLon.text =
|
||||
String.format(mainActivity.getString(R.string.pat_osm_latLon), satLat, satLon)
|
||||
}
|
||||
|
||||
private fun getSatVelocity(satAlt: Double): Double {
|
||||
val earthG = 6.674 * 10.0.pow(-11)
|
||||
val earthM = 5.98 * 10.0.pow(24)
|
||||
val radius = 6.37 * 10.0.pow(6) + satAlt * 10.0.pow(3)
|
||||
return sqrt(earthG * earthM / radius) / 1000
|
||||
}
|
||||
|
||||
private fun getSatTrack(pass: SatPass): Overlay {
|
||||
val period = (24 * 60 / pass.tle.meanmo).toInt()
|
||||
val positions = pass.predictor.getPositions(dateNow, 20, 0, period * 3)
|
||||
val trackOverlay = FolderOverlay()
|
||||
val trackPoints = mutableListOf<GeoPoint>()
|
||||
|
||||
var oldLon = 0.0
|
||||
positions.forEach {
|
||||
val newLat = Math.toDegrees(it.latitude)
|
||||
var newLon = Math.toDegrees(it.longitude)
|
||||
if (newLon > 180.0) newLon -= 360.0
|
||||
if (oldLon < -170.0 && newLon > 170.0 || oldLon > 170.0 && newLon < -170.0) {
|
||||
val currentPoints = mutableListOf<GeoPoint>()
|
||||
currentPoints.addAll(trackPoints)
|
||||
Polyline().apply {
|
||||
outlinePaint.set(trackPaint)
|
||||
setPoints(currentPoints)
|
||||
trackOverlay.add(this)
|
||||
}
|
||||
trackPoints.clear()
|
||||
}
|
||||
oldLon = newLon
|
||||
trackPoints.add(GeoPoint(newLat, newLon))
|
||||
}
|
||||
|
||||
Polyline().apply {
|
||||
outlinePaint.set(trackPaint)
|
||||
setPoints(trackPoints)
|
||||
trackOverlay.add(this)
|
||||
}
|
||||
|
||||
return trackOverlay
|
||||
}
|
||||
|
||||
private fun getSatFootprint(pass: SatPass): Overlay {
|
||||
val rangeCircle = pass.predictor.getSatPos(dateNow).rangeCircle
|
||||
val rangePoints = mutableListOf<GeoPoint>()
|
||||
var zeroPoint = GeoPoint(0.0, 0.0)
|
||||
|
||||
rangeCircle.withIndex().forEach {
|
||||
var lat = it.value.lat
|
||||
var lon = it.value.lon
|
||||
|
||||
if (lat > 85.05) lat = 85.05
|
||||
else if (lat < -85.05) lat = -85.05
|
||||
if (lon > 180.0) lon -= 360.0
|
||||
|
||||
if (it.index == 0) zeroPoint = GeoPoint(lat, lon)
|
||||
rangePoints.add(GeoPoint(lat, lon))
|
||||
}
|
||||
rangePoints.add(zeroPoint)
|
||||
|
||||
return Polygon().apply {
|
||||
fillPaint.set(footprintPaint)
|
||||
outlinePaint.set(footprintPaint)
|
||||
points = rangePoints
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColorFilter(targetColor: Int): ColorMatrixColorFilter {
|
||||
val newR = Color.red(targetColor) / 255f
|
||||
val newG = Color.green(targetColor) / 255f
|
||||
val newB = Color.blue(targetColor) / 255f
|
||||
|
||||
val negativeMatrix = ColorMatrix(
|
||||
floatArrayOf(
|
||||
-1f, 0f, 0f, 0f, 255f,
|
||||
0f, -1f, 0f, 0f, 255f,
|
||||
0f, 0f, -1f, 0f, 255f,
|
||||
0f, 0f, 0f, 1f, 0f
|
||||
)
|
||||
)
|
||||
|
||||
val tintedMatrix = ColorMatrix(
|
||||
floatArrayOf(
|
||||
newR, newG, newB, 0f, 0f,
|
||||
newR, newG, newB, 0f, 0f,
|
||||
newR, newG, newB, 0f, 0f,
|
||||
0f, 0f, 0f, 0f, 255f
|
||||
)
|
||||
)
|
||||
|
||||
tintedMatrix.preConcat(negativeMatrix)
|
||||
return ColorMatrixColorFilter(tintedMatrix)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
binding.mapView.onPause()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.mapView.onResume()
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapViewBinding
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.views.MapView
|
||||
import com.rtbishop.look4sat.utility.Extensions.toast
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var predictor: PassPredictor
|
||||
private lateinit var selectedSat: TLE
|
||||
private lateinit var binding: FragmentMapViewBinding
|
||||
private var gsp = GroundStationPosition(0.0, 0.0, 0.0)
|
||||
private var satPassList = emptyList<SatPass>()
|
||||
private var checkedItem = 0
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentMapViewBinding.bind(view)
|
||||
mainActivity = requireActivity() as MainActivity
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
setupObservers(binding)
|
||||
}
|
||||
|
||||
private fun setupObservers(binding: FragmentMapViewBinding) {
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { result ->
|
||||
when (result) {
|
||||
is Result.Success -> gsp = result.data
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.getPassList().observe(viewLifecycleOwner, { result ->
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
satPassList = result.data
|
||||
setupMapView(binding)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupMapView(binding: FragmentMapViewBinding) {
|
||||
if (satPassList.isNotEmpty()) {
|
||||
satPassList = satPassList.distinctBy { it.tle }
|
||||
satPassList = satPassList.sortedBy { it.tle.name }
|
||||
binding.fabMap.setOnClickListener { showSelectSatDialog(satPassList) }
|
||||
selectedSat = satPassList.first().tle
|
||||
predictor = satPassList.first().predictor
|
||||
mapView = MapView(mainActivity, gsp)
|
||||
mapView.setList(satPassList)
|
||||
mapView.setChecked(checkedItem)
|
||||
binding.frameMap.addView(mapView)
|
||||
refreshView()
|
||||
} else {
|
||||
binding.fabMap.setOnClickListener {
|
||||
getString(R.string.err_no_sat_selected).toast(mainActivity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshView() {
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
mapView.invalidate()
|
||||
setDataToTextViews()
|
||||
delay(viewModel.getRefreshRate())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectSatDialog(list: List<SatPass>) {
|
||||
val tleArray = arrayOfNulls<String>(list.size).apply {
|
||||
list.withIndex().forEach {
|
||||
this[it.index] = it.value.tle.name
|
||||
}
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(mainActivity)
|
||||
builder.setTitle(getString(R.string.dialog_show_track))
|
||||
.setSingleChoiceItems(tleArray, checkedItem) { dialog, which ->
|
||||
checkedItem = which
|
||||
selectedSat = list[which].tle
|
||||
predictor = list[which].predictor
|
||||
mapView.setChecked(checkedItem)
|
||||
mapView.invalidate()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun setDataToTextViews() {
|
||||
val currentTime = Date(System.currentTimeMillis())
|
||||
val position = predictor.getSatPos(currentTime)
|
||||
var lon = Math.toDegrees(position.longitude).toFloat()
|
||||
val lat = Math.toDegrees(position.latitude).toFloat()
|
||||
val rng = position.range
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
binding.tvMapLat.text = String.format(mainActivity.getString(R.string.pat_latitude), lat)
|
||||
binding.tvMapLon.text = String.format(mainActivity.getString(R.string.pat_longitude), lon)
|
||||
binding.tvMapRng.text = String.format(mainActivity.getString(R.string.pat_distance), rng)
|
||||
}
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentPassListBinding
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.adapters.SatPassAdapter
|
||||
import com.rtbishop.look4sat.utility.Extensions.toast
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class PassListFragment : Fragment(R.layout.fragment_pass_list) {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var satPassAdapter: SatPassAdapter
|
||||
private lateinit var btnPassPrefs: ImageButton
|
||||
private lateinit var aosTimer: CountDownTimer
|
||||
private lateinit var aosTimerText: TextView
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private var isTimerSet: Boolean = false
|
||||
private var satPassList: MutableList<SatPass> = mutableListOf()
|
||||
|
||||
private var _binding: FragmentPassListBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentPassListBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mainActivity = activity as MainActivity
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
satPassAdapter = SatPassAdapter(satPassList, prefsManager)
|
||||
aosTimerText = mainActivity.findViewById(R.id.toolbar_timer)
|
||||
btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter)
|
||||
|
||||
setupObservers(binding)
|
||||
setupComponents(binding)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (satPassAdapter.itemCount == 0) {
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers(binding: FragmentPassListBinding) {
|
||||
viewModel.getPassList().observe(viewLifecycleOwner, { result ->
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
satPassList = result.data
|
||||
satPassAdapter.setList(satPassList)
|
||||
if (satPassList.isNotEmpty()) {
|
||||
binding.layoutInfo.visibility = View.INVISIBLE
|
||||
binding.recPassList.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.layoutInfo.visibility = View.VISIBLE
|
||||
binding.recPassList.visibility = View.INVISIBLE
|
||||
}
|
||||
setTimer()
|
||||
binding.refLayoutPassList.isRefreshing = false
|
||||
}
|
||||
is Result.InProgress -> {
|
||||
binding.refLayoutPassList.isRefreshing = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupComponents(binding: FragmentPassListBinding) {
|
||||
binding.recPassList.apply {
|
||||
layoutManager = LinearLayoutManager(mainActivity)
|
||||
adapter = satPassAdapter
|
||||
isVerticalScrollBarEnabled = false
|
||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
satPassAdapter.setList(satPassList)
|
||||
setTimer()
|
||||
|
||||
binding.refLayoutPassList.setProgressBackgroundColorSchemeResource(R.color.themeAccent)
|
||||
binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark)
|
||||
binding.refLayoutPassList.setOnRefreshListener { viewModel.calculatePasses() }
|
||||
btnPassPrefs.setOnClickListener {
|
||||
showSatPassPrefsDialog(viewModel.getHoursAhead(), viewModel.getMinElevation())
|
||||
}
|
||||
binding.fabSatSelect.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
val list = viewModel.getAllEntries() as MutableList
|
||||
if (list.isEmpty()) {
|
||||
getString(R.string.err_update_data).toast(mainActivity, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
showSelectSatDialog(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSatPassPrefsDialog(hoursAhead: Int, minEl: Double) {
|
||||
val satPassPrefView = View.inflate(mainActivity, R.layout.dialog_pass_pref, null)
|
||||
val etHoursAhead = satPassPrefView.findViewById<EditText>(R.id.pref_et_hoursAhead)
|
||||
val etMinEl = satPassPrefView.findViewById<EditText>(R.id.pref_et_minEl)
|
||||
etHoursAhead.setText(hoursAhead.toString())
|
||||
etMinEl.setText(minEl.toString())
|
||||
|
||||
AlertDialog.Builder(mainActivity).apply {
|
||||
setPositiveButton(getString(android.R.string.ok)) { _, _ ->
|
||||
val hoursStr = etHoursAhead.text.toString()
|
||||
val elevationStr = etMinEl.text.toString()
|
||||
if (hoursStr.isNotEmpty() && elevationStr.isNotEmpty()) {
|
||||
val hours = hoursStr.toInt()
|
||||
val elevation = elevationStr.toDouble()
|
||||
when {
|
||||
hours < 1 || hours > 168 -> {
|
||||
getString(R.string.pref_hours_ahead_input_error).toast(
|
||||
mainActivity,
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
elevation < 0 || elevation > 90 -> {
|
||||
getString(R.string.pref_min_el_input_error).toast(
|
||||
mainActivity,
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
viewModel.setPassPrefs(hours, elevation)
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
}
|
||||
} else getString(R.string.err_enter_value).toast(mainActivity, Toast.LENGTH_SHORT)
|
||||
|
||||
}
|
||||
setNegativeButton(getString(android.R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
setView(satPassPrefView)
|
||||
create()
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectSatDialog(tleMainList: MutableList<SatEntry>) {
|
||||
val listener = object : SatEntryDialogFragment.EntriesSubmitListener {
|
||||
override fun onEntriesSubmit(catNumList: MutableList<Int>) {
|
||||
viewModel.updateEntriesSelection(catNumList)
|
||||
}
|
||||
}
|
||||
|
||||
SatEntryDialogFragment(tleMainList).apply {
|
||||
setEntriesListener(listener)
|
||||
show(mainActivity.supportFragmentManager, "SatEntryDialogFragment")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTimer() {
|
||||
if (satPassList.isNotEmpty()) {
|
||||
resetTimer()
|
||||
val timeNow = Date()
|
||||
try {
|
||||
setTimerForNext(timeNow)
|
||||
} catch (e: NoSuchElementException) {
|
||||
setTimerForLast(timeNow)
|
||||
} finally {
|
||||
aosTimer.start()
|
||||
isTimerSet = true
|
||||
}
|
||||
} else {
|
||||
resetTimer(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTimerForNext(timeNow: Date) {
|
||||
val nextPass = satPassList.first { it.pass.startTime.after(timeNow) }
|
||||
val millisBeforeStart = nextPass.pass.startTime.time.minus(timeNow.time)
|
||||
aosTimer = object : CountDownTimer(millisBeforeStart, 1000) {
|
||||
override fun onFinish() {
|
||||
setTimer()
|
||||
}
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
aosTimerText.text = String.format(
|
||||
mainActivity.getString(R.string.pat_timer),
|
||||
TimeUnit.MILLISECONDS.toHours(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
|
||||
)
|
||||
satPassAdapter.updateRecycler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTimerForLast(timeNow: Date) {
|
||||
val lastPass = satPassList.last()
|
||||
val millisBeforeEnd = lastPass.pass.endTime.time.minus(timeNow.time)
|
||||
aosTimer = object : CountDownTimer(millisBeforeEnd, 1000) {
|
||||
override fun onFinish() {
|
||||
viewModel.calculatePasses()
|
||||
}
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
aosTimerText.text = String.format(
|
||||
mainActivity.getString(R.string.pat_timer),
|
||||
TimeUnit.MILLISECONDS.toHours(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
|
||||
)
|
||||
satPassAdapter.updateRecycler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetTimer(resetToNull: Boolean = false) {
|
||||
if (isTimerSet) {
|
||||
aosTimer.cancel()
|
||||
isTimerSet = false
|
||||
}
|
||||
if (resetToNull) aosTimerText.text =
|
||||
String.format(getString(R.string.pat_timer), 0, 0, 0)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.*
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.dagger.ViewModelFactory
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentPolarViewBinding
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.adapters.TransmitterAdapter
|
||||
import com.rtbishop.look4sat.ui.views.PolarView
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.round
|
||||
|
||||
class PolarViewFragment : Fragment(R.layout.fragment_polar_view), SensorEventListener {
|
||||
|
||||
@Inject
|
||||
lateinit var modelFactory: ViewModelFactory
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var binding: FragmentPolarViewBinding
|
||||
private lateinit var satPass: SatPass
|
||||
private lateinit var sensorManager: SensorManager
|
||||
private var polarView: PolarView? = null
|
||||
private val args: PolarViewFragmentArgs by navArgs()
|
||||
private val transmitterAdapter = TransmitterAdapter()
|
||||
private var magneticDeclination = 0f
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mainActivity = activity as MainActivity
|
||||
binding = FragmentPolarViewBinding.bind(view)
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
sensorManager = mainActivity.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||
binding.recPolar.apply {
|
||||
layoutManager = LinearLayoutManager(mainActivity)
|
||||
adapter = transmitterAdapter
|
||||
}
|
||||
observePasses()
|
||||
observeStationPosition()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (viewModel.getCompass()) {
|
||||
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
|
||||
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (viewModel.getCompass()) {
|
||||
sensorManager.unregisterListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||
|
||||
override fun onSensorChanged(event: SensorEvent?) {
|
||||
event?.let { calculateAzimuth(it) }
|
||||
}
|
||||
|
||||
private fun calculateAzimuth(event: SensorEvent) {
|
||||
val rotationValues = FloatArray(9)
|
||||
SensorManager.getRotationMatrixFromVector(rotationValues, event.values)
|
||||
val orientationValues = FloatArray(3)
|
||||
SensorManager.getOrientation(rotationValues, orientationValues)
|
||||
val magneticAzimuth = ((orientationValues[0] * 57.2957795f) + 360f) % 360f
|
||||
val roundedAzimuth = round(magneticAzimuth * 100) / 100
|
||||
polarView?.rotation = -(roundedAzimuth + magneticDeclination)
|
||||
}
|
||||
|
||||
private fun observePasses() {
|
||||
viewModel.getPassList().observe(viewLifecycleOwner, { result ->
|
||||
if (result is Result.Success) {
|
||||
val refreshRate = viewModel.getRefreshRate()
|
||||
satPass = result.data[args.satPassIndex]
|
||||
mainActivity.supportActionBar?.title = satPass.tle.name
|
||||
polarView = PolarView(mainActivity, satPass)
|
||||
binding.framePolar.addView(polarView)
|
||||
observeTransmitters()
|
||||
refreshText(refreshRate)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun observeTransmitters() {
|
||||
viewModel.getTransmittersForSat(satPass.tle.catnum).observe(viewLifecycleOwner, {
|
||||
if (it.isNotEmpty()) {
|
||||
transmitterAdapter.setPredictor(satPass.predictor)
|
||||
transmitterAdapter.setList(it)
|
||||
transmitterAdapter.notifyDataSetChanged()
|
||||
binding.recPolar.visibility = View.VISIBLE
|
||||
binding.tvPolarNoTrans.visibility = View.INVISIBLE
|
||||
} else {
|
||||
binding.recPolar.visibility = View.INVISIBLE
|
||||
binding.tvPolarNoTrans.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun observeStationPosition() {
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { result ->
|
||||
if (result is Result.Success) {
|
||||
val geoField = GeomagneticField(
|
||||
result.data.latitude.toFloat(),
|
||||
result.data.longitude.toFloat(),
|
||||
result.data.heightAMSL.toFloat(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
magneticDeclination = geoField.declination
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun refreshText(rate: Long) {
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
setPassText()
|
||||
polarView?.invalidate()
|
||||
transmitterAdapter.notifyDataSetChanged()
|
||||
delay(rate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPassText() {
|
||||
val satPos = satPass.predictor.getSatPos(Date())
|
||||
val polarAz = mainActivity.getString(R.string.pat_azimuth)
|
||||
val polarEl = mainActivity.getString(R.string.pat_elevation)
|
||||
val polarRng = mainActivity.getString(R.string.pat_distance)
|
||||
val polarAlt = mainActivity.getString(R.string.pat_altitude)
|
||||
binding.tvPolarAz.text = String.format(polarAz, Math.toDegrees(satPos.azimuth))
|
||||
binding.tvPolarEl.text = String.format(polarEl, Math.toDegrees(satPos.elevation))
|
||||
binding.tvPolarRng.text = String.format(polarRng, satPos.range)
|
||||
binding.tvPolarAlt.text = String.format(polarAlt, satPos.altitude)
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.utility.Extensions.toast
|
||||
|
||||
class PreferencesFragment : PreferenceFragmentCompat(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var viewModel: SharedViewModel
|
||||
private lateinit var keyLat: String
|
||||
private lateinit var keyLon: String
|
||||
private lateinit var keyAlt: String
|
||||
private lateinit var keyDelay: String
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preference, rootKey)
|
||||
val provider = EditTextPreference.SimpleSummaryProvider.getInstance()
|
||||
|
||||
mainActivity = activity as MainActivity
|
||||
viewModel = ViewModelProvider(mainActivity).get(SharedViewModel::class.java)
|
||||
|
||||
keyLat = mainActivity.getString(R.string.pref_lat_key)
|
||||
keyLon = mainActivity.getString(R.string.pref_lon_key)
|
||||
keyAlt = mainActivity.getString(R.string.pref_alt_key)
|
||||
keyDelay = mainActivity.getString(R.string.pref_refresh_rate_key)
|
||||
|
||||
findPreference<EditTextPreference>(keyLat)?.apply {
|
||||
summaryProvider = provider
|
||||
setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_NUMBER or
|
||||
InputType.TYPE_NUMBER_FLAG_DECIMAL or
|
||||
InputType.TYPE_NUMBER_FLAG_SIGNED
|
||||
}
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val valueStr = newValue.toString()
|
||||
if (valueStr.isEmpty() || valueStr == "-" || valueStr.toDouble() < -90.0 || valueStr.toDouble() > 90.0) {
|
||||
getString(R.string.pref_lat_input_error).toast(mainActivity)
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<EditTextPreference>(keyLon)?.apply {
|
||||
summaryProvider = provider
|
||||
setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_NUMBER or
|
||||
InputType.TYPE_NUMBER_FLAG_DECIMAL or
|
||||
InputType.TYPE_NUMBER_FLAG_SIGNED
|
||||
}
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val valueStr = newValue.toString()
|
||||
if (valueStr.isEmpty() || valueStr == "-" || valueStr.toDouble() < -180.0 || valueStr.toDouble() > 180.0) {
|
||||
getString(R.string.pref_lon_input_error).toast(mainActivity)
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<EditTextPreference>(keyAlt)?.apply {
|
||||
summaryProvider = provider
|
||||
setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_NUMBER or
|
||||
InputType.TYPE_NUMBER_FLAG_DECIMAL or
|
||||
InputType.TYPE_NUMBER_FLAG_SIGNED
|
||||
}
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val valueStr = newValue.toString()
|
||||
if (valueStr.isEmpty() || valueStr == "-" || valueStr.toDouble() < -413.0 || valueStr.toDouble() > 8850.0) {
|
||||
getString(R.string.pref_alt_input_error).toast(mainActivity)
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<EditTextPreference>(keyDelay)?.apply {
|
||||
summaryProvider = provider
|
||||
setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER }
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val valueStr = newValue.toString()
|
||||
if (valueStr.isEmpty() || valueStr.toLong() < 250 || valueStr.toLong() > 10000) {
|
||||
getString(R.string.pref_refresh_rate_input_error).toast(mainActivity)
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == keyLat || key == keyLon || key == keyAlt) viewModel.setPositionFromPref()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.SearchView
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.databinding.DialogSatEntryBinding
|
||||
import com.rtbishop.look4sat.ui.adapters.SatEntryAdapter
|
||||
import java.util.*
|
||||
|
||||
class SatEntryDialogFragment(private var entries: MutableList<SatEntry>) :
|
||||
AppCompatDialogFragment(), SearchView.OnQueryTextListener {
|
||||
|
||||
private lateinit var entriesListener: EntriesSubmitListener
|
||||
private val entryAdapter = SatEntryAdapter(entries)
|
||||
private var selectAllToggle = true
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogSatEntryBinding.inflate(requireActivity().layoutInflater)
|
||||
val satEntryDialog = Dialog(requireActivity()).apply {
|
||||
window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(binding.root)
|
||||
window?.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
binding.dialogSearch.apply {
|
||||
setOnQueryTextListener(this@SatEntryDialogFragment)
|
||||
onActionViewExpanded()
|
||||
clearFocus()
|
||||
}
|
||||
|
||||
binding.dialogRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(activity)
|
||||
adapter = entryAdapter
|
||||
}
|
||||
|
||||
binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() }
|
||||
binding.dialogBtnNegative.setOnClickListener { onNegativeClicked() }
|
||||
binding.dialogBtnNeutral.setOnClickListener { onNeutralClicked() }
|
||||
|
||||
return satEntryDialog
|
||||
}
|
||||
|
||||
fun setEntriesListener(listener: EntriesSubmitListener): SatEntryDialogFragment {
|
||||
entriesListener = listener
|
||||
return this
|
||||
}
|
||||
|
||||
private fun filterEntries(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||
if (query.isEmpty()) return list
|
||||
return try {
|
||||
filterByCatNum(list, query.toInt())
|
||||
} catch (e: NumberFormatException) {
|
||||
filterByName(list, query)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterByCatNum(list: MutableList<SatEntry>, catNum: Int): MutableList<SatEntry> {
|
||||
val filteredList = list.filter { it.catNum == catNum }
|
||||
return filteredList as MutableList<SatEntry>
|
||||
}
|
||||
|
||||
private fun filterByName(list: MutableList<SatEntry>, query: String): MutableList<SatEntry> {
|
||||
val searchQuery = query.toLowerCase(Locale.getDefault())
|
||||
val filteredList = mutableListOf<SatEntry>()
|
||||
list.forEach {
|
||||
val name = it.name.toLowerCase(Locale.getDefault())
|
||||
if (name.contains(searchQuery)) filteredList.add(it)
|
||||
}
|
||||
return filteredList
|
||||
}
|
||||
|
||||
private fun onPositiveClicked() {
|
||||
val catNumList = mutableListOf<Int>().apply {
|
||||
entries.forEach { if (it.isSelected) this.add(it.catNum) }
|
||||
}
|
||||
entriesListener.onEntriesSubmit(catNumList)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun onNegativeClicked() {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private fun onNeutralClicked() {
|
||||
selectAllToggle = if (selectAllToggle) {
|
||||
val currentList = entryAdapter.getEntries()
|
||||
currentList.forEach { it.isSelected = true }
|
||||
entryAdapter.setEntries(currentList)
|
||||
false
|
||||
} else {
|
||||
val currentList = entryAdapter.getEntries()
|
||||
currentList.forEach { it.isSelected = false }
|
||||
entryAdapter.setEntries(currentList)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
val filteredList = filterEntries(entries, newText)
|
||||
entryAdapter.setEntries(filteredList)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
interface EntriesSubmitListener {
|
||||
fun onEntriesSubmit(catNumList: MutableList<Int>)
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.databinding.DialogTleSourcesBinding
|
||||
import com.rtbishop.look4sat.ui.adapters.TleSourcesAdapter
|
||||
|
||||
class TleSourcesDialogFragment(sources: List<TleSource>) :
|
||||
AppCompatDialogFragment() {
|
||||
|
||||
private lateinit var sourcesListener: SourcesSubmitListener
|
||||
private val emptySource = TleSource("")
|
||||
private val sourcesAdapter = TleSourcesAdapter(sources.toMutableList())
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogTleSourcesBinding.inflate(requireActivity().layoutInflater)
|
||||
val tleSourcesDialog = Dialog(requireActivity()).apply {
|
||||
window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(binding.root)
|
||||
window?.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
binding.tleSourcesRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(activity)
|
||||
adapter = sourcesAdapter
|
||||
}
|
||||
|
||||
binding.tleSourceBtnAdd.setOnClickListener {
|
||||
val tempSources = sourcesAdapter.getSources()
|
||||
tempSources.add(emptySource)
|
||||
sourcesAdapter.setSources(tempSources)
|
||||
sourcesAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
binding.tleSourcesBtnNeg.setOnClickListener { dismiss() }
|
||||
binding.tleSourcesBtnPos.setOnClickListener {
|
||||
val filteredSources = sourcesAdapter.getSources()
|
||||
.filter { it.url != String() && it.url != " " && it.url.contains("https://") }
|
||||
sourcesListener.onSourcesSubmit(filteredSources)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
return tleSourcesDialog
|
||||
}
|
||||
|
||||
fun setSourcesListener(listener: SourcesSubmitListener): TleSourcesDialogFragment {
|
||||
sourcesListener = listener
|
||||
return this
|
||||
}
|
||||
|
||||
interface SourcesSubmitListener {
|
||||
fun onSourcesSubmit(list: List<TleSource>)
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package com.rtbishop.look4sat.ui.views
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.github.amsacode.predict4java.SatPos
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
class MapView(context: Context) : View(context) {
|
||||
|
||||
constructor(context: Context, groundStationPosition: GroundStationPosition) : this(context) {
|
||||
gsp = groundStationPosition
|
||||
}
|
||||
|
||||
private lateinit var passList: List<SatPass>
|
||||
private lateinit var gsp: GroundStationPosition
|
||||
private lateinit var selectedSat: TLE
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val groundTrackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintPrim = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satPrimary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintSec = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satSecondary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satPrimary)
|
||||
style = Paint.Style.FILL
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
setShadowLayer(2f, 2f, 2f, Color.BLACK)
|
||||
}
|
||||
private val outlinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = Color.BLACK
|
||||
style = Paint.Style.FILL_AND_STROKE
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
}
|
||||
private val rect = Rect()
|
||||
private var checked = 0
|
||||
private var degLon = 0f
|
||||
private var degLat = 0f
|
||||
|
||||
fun setList(satPassList: List<SatPass>) {
|
||||
passList = satPassList
|
||||
}
|
||||
|
||||
fun setChecked(item: Int) {
|
||||
checked = item
|
||||
selectedSat = passList[checked].tle
|
||||
}
|
||||
|
||||
@SuppressLint("DrawAllocation")
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
degLon = width / 360f
|
||||
degLat = height / 180f
|
||||
canvas.translate(width / 2f, height / 2f)
|
||||
drawHomeLoc(canvas)
|
||||
val currentTime = Date(System.currentTimeMillis())
|
||||
val orbitalPeriod = (24 * 60 / selectedSat.meanmo).toInt()
|
||||
val predictor = passList[checked].predictor
|
||||
val positions = predictor.getPositions(currentTime, 60, 0, orbitalPeriod * 3)
|
||||
drawGroundTrack(canvas, positions)
|
||||
passList.forEach { satPass -> drawSat(canvas, satPass, currentTime, satPaintSec) }
|
||||
drawSat(canvas, passList[checked], currentTime, satPaintPrim)
|
||||
}
|
||||
|
||||
private fun drawHomeLoc(canvas: Canvas) {
|
||||
val lon = gsp.longitude.toFloat()
|
||||
val lat = gsp.latitude.toFloat() * -1
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
val gspName = context.getString(R.string.map_gsp)
|
||||
txtPaint.getTextBounds(gspName, 0, gspName.length, rect)
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
|
||||
}
|
||||
|
||||
private fun drawGroundTrack(canvas: Canvas, list: List<SatPos>) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, satPos) ->
|
||||
lon = Math.toDegrees(satPos.longitude).toFloat()
|
||||
lat = Math.toDegrees(satPos.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, groundTrackPaint)
|
||||
}
|
||||
|
||||
private fun drawSat(canvas: Canvas, satPass: SatPass, date: Date, paint: Paint) {
|
||||
val tle = satPass.tle
|
||||
val predictor = satPass.predictor
|
||||
val satPosNow = predictor.getSatPos(date)
|
||||
val footprintPosList = satPosNow.rangeCircle
|
||||
drawFootprint(canvas, footprintPosList, paint)
|
||||
drawName(canvas, satPosNow, tle.name)
|
||||
}
|
||||
|
||||
private fun drawFootprint(canvas: Canvas, list: List<Position>, paint: Paint) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, position) ->
|
||||
lon = position.lon.toFloat()
|
||||
lat = position.lat.toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
}
|
||||
|
||||
private fun drawName(canvas: Canvas, position: SatPos, name: String) {
|
||||
var lon = Math.toDegrees(position.longitude).toFloat()
|
||||
val lat = Math.toDegrees(position.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
txtPaint.getTextBounds(name, 0, name.length, rect)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.rtbishop.look4sat.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Path
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import java.util.*
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class PolarView(context: Context) : View(context) {
|
||||
|
||||
constructor(context: Context, satPass: SatPass) : this(context) {
|
||||
pass = satPass
|
||||
}
|
||||
|
||||
private lateinit var pass: SatPass
|
||||
private val polarWidth = resources.displayMetrics.widthPixels
|
||||
private val polarCenter = polarWidth / 2f
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val radius = polarWidth * 0.49f
|
||||
private val txtSize = scale * 15
|
||||
private val path: Path = Path()
|
||||
private var azimuth = 0f
|
||||
|
||||
private val radarPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.themeLight)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.themeAccent)
|
||||
textSize = txtSize
|
||||
}
|
||||
private val trackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.themeAccent)
|
||||
style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
canvas.rotate(-azimuth, polarCenter, polarCenter)
|
||||
canvas.translate(polarCenter, polarCenter)
|
||||
drawRadarView(canvas)
|
||||
drawRadarText(canvas)
|
||||
if (!pass.tle.isDeepspace) {
|
||||
drawPassTrajectory(canvas, pass)
|
||||
}
|
||||
drawSatellite(canvas, pass)
|
||||
}
|
||||
|
||||
private fun drawRadarView(cvs: Canvas) {
|
||||
cvs.drawLine(-radius, 0f, radius, 0f, radarPaint)
|
||||
cvs.drawLine(0f, -radius, 0f, radius, radarPaint)
|
||||
cvs.drawCircle(0f, 0f, radius, radarPaint)
|
||||
cvs.drawCircle(0f, 0f, (radius / 3) * 2, radarPaint)
|
||||
cvs.drawCircle(0f, 0f, radius / 3, radarPaint)
|
||||
}
|
||||
|
||||
private fun drawRadarText(cvs: Canvas) {
|
||||
cvs.drawText("N", scale, -radius + txtSize - scale * 2, txtPaint)
|
||||
cvs.drawText("30°", scale, -((radius / 3) * 2) - scale * 2, txtPaint)
|
||||
cvs.drawText("60°", scale, -(radius / 3) - scale * 2, txtPaint)
|
||||
cvs.drawText("90°", scale, -scale * 2, txtPaint)
|
||||
}
|
||||
|
||||
private fun drawPassTrajectory(cvs: Canvas, satPass: SatPass) {
|
||||
val startTime = satPass.pass.startTime
|
||||
val endTime = satPass.pass.endTime
|
||||
while (startTime.before(endTime)) {
|
||||
val satPos = satPass.predictor.getSatPos(startTime)
|
||||
val x = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||
val y = sph2CartY(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||
if (startTime.compareTo(satPass.pass.startTime) == 0) {
|
||||
path.moveTo(x, -y)
|
||||
} else {
|
||||
path.lineTo(x, -y)
|
||||
}
|
||||
startTime.time += 15000
|
||||
}
|
||||
cvs.drawPath(path, trackPaint)
|
||||
}
|
||||
|
||||
private fun drawSatellite(cvs: Canvas, satPass: SatPass) {
|
||||
val date = Date(System.currentTimeMillis())
|
||||
val satPos = satPass.predictor.getSatPos(date)
|
||||
if (satPos.elevation > 0) {
|
||||
val x = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||
val y = sph2CartY(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||
cvs.drawCircle(x, -y, txtSize / 3, satPaint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sph2CartX(azimuth: Double, elevation: Double, r: Double): Float {
|
||||
val piDiv2 = Math.PI / 2.0
|
||||
val radius = r * (piDiv2 - elevation) / piDiv2
|
||||
return (radius * cos(piDiv2 - azimuth)).toFloat()
|
||||
}
|
||||
|
||||
private fun sph2CartY(azimuth: Double, elevation: Double, r: Double): Float {
|
||||
val piDiv2 = Math.PI / 2.0
|
||||
val radius = r * (piDiv2 - elevation) / piDiv2
|
||||
return (radius * sin(piDiv2 - azimuth)).toFloat()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.google.gson.Gson
|
||||
|
||||
class Converters {
|
||||
private val gSon = Gson()
|
||||
|
||||
@TypeConverter
|
||||
fun tleToString(tle: TLE): String {
|
||||
return gSon.toJson(tle)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun tleFromString(string: String): TLE {
|
||||
return gSon.fromJson(string, TLE::class.java)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
|
||||
object Extensions {
|
||||
|
||||
fun String.toast(context: Context, duration: Int = Toast.LENGTH_SHORT): Toast {
|
||||
return Toast.makeText(context, this, duration).apply { show() }
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
/**
|
||||
* predict4java: An SDP4 / SGP4 library for satellite orbit predictions
|
||||
*
|
||||
* Copyright (C) 2004-2010 David A. B. Johnson, G4DPZ.
|
||||
*
|
||||
* This class is a Java port of one of the core elements of
|
||||
* the Predict program, Copyright John A. Magliacane,
|
||||
* KD2BD 1991-2003: http://www.qsl.net/kd2bd/predict.html
|
||||
*
|
||||
* Dr. T.S. Kelso is the author of the SGP4/SDP4 orbital models,
|
||||
* originally written in Fortran and Pascal, and released into the
|
||||
* public domain through his website (http://www.celestrak.com/).
|
||||
* Neoklis Kyriazis, 5B4AZ, later re-wrote Dr. Kelso's code in C,
|
||||
* and released it under the GNU GPL in 2002.
|
||||
* PREDICT's core is based on 5B4AZ's code translation efforts.
|
||||
*
|
||||
* Author: David A. B. Johnson, G4DPZ <dave></dave>@g4dpz.me.uk>
|
||||
*
|
||||
* Comments, questions and bugreports should be submitted via
|
||||
* http://sourceforge.net/projects/websat/
|
||||
* More details can be found at the project home page:
|
||||
*
|
||||
* http://websat.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, visit http://www.fsf.org/
|
||||
*/
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import com.github.amsacode.predict4java.*
|
||||
import java.util.*
|
||||
|
||||
class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition) {
|
||||
private val sat: Satellite = SatelliteFactory.createSatellite(tle)
|
||||
private val south = "south"
|
||||
private val north = "north"
|
||||
private val deadSpotNone = "none"
|
||||
private val speedOfLight = 2.99792458E8
|
||||
private val twoPi = Math.PI * 2.0
|
||||
private val timeZone: TimeZone = TimeZone.getTimeZone("UTC")
|
||||
private var iterationCount = 0
|
||||
|
||||
fun getDownlinkFreq(freq: Long, date: Date): Long {
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
val rangeRate = satPos.rangeRate
|
||||
return (freq.toDouble() * (speedOfLight - rangeRate * 1000.0) / speedOfLight).toLong()
|
||||
}
|
||||
|
||||
fun getUplinkFreq(freq: Long, date: Date): Long {
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
val rangeRate = satPos.rangeRate
|
||||
return (freq.toDouble() * (speedOfLight + rangeRate * 1000.0) / speedOfLight).toLong()
|
||||
}
|
||||
|
||||
fun getSatPos(time: Date): SatPos {
|
||||
iterationCount++
|
||||
return sat.getPosition(qth, time)
|
||||
}
|
||||
|
||||
fun getPositions(
|
||||
referenceDate: Date,
|
||||
incrementSeconds: Int,
|
||||
minutesBefore: Int,
|
||||
minutesAfter: Int
|
||||
): List<SatPos> {
|
||||
val positions: MutableList<SatPos> = ArrayList()
|
||||
val endDateDate = Date(referenceDate.time + minutesAfter * 60L * 1000L)
|
||||
var trackDate = Date(referenceDate.time - minutesBefore * 60L * 1000L)
|
||||
|
||||
while (trackDate.before(endDateDate)) {
|
||||
positions.add(getSatPos(trackDate))
|
||||
trackDate = Date(trackDate.time + incrementSeconds * 1000)
|
||||
}
|
||||
|
||||
return positions
|
||||
}
|
||||
|
||||
fun getPasses(start: Date, hoursAhead: Int, windBack: Boolean): List<SatPassTime> {
|
||||
iterationCount = 0
|
||||
|
||||
val satellite = SatelliteFactory.createSatellite(tle)
|
||||
val passes: MutableList<SatPassTime> = ArrayList()
|
||||
val trackEndDate = Date(start.time + hoursAhead * 60L * 60L * 1000L)
|
||||
var trackStartDate = start
|
||||
var windBackTime = windBack
|
||||
var lastAOS: Date
|
||||
var count = 0
|
||||
|
||||
if (satellite.willBeSeen(qth)) {
|
||||
if (tle.isDeepspace) passes.add(nextGeoSatPass(start))
|
||||
else {
|
||||
do {
|
||||
if (count > 0) windBackTime = false
|
||||
val pass = nextSatPass(trackStartDate, windBackTime)
|
||||
lastAOS = pass.startTime
|
||||
passes.add(pass)
|
||||
trackStartDate =
|
||||
Date(pass.endTime.time + threeQuarterOrbitMinutes() * 60L * 1000L)
|
||||
count++
|
||||
} while (lastAOS < trackEndDate)
|
||||
}
|
||||
}
|
||||
|
||||
return passes
|
||||
}
|
||||
|
||||
private fun nextGeoSatPass(date: Date): SatPassTime {
|
||||
val aosAzimuth: Int
|
||||
val losAzimuth: Int
|
||||
val tca: Date
|
||||
val polePassed: String
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
|
||||
aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
tca = satPos.time
|
||||
polePassed = getPolePassed(satPos, satPos)
|
||||
|
||||
cal.add(Calendar.HOUR, -12)
|
||||
val startDate = cal.time
|
||||
cal.add(Calendar.HOUR, 24)
|
||||
val endDate = cal.time
|
||||
|
||||
return SatPassTime(
|
||||
startDate, endDate, tca, polePassed, aosAzimuth,
|
||||
losAzimuth, satPos.elevation / (2.0 * Math.PI) * 360.0
|
||||
)
|
||||
}
|
||||
|
||||
private fun nextSatPass(date: Date, windBack: Boolean = false): SatPassTime {
|
||||
val aosAzimuth: Int
|
||||
val losAzimuth: Int
|
||||
var maxElevation = 0.0
|
||||
var elevation: Double
|
||||
var prevPos: SatPos
|
||||
var polePassed = deadSpotNone
|
||||
|
||||
// get the current position
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
|
||||
// wind back time 1/4 of an orbit
|
||||
if (windBack) {
|
||||
val meanMotion = tle.meanmo
|
||||
cal.add(Calendar.MINUTE, (-24.0 * 60.0 / meanMotion / 4.0).toInt())
|
||||
}
|
||||
var satPos = getSatPos(cal.time)
|
||||
|
||||
// test for the elevation being above the horizon
|
||||
if (satPos.elevation > 0.0) {
|
||||
// move time forward in 30 second intervals until the sat goes below the horizon
|
||||
do {
|
||||
satPos = getPosition(cal, 60)
|
||||
} while (satPos.elevation > 0.0)
|
||||
// move time forward 3/4 orbit
|
||||
cal.add(Calendar.MINUTE, threeQuarterOrbitMinutes())
|
||||
}
|
||||
|
||||
// now find the next time it comes above the horizon
|
||||
do {
|
||||
satPos = getPosition(cal, 60)
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
}
|
||||
} while (satPos.elevation < 0.0)
|
||||
|
||||
// refine it to 5 seconds
|
||||
cal.add(Calendar.SECOND, -60)
|
||||
do {
|
||||
satPos = getPosition(cal, 5)
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
}
|
||||
prevPos = satPos
|
||||
} while (satPos.elevation < 0.0)
|
||||
val startDate = satPos.time
|
||||
aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
|
||||
// now find when it goes below
|
||||
do {
|
||||
satPos = getPosition(cal, 30)
|
||||
val currPolePassed = getPolePassed(prevPos, satPos)
|
||||
if (currPolePassed != deadSpotNone) {
|
||||
polePassed = currPolePassed
|
||||
}
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
}
|
||||
prevPos = satPos
|
||||
} while (satPos.elevation > 0.0)
|
||||
|
||||
// refine it to 5 seconds
|
||||
cal.add(Calendar.SECOND, -30)
|
||||
do {
|
||||
satPos = getPosition(cal, 5)
|
||||
elevation = satPos.elevation
|
||||
if (elevation > maxElevation) {
|
||||
maxElevation = elevation
|
||||
}
|
||||
} while (satPos.elevation > 0.0)
|
||||
|
||||
val endDate = satPos.time
|
||||
losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
val tca = Date(startDate.time + (endDate.time - startDate.time) / 2)
|
||||
|
||||
return SatPassTime(
|
||||
startDate, endDate, tca, polePassed, aosAzimuth,
|
||||
losAzimuth, maxElevation / (2.0 * Math.PI) * 360.0
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPosition(cal: Calendar, offSet: Int): SatPos {
|
||||
cal.add(Calendar.SECOND, offSet)
|
||||
return getSatPos(cal.time)
|
||||
}
|
||||
|
||||
private fun getPolePassed(prevPos: SatPos, satPos: SatPos): String {
|
||||
var polePassed = deadSpotNone
|
||||
val az1 = prevPos.azimuth / twoPi * 360.0
|
||||
val az2 = satPos.azimuth / twoPi * 360.0
|
||||
if (az1 > az2) {
|
||||
// we may be moving from 350 or greater through north
|
||||
if (az1 > 350 && az2 < 10) polePassed = north
|
||||
else {
|
||||
// we may be moving from 190 or greater through south
|
||||
if (az1 > 180 && az2 < 180) polePassed = south
|
||||
}
|
||||
} else {
|
||||
// we may be moving from 10 or less through north
|
||||
if (az1 < 10 && az2 > 350) polePassed = north
|
||||
else {
|
||||
// we may be moving from 170 or more through south
|
||||
if (az1 < 180 && az2 > 180) polePassed = south
|
||||
}
|
||||
}
|
||||
return polePassed
|
||||
}
|
||||
|
||||
private fun threeQuarterOrbitMinutes(): Int {
|
||||
return (24.0 * 60.0 / tle.meanmo * 0.75).toInt()
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
* Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.rtbishop.look4sat.utility
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import androidx.core.content.edit
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import javax.inject.Inject
|
||||
|
||||
class PrefsManager @Inject constructor(
|
||||
private val preferences: SharedPreferences,
|
||||
private val locationManager: LocationManager
|
||||
) {
|
||||
private val keyHoursAhead = "hoursAhead"
|
||||
private val keyMinElevation = "minEl"
|
||||
private val keyLatitude = "latitude"
|
||||
private val keyLongitude = "longitude"
|
||||
private val keyAltitude = "altitude"
|
||||
private val keyRefreshRate = "rate"
|
||||
private val keyCompass = "compass"
|
||||
private val keyTimeUtc = "timeUTC"
|
||||
private val defaultHoursAhead = 8
|
||||
private val defaultMinEl = 16.0
|
||||
private val defaultRefreshRate = "3000"
|
||||
private val defaultGSP = "0.0"
|
||||
|
||||
fun isFirstLaunch(): Boolean {
|
||||
val keyIsFirstLaunch = "keyIsFirstLaunch"
|
||||
val isFirstLaunch = preferences.getBoolean(keyIsFirstLaunch, true)
|
||||
return if (isFirstLaunch) {
|
||||
preferences.edit {
|
||||
putBoolean(keyIsFirstLaunch, false)
|
||||
apply()
|
||||
}
|
||||
true
|
||||
} else isFirstLaunch
|
||||
}
|
||||
|
||||
fun isTimeUTC(): Boolean {
|
||||
return preferences.getBoolean(keyTimeUtc, false)
|
||||
}
|
||||
|
||||
fun getHoursAhead(): Int {
|
||||
return preferences.getInt(keyHoursAhead, defaultHoursAhead)
|
||||
}
|
||||
|
||||
fun getMinElevation(): Double {
|
||||
return preferences.getDouble(keyMinElevation, defaultMinEl)
|
||||
}
|
||||
|
||||
fun getRefreshRate(): Long {
|
||||
return preferences.getString(keyRefreshRate, defaultRefreshRate)!!.toLong()
|
||||
}
|
||||
|
||||
fun getCompass(): Boolean {
|
||||
return preferences.getBoolean(keyCompass, true)
|
||||
}
|
||||
|
||||
fun getPosition(): GroundStationPosition {
|
||||
val lat = preferences.getString(keyLatitude, defaultGSP)!!.toDouble()
|
||||
val lon = preferences.getString(keyLongitude, defaultGSP)!!.toDouble()
|
||||
val alt = preferences.getString(keyAltitude, defaultGSP)!!.toDouble()
|
||||
return GroundStationPosition(lat, lon, alt)
|
||||
}
|
||||
|
||||
fun getLastKnownLocation(): Location? {
|
||||
val provPassive = LocationManager.PASSIVE_PROVIDER
|
||||
return try {
|
||||
val location = locationManager.getLastKnownLocation(provPassive)
|
||||
location?.let {
|
||||
preferences.edit {
|
||||
putString(keyLatitude, location.latitude.toString())
|
||||
putString(keyLongitude, location.longitude.toString())
|
||||
putString(keyAltitude, location.altitude.toString())
|
||||
apply()
|
||||
}
|
||||
}
|
||||
location
|
||||
} catch (e: SecurityException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun setHoursAhead(hours: Int) {
|
||||
preferences.edit {
|
||||
putInt(keyHoursAhead, hours)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun setMinElevation(minEl: Double) {
|
||||
preferences.edit {
|
||||
putDouble(keyMinElevation, minEl)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
|
||||
putLong(key, double.toRawBits())
|
||||
}
|
||||
|
||||
private fun SharedPreferences.getDouble(key: String, default: Double): Double {
|
||||
return Double.fromBits(getLong(key, default.toRawBits()))
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB |
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/backgroundMapText" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#C0C0C0"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#C0C0C0"
|
||||
android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z" />
|
||||
</vector>
|
||||
@@ -1,7 +0,0 @@
|
||||
<vector android:height="24dp" android:viewportHeight="100"
|
||||
android:viewportWidth="100" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFE082" android:pathData="M63.5,45.5c-2.485,0 -4.5,2.015 -4.5,4.5c0,2.485 2.015,4.5 4.5,4.5S68,52.485 68,50C68,47.515 65.985,45.5 63.5,45.5L63.5,45.5z"/>
|
||||
<path android:fillColor="#FFE082" android:pathData="M54.5,23c14.888,0 27,12.112 27,27s-12.112,27 -27,27s-27,-12.112 -27,-27S39.612,23 54.5,23M54.5,18.5C37.103,18.5 23,32.603 23,50s14.103,31.5 31.5,31.5S86,67.397 86,50S71.897,18.5 54.5,18.5L54.5,18.5z"/>
|
||||
<path android:fillColor="#FFE082" android:pathData="M50,9.5c22.332,0 40.5,18.168 40.5,40.5S72.332,90.5 50,90.5S9.5,72.332 9.5,50S27.668,9.5 50,9.5M50,5C25.147,5 5,25.147 5,50s20.147,45 45,45s45,-20.147 45,-45S74.853,5 50,5L50,5z"/>
|
||||
<path android:fillColor="#FFE082" android:pathData="M59,36.5c7.444,0 13.5,6.056 13.5,13.5c0,7.444 -6.056,13.5 -13.5,13.5c-7.444,0 -13.5,-6.056 -13.5,-13.5C45.5,42.556 51.556,36.5 59,36.5M59,32c-9.941,0 -18,8.059 -18,18s8.059,18 18,18s18,-8.059 18,-18S68.941,32 59,32L59,32z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/themeIcon"
|
||||
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#C0C0C0"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z" />
|
||||
</vector>
|
||||
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeIcon"
|
||||
android:pathData="M12,0.297c-6.63,0 -12,5.373 -12,12 0,5.303 3.438,9.8 8.205,11.385 0.6,0.113 0.82,-0.258 0.82,-0.577 0,-0.285 -0.01,-1.04 -0.015,-2.04 -3.338,0.724 -4.042,-1.61 -4.042,-1.61C4.422,18.07 3.633,17.7 3.633,17.7c-1.087,-0.744 0.084,-0.729 0.084,-0.729 1.205,0.084 1.838,1.236 1.838,1.236 1.07,1.835 2.809,1.305 3.495,0.998 0.108,-0.776 0.417,-1.305 0.76,-1.605 -2.665,-0.3 -5.466,-1.332 -5.466,-5.93 0,-1.31 0.465,-2.38 1.235,-3.22 -0.135,-0.303 -0.54,-1.523 0.105,-3.176 0,0 1.005,-0.322 3.3,1.23 0.96,-0.267 1.98,-0.399 3,-0.405 1.02,0.006 2.04,0.138 3,0.405 2.28,-1.552 3.285,-1.23 3.285,-1.23 0.645,1.653 0.24,2.873 0.12,3.176 0.765,0.84 1.23,1.91 1.23,3.22 0,4.61 -2.805,5.625 -5.475,5.92 0.42,0.36 0.81,1.096 0.81,2.22 0,1.606 -0.015,2.896 -0.015,3.286 0,0.315 0.21,0.69 0.825,0.57C20.565,22.092 24,17.592 24,12.297c0,-6.627 -5.373,-12 -12,-12"
|
||||
tools:ignore="VectorPath" />
|
||||
</vector>
|
||||
@@ -1,27 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="270"
|
||||
android:endColor="#181818"
|
||||
android:startColor="@color/backgroundDark"
|
||||
android:type="linear" />
|
||||
</shape>
|
||||
@@ -1,41 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="271.2439"
|
||||
android:viewportHeight="271.2439">
|
||||
<group
|
||||
android:translateX="1.3562195"
|
||||
android:translateY="1.3562195">
|
||||
<group
|
||||
android:translateX="70.26573"
|
||||
android:translateY="70.26573">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="m96.642,31.504c7.911,7.997 17.143,13.584 25.365,15.581l1.754,-3.997C123.78,43.048 123.786,43.005 123.802,42.965 125.834,38.995 127,34.495 127,29.715 127,13.881 114.379,1 98.867,1c-5.125,0 -9.92,1.429 -14.064,3.884l-3.398,1.598c0.08,0.306 0.133,0.599 0.221,0.91 2.32,8.104 7.652,16.667 15.016,24.112z" />
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M93.876,34.3C86.053,26.391 80.369,17.225 77.87,8.49 77.84,8.385 77.818,8.285 77.788,8.181L2.629,43.513c-1.404,0.66 -2.019,2.358 -1.372,3.791 0.472,1.046 1.485,1.663 2.545,1.663 0.392,0 0.79,-0.084 1.169,-0.263L74.045,16.235c-1.873,3.578 -2.997,7.611 -3.228,11.885L35.566,51.732c-1.294,0.866 -1.653,2.638 -0.805,3.957 0.538,0.836 1.431,1.29 2.344,1.29 0.526,0 1.06,-0.151 1.533,-0.469L71.189,34.707c1.4,8.11 6.135,15.044 12.715,19.285l-54.945,68.337c-0.981,1.22 -0.808,3.021 0.388,4.023 0.521,0.437 1.149,0.649 1.775,0.649 0.809,0 1.611,-0.357 2.166,-1.045L89.056,56.595c3.06,1.168 6.357,1.838 9.811,1.838 4.932,0 9.566,-1.312 13.601,-3.597L84.602,118.323c-0.633,1.44 0,3.131 1.41,3.777 0.372,0.17 0.76,0.25 1.144,0.25 1.07,0 2.092,-0.629 2.556,-1.691L120.402,50.739C111.642,48.416 102.042,42.555 93.876,34.3Z"
|
||||
tools:ignore="VectorPath" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="@color/themeAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeAccent"
|
||||
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="@color/themeAccent"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeAccent"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
|
||||
</vector>
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m105.138,13.879a2.864,2.864 90,0 1,1.701 0.85l19.334,19.331a2.864,2.864 90,0 1,-0 4.027l-26.584,26.625a2.864,2.864 90,0 1,-1.835 0.805l-7.922,0.626 5.773,5.772a2.864,2.864 90,0 1,-0 4.027l-19.602,19.644a2.864,2.864 90,0 1,-4.073 0l-5.773,-5.772 -0.627,7.92a2.864,2.864 90,0 1,-0.805 1.835l-26.629,26.58a2.864,2.864 90,0 1,-4.073 0l-19.289,-19.286a2.864,2.864 90,0 1,-0 -4.072l26.584,-26.625a2.864,2.864 90,0 1,1.835 -0.805l7.922,-0.626 -5.773,-5.772a2.864,2.864 90,0 1,-0 -4.072l19.603,-19.599a2.864,2.864 90,0 1,4.073 0l5.773,5.772 0.626,-7.92a2.864,2.864 90,0 1,0.806 -1.835l26.629,-26.58a2.864,2.864 90,0 1,2.059 -0.85,2.864 2.864,90 0,1 0.269,0zM104.825,20.77 L80.97,44.62 80.165,55.315 85.58,60.729 96.276,59.879 120.13,36.074zM55.326,80.15 L44.629,81 20.775,104.806 36.081,120.109 59.891,96.259 60.741,85.564z"
|
||||
android:strokeColor="#00000000"
|
||||
tools:ignore="VectorPath" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,12.194a2.864,2.864 90,1 1,-0 5.727c-11.457,0 -22.876,4.351 -31.634,13.107 -8.741,8.74 -13.095,20.174 -13.095,31.614a2.864,2.864 90,1 1,-5.728 0c-0,-12.897 4.935,-25.829 14.773,-35.664 9.85,-9.848 22.772,-14.785 35.684,-14.785z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,1a2.864,2.864 90,1 1,-0 5.727c-14.325,0 -28.612,5.441 -39.547,16.375 -10.935,10.933 -16.378,25.233 -16.378,39.541a2.864,2.864 90,1 1,-5.728 0c-0,-15.763 6.025,-31.562 18.055,-43.59 12.029,-12.028 27.818,-18.052 43.597,-18.052z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,23.302a2.864,2.864 90,1 1,-0 5.727c-8.62,0 -17.201,3.263 -23.778,9.839 -6.577,6.576 -9.855,15.174 -9.855,23.774a2.864,2.864 90,1 1,-5.728 0c-0,-10.061 3.861,-20.153 11.533,-27.824 7.672,-7.671 17.756,-11.517 27.829,-11.517z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,34.525a2.864,2.864 90,1 1,-0 5.727c-5.737,0 -11.453,2.174 -15.836,6.557 -4.384,4.383 -6.558,10.098 -6.558,15.834a2.864,2.864 90,1 1,-5.728 0c-0,-7.192 2.757,-14.406 8.236,-19.883 5.479,-5.478 12.693,-8.234 19.887,-8.234z"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m22.862,13.879a2.864,2.864 90,0 0,-1.701 0.85l-19.334,19.331a2.864,2.864 90,0 0,0 4.027l26.584,26.625a2.864,2.864 90,0 0,1.835 0.805l7.922,0.626 -5.773,5.772a2.864,2.864 90,0 0,0 4.027l19.602,19.644a2.864,2.864 90,0 0,4.073 0l5.773,-5.772 0.627,7.92a2.864,2.864 90,0 0,0.805 1.835l26.629,26.58a2.864,2.864 90,0 0,4.073 0l19.289,-19.286a2.864,2.864 90,0 0,0 -4.072l-26.584,-26.625a2.864,2.864 90,0 0,-1.835 -0.805l-7.922,-0.626 5.773,-5.772a2.864,2.864 90,0 0,0 -4.072l-19.603,-19.599a2.864,2.864 90,0 0,-4.073 0l-5.773,5.772 -0.626,-7.92a2.864,2.864 90,0 0,-0.806 -1.835l-26.629,-26.58a2.864,2.864 90,0 0,-2.059 -0.85,2.864 2.864,90 0,0 -0.269,0zM23.175,20.77 L47.03,44.62 47.835,55.315 42.42,60.729 31.724,59.879 7.87,36.074zM72.674,80.15 L83.371,81 107.225,104.806 91.919,120.109 68.109,96.259 67.259,85.564z"
|
||||
android:strokeColor="#00000000"
|
||||
tools:ignore="VectorPath" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m65.347,12.194a2.864,2.864 90,1 0,0 5.727c11.457,0 22.876,4.351 31.634,13.107 8.741,8.74 13.095,20.174 13.095,31.614a2.864,2.864 90,1 0,5.728 0c0,-12.897 -4.935,-25.829 -14.773,-35.664 -9.85,-9.848 -22.772,-14.785 -35.684,-14.785z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m65.347,1a2.864,2.864 90,1 0,0 5.727c14.325,0 28.612,5.441 39.547,16.375 10.935,10.933 16.378,25.233 16.378,39.541a2.864,2.864 90,1 0,5.728 0c0,-15.763 -6.025,-31.562 -18.055,-43.59 -12.029,-12.028 -27.818,-18.052 -43.597,-18.052z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m65.347,23.302a2.864,2.864 90,1 0,0 5.727c8.62,0 17.201,3.263 23.778,9.839 6.577,6.576 9.855,15.174 9.855,23.774a2.864,2.864 90,1 0,5.728 0c0,-10.061 -3.861,-20.153 -11.533,-27.824 -7.672,-7.671 -17.756,-11.517 -27.829,-11.517z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m65.347,34.525a2.864,2.864 90,1 0,0 5.727c5.737,0 11.453,2.174 15.836,6.557 4.384,4.383 6.558,10.098 6.558,15.834a2.864,2.864 90,1 0,5.728 0c0,-7.192 -2.757,-14.406 -8.236,-19.883 -5.479,-5.478 -12.693,-8.234 -19.887,-8.234z"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#C0C0C0"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m105.138,114.121a2.864,2.864 90,0 0,1.701 -0.85l19.334,-19.331a2.864,2.864 90,0 0,-0 -4.027l-26.584,-26.625a2.864,2.864 90,0 0,-1.835 -0.805l-7.922,-0.626 5.773,-5.772a2.864,2.864 90,0 0,-0 -4.027l-19.602,-19.644a2.864,2.864 90,0 0,-4.073 -0l-5.773,5.772 -0.627,-7.92a2.864,2.864 90,0 0,-0.805 -1.835l-26.629,-26.58a2.864,2.864 90,0 0,-4.073 -0l-19.289,19.286a2.864,2.864 90,0 0,-0 4.072l26.584,26.625a2.864,2.864 90,0 0,1.835 0.805l7.922,0.626 -5.773,5.772a2.864,2.864 90,0 0,-0 4.072l19.603,19.599a2.864,2.864 90,0 0,4.073 -0l5.773,-5.772 0.626,7.92a2.864,2.864 90,0 0,0.806 1.835l26.629,26.58a2.864,2.864 90,0 0,2.059 0.85,2.864 2.864,90 0,0 0.269,-0zM104.825,107.23 L80.97,83.38 80.165,72.685 85.58,67.271 96.276,68.121 120.13,91.926zM55.326,47.85 L44.629,47 20.775,23.194 36.081,7.891 59.891,31.741 60.741,42.436z"
|
||||
android:strokeColor="#00000000"
|
||||
tools:ignore="VectorPath" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FFE082"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,115.806a2.864,2.864 90,1 0,-0 -5.727c-11.457,-0 -22.876,-4.351 -31.634,-13.107 -8.741,-8.74 -13.095,-20.174 -13.095,-31.614a2.864,2.864 90,1 0,-5.728 -0c-0,12.897 4.935,25.829 14.773,35.664 9.85,9.848 22.772,14.785 35.684,14.785z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FFE082"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,127a2.864,2.864 90,1 0,-0 -5.727c-14.325,-0 -28.612,-5.441 -39.547,-16.375 -10.935,-10.933 -16.378,-25.233 -16.378,-39.541a2.864,2.864 90,1 0,-5.728 -0c-0,15.763 6.025,31.562 18.055,43.59 12.029,12.028 27.818,18.052 43.597,18.052z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FFE082"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,104.698a2.864,2.864 90,1 0,-0 -5.727c-8.62,-0 -17.201,-3.263 -23.778,-9.839 -6.577,-6.576 -9.855,-15.174 -9.855,-23.774a2.864,2.864 90,1 0,-5.728 -0c-0,10.061 3.861,20.153 11.533,27.824 7.672,7.671 17.756,11.517 27.829,11.517z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#FFE082"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="m62.653,93.475a2.864,2.864 90,1 0,-0 -5.727c-5.737,-0 -11.453,-2.174 -15.836,-6.557 -4.384,-4.383 -6.558,-10.098 -6.558,-15.834a2.864,2.864 90,1 0,-5.728 -0c-0,7.192 2.757,14.406 8.236,19.883 5.479,5.478 12.693,8.234 19.887,8.234z"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" />
|
||||
</vector>
|
||||
@@ -1,33 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="m96.642,31.504c7.911,7.997 17.143,13.584 25.365,15.581l1.754,-3.997C123.78,43.048 123.786,43.005 123.802,42.965 125.834,38.995 127,34.495 127,29.715 127,13.881 114.379,1 98.867,1c-5.125,0 -9.92,1.429 -14.064,3.884l-3.398,1.598c0.08,0.306 0.133,0.599 0.221,0.91 2.32,8.104 7.652,16.667 15.016,24.112z" />
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M93.876,34.3C86.053,26.391 80.369,17.225 77.87,8.49 77.84,8.385 77.818,8.285 77.788,8.181L2.629,43.513c-1.404,0.66 -2.019,2.358 -1.372,3.791 0.472,1.046 1.485,1.663 2.545,1.663 0.392,0 0.79,-0.084 1.169,-0.263L74.045,16.235c-1.873,3.578 -2.997,7.611 -3.228,11.885L35.566,51.732c-1.294,0.866 -1.653,2.638 -0.805,3.957 0.538,0.836 1.431,1.29 2.344,1.29 0.526,0 1.06,-0.151 1.533,-0.469L71.189,34.707c1.4,8.11 6.135,15.044 12.715,19.285l-54.945,68.337c-0.981,1.22 -0.808,3.021 0.388,4.023 0.521,0.437 1.149,0.649 1.775,0.649 0.809,0 1.611,-0.357 2.166,-1.045L89.056,56.595c3.06,1.168 6.357,1.838 9.811,1.838 4.932,0 9.566,-1.312 13.601,-3.597L84.602,118.323c-0.633,1.44 0,3.131 1.41,3.777 0.372,0.17 0.76,0.25 1.144,0.25 1.07,0 2.092,-0.629 2.556,-1.691L120.402,50.739C111.642,48.416 102.042,42.555 93.876,34.3Z"
|
||||
tools:ignore="VectorPath" />
|
||||
</vector>
|
||||
@@ -1,31 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M6.18,17.82m-2.18,0a2.18,2.18 0,1 1,4.36 0a2.18,2.18 0,1 1,-4.36 0" />
|
||||
<path
|
||||
android:fillColor="#FFE082"
|
||||
android:pathData="M4,4.44v2.83c7.03,0 12.73,5.7 12.73,12.73h2.83c0,-8.59 -6.97,-15.56 -15.56,-15.56zM4,10.1v2.83c3.9,0 7.07,3.17 7.07,7.07h2.83c0,-5.47 -4.43,-9.9 -9.9,-9.9z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/themeIcon"
|
||||
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/themeIcon"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48V20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48V3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM15,19l-6,-2.11V5l6,2.11V19z" />
|
||||
</vector>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:drawable="@drawable/ic_launcher_background" />
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@drawable/splash_front" />
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start">
|
||||
|
||||
<include
|
||||
android:id="@+id/include_app_bar"
|
||||
layout="@layout/app_bar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:headerLayout="@layout/drawer_header"
|
||||
app:menu="@menu/drawer_menu" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:titleTextColor="@color/themeAccent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbar_timer"
|
||||
style="@style/ToolbarText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/toolbar_filter"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/toolbar_filter"
|
||||
style="@style/ToolbarButton"
|
||||
android:contentDescription="@string/placeholder"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/include_main_content"
|
||||
layout="@layout/content_main" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/app_bar_main">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_host"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navGraph="@navigation/nav_graph"
|
||||
tools:ignore="FragmentTagUsage" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,79 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/pass_pref_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pref_tv_title"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/dialog_filter_passes"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pref_tv_hoursAhead"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/pref_hours_ahead_summary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_tv_title" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/pref_et_hoursAhead"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/pref_hours_ahead_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="number"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_tv_hoursAhead"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_tv_hoursAhead"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_tv_hoursAhead" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pref_tv_minEl"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/pref_min_el_summary"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_et_hoursAhead"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_et_hoursAhead"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_et_hoursAhead" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/pref_et_minEl"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/pref_min_el_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="number|numberDecimal"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_tv_minEl"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_tv_minEl"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_tv_minEl" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/dialog_sat_entry_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
style="@style/DialogText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/dialog_select_sat"
|
||||
app:layout_constraintEnd_toEndOf="@+id/dialog_btn_positive"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="@+id/dialog_btn_neutral"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<SearchView
|
||||
android:id="@+id/dialog_search"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:queryHint="@string/dialog_entries_hint"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/dialog_title" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dialog_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/dialog_btn_negative"
|
||||
app:layout_constraintEnd_toEndOf="@+id/dialog_search"
|
||||
app:layout_constraintStart_toStartOf="@+id/dialog_search"
|
||||
app:layout_constraintTop_toBottomOf="@+id/dialog_search" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_btn_neutral"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/btn_all_none"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/dialog_btn_negative"
|
||||
app:layout_constraintStart_toStartOf="@+id/dialog_recycler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_btn_negative"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/btn_cancel"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/dialog_btn_positive"
|
||||
app:layout_constraintEnd_toStartOf="@+id/dialog_btn_positive" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_btn_positive"
|
||||
style="@style/DialogText"
|
||||
android:layout_width="36dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="end"
|
||||
android:text="@string/btn_ok"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/dialog_recycler" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/tleSourcesDialog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tleSourcesTitle"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/dialog_tle_sources"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tleSourceBtnAdd"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tleSourceBtnAdd"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:contentDescription="@string/placeholder"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tleSourcesWarning"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/tleSourcesTitle"
|
||||
app:layout_constraintTop_toTopOf="@+id/tleSourcesTitle"
|
||||
app:srcCompat="@drawable/ic_add" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tleSourcesRecycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tleSourcesBtnPos"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tleSourceBtnAdd"
|
||||
app:layout_constraintVertical_chainStyle="packed">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tleSourcesWarning"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/https_only"
|
||||
app:layout_constraintStart_toStartOf="@+id/tleSourcesTitle"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tleSourcesTitle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tleSourcesBtnNeg"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/btn_cancel"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/tleSourcesBtnPos"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tleSourcesBtnPos"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tleSourcesBtnPos"
|
||||
style="@style/DialogText"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/btn_ok"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/tleSourceBtnAdd" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,176 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_launcher_background"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_title"
|
||||
style="@style/DrawerHeader.Title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="@string/drawer_title"
|
||||
app:layout_constraintEnd_toStartOf="@+id/drawer_sat_img"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toTopOf="@+id/guidelineTop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drawer_sat_img"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:contentDescription="@string/app_name"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/drawer_title"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/drawer_title"
|
||||
app:layout_constraintTop_toTopOf="@+id/drawer_title"
|
||||
app:srcCompat="@drawable/ic_sat_desc_left" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_lat"
|
||||
style="@style/DrawerHeader.Item"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="@string/drawer_lat_text"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/drawer_lat_value"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_lat_value"
|
||||
style="@style/DrawerHeader.ItemValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/pat_location"
|
||||
app:layout_constraintStart_toStartOf="@+id/drawer_lon_value"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_sat_img" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_lon"
|
||||
style="@style/DrawerHeader.Item"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="@string/drawer_lon_text"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/drawer_lon_value"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawer_lon_value"
|
||||
style="@style/DrawerHeader.ItemValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/pat_location"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.1"
|
||||
app:layout_constraintStart_toEndOf="@+id/mainBarrier"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_lat_value" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/drawer_btn_loc"
|
||||
style="@style/DrawerHeader.Button"
|
||||
android:layout_width="0dp"
|
||||
android:drawableEnd="@drawable/ic_update_loc"
|
||||
android:text="@string/update_loc"
|
||||
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_tle_file"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_lon_value" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/drawer_btn_tle_file"
|
||||
style="@style/DrawerHeader.Button"
|
||||
android:layout_width="0dp"
|
||||
android:drawableEnd="@drawable/ic_file_open"
|
||||
android:text="@string/import_data_file"
|
||||
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_tle_url"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_loc" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/drawer_btn_tle_url"
|
||||
style="@style/DrawerHeader.Button"
|
||||
android:layout_width="0dp"
|
||||
android:drawableEnd="@drawable/ic_update_tle"
|
||||
android:text="@string/import_data_web"
|
||||
app:layout_constraintBottom_toTopOf="@+id/drawer_btn_github"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_tle_file" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/drawer_btn_github"
|
||||
style="@style/DrawerHeader.Button"
|
||||
android:layout_width="0dp"
|
||||
android:drawableEnd="@drawable/ic_goto_github"
|
||||
android:text="@string/goto_github"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guidelineBottom"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drawer_btn_tle_url" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/mainBarrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="end"
|
||||
app:constraint_referenced_ids="drawer_lat,drawer_lon"
|
||||
tools:layout_editor_absoluteX="101dp"
|
||||
tools:layout_editor_absoluteY="8dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guidelineTop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="24dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guidelineLeft"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="6dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guidelineRight"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_end="6dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guidelineBottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_end="6dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragments.AboutFragment">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_about_title"
|
||||
style="@style/AboutTitle"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/app_name"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/img_about"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/img_about"
|
||||
app:layout_constraintTop_toTopOf="@+id/img_about" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_about"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:src="@drawable/ic_sputnik"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tv_about_title"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_about_version"
|
||||
style="@style/AboutSubtitle"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/app_version"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_about_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_about_subtitle"
|
||||
style="@style/AboutSubtitle"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/about_subtitle"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_about_version" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_about_thanks"
|
||||
style="@style/AboutSubtitle"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/about_thanks_to"
|
||||
app:layout_constraintEnd_toEndOf="@+id/tv_about_subtitle"
|
||||
app:layout_constraintStart_toStartOf="@+id/tv_about_subtitle"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_about_subtitle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_about_message"
|
||||
style="@style/AboutRegular"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/about_thanks_list"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_about_thanks" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
@@ -1,79 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/osmLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragments.MapOsmFragment">
|
||||
|
||||
<org.osmdroid.views.MapView
|
||||
android:id="@+id/mapView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/satInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/backgroundMapInfoLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/idName"
|
||||
style="@style/MapOsmSatInfo.Name"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/pat_osm_idName"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/altitude"
|
||||
style="@style/MapOsmSatInfo"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="@string/pat_altitude"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/idName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/distance"
|
||||
style="@style/MapOsmSatInfo"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/pat_distance"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/altitude"
|
||||
app:layout_constraintTop_toBottomOf="@+id/altitude" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/velocity"
|
||||
style="@style/MapOsmSatInfo"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="@string/pat_osm_vel"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/altitude"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/latLon"
|
||||
style="@style/MapOsmSatInfo"
|
||||
android:text="@string/pat_osm_latLon"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/distance"
|
||||
app:layout_constraintEnd_toEndOf="@+id/velocity" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mapOsmCopyright"
|
||||
style="@style/MapOsmCopyright"
|
||||
android:text="@string/osmCopyright"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||
~ Copyright (C) 2019, 2020 Arty Bishop (bishop.arty@gmail.com)
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation; either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragments.MapViewFragment">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/frameMap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/worldmap_bg_dark"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabMap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@drawable/ic_sat_asc_right" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMapLat"
|
||||
style="@style/MapText"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/pat_latitude"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMapLon"
|
||||
style="@style/MapText"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="@string/pat_longitude"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMapRng"
|
||||
style="@style/MapText"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/pat_distance"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Loaded 100 of 5763 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user