Compare commits
464 commits
Author | SHA1 | Date | |
---|---|---|---|
|
774c5bec59 | ||
|
c65aab3840 | ||
|
c2bea7bec0 | ||
|
36bd1af0b9 | ||
|
67b0bbbfd2 | ||
|
b80cc3ab04 | ||
|
37f586912f | ||
|
de378b8adc | ||
|
8161353de7 | ||
|
c42b4995b3 | ||
|
5a5d1d66b3 | ||
|
ceb0002546 | ||
|
0cf003ea38 | ||
|
904f2af20a | ||
|
d923630b42 | ||
|
a76a463cd4 | ||
|
c9c10a6fd4 | ||
|
e5866ffb2b | ||
|
97d9bf434e | ||
|
f1464b5f8f | ||
|
369abf14a5 | ||
|
ceb98c4258 | ||
|
4ebd393250 | ||
|
f3b3c6a160 | ||
|
ff62aa5a07 | ||
|
6fbd399a4b | ||
|
fa7e37ccba | ||
|
20d75acd39 | ||
|
7b1897b2e0 | ||
|
93aadae64b | ||
|
a7dd4a6166 | ||
|
cf1f0100ba | ||
|
875f613cd9 | ||
|
ea1ee6bc40 | ||
|
a66d7bf3b2 | ||
|
c5849d7d6a | ||
|
cc16b84011 | ||
|
0f6b1c3ec3 | ||
|
a686fea141 | ||
|
f9951f3b16 | ||
|
073a688db9 | ||
|
1f3cde9326 | ||
|
8326c2196c | ||
|
7361d4bc3f | ||
|
1948c28cff | ||
|
d1be7f5215 | ||
|
8d019b6c3b | ||
|
0708fcb02b | ||
|
c5e3a42005 | ||
|
8c3c7da2ab | ||
|
3bc6afad03 | ||
|
194fbf6927 | ||
|
6d45620181 | ||
|
c9d3693515 | ||
|
a618da97d8 | ||
|
3ec8ab89c6 | ||
|
938a54fc74 | ||
|
0732fe1b91 | ||
|
a7054d3ff8 | ||
25020c1692 | |||
b1fb5d646a | |||
|
51c3f68f22 | ||
|
a80f6ebb45 | ||
|
49c6a97ce7 | ||
|
4f44d1acd3 | ||
|
24571f6921 | ||
|
fb8eb60974 | ||
|
b833311353 | ||
|
6f310985d6 | ||
|
6d62c70359 | ||
|
d34cbe1ed1 | ||
|
66cbf9a47d | ||
|
b1d5e980c2 | ||
|
f693418d64 | ||
|
04e89e516c | ||
|
5854075080 | ||
|
1f8babd708 | ||
|
2618bdf5ad | ||
|
19884c33c1 | ||
|
2289c04f0f | ||
|
1129f1848a | ||
|
c77fd1db01 | ||
|
b072111b8b | ||
|
351b2d6447 | ||
|
ddc2549c66 | ||
|
c1d34fc5db | ||
|
33db3656fa | ||
|
e194d2159e | ||
|
e66c72d255 | ||
|
4cd88400ee | ||
|
48a00b099e | ||
|
e6b2fa606e | ||
|
0b66ef801f | ||
|
e1ea19f02a | ||
|
af9e3ad8a3 | ||
|
d76fe4b82b | ||
|
dc07beafc3 | ||
|
423970ce39 | ||
|
215f67308e | ||
|
376449486b | ||
|
1e15374229 | ||
|
dbbd3cef35 | ||
|
918adcf358 | ||
|
957573ea83 | ||
|
65ba10712f | ||
|
099eb9ca78 | ||
|
ad3966dd85 | ||
|
9a6798f9f4 | ||
|
2cc74ea613 | ||
|
cebf0f473b | ||
|
9da1a910b3 | ||
|
38cf36b46c | ||
|
68be2f3a4a | ||
|
51093e0c3d | ||
|
d53128e5cb | ||
|
82ccc54436 | ||
|
f6ab146fd7 | ||
|
80f8f10bf9 | ||
|
dcc8728171 | ||
|
b48dc5dcac | ||
|
618f3eaaba | ||
|
08242760bb | ||
|
a88dc5d13c | ||
|
586875e32b | ||
|
43a2ad25bc | ||
|
6cac47763c | ||
|
5921549a9c | ||
|
07acb6bd02 | ||
|
dd0432f718 | ||
|
1bb061b563 | ||
|
d8d74de22b | ||
|
8df13fe283 | ||
|
724a0dbc9c | ||
|
1f873e2057 | ||
|
ea66b57979 | ||
|
cbb98f7c60 | ||
|
ed511bec01 | ||
|
204429b8d5 | ||
|
120c48f702 | ||
|
e4992870fe | ||
|
be4309ecd6 | ||
|
a07bc144d8 | ||
|
3442f018e9 | ||
8aec1aa74f | |||
|
a3cb818db4 | ||
|
15240fca49 | ||
|
32a74e293a | ||
|
b1c2219b4d | ||
|
7215cbd7e6 | ||
|
06119a52cd | ||
|
755adb2ad9 | ||
|
1a99d53c5d | ||
|
28dac50d84 | ||
|
255c6d650e | ||
|
8ac5c2dee9 | ||
|
0393bf274f | ||
|
d1c4e68df3 | ||
|
08c450fc99 | ||
|
ae226c9e16 | ||
|
086f056216 | ||
|
d1d2d7b4d1 | ||
|
a96e91aefb | ||
|
aaa2445bef | ||
|
cb811d8236 | ||
|
496faa7945 | ||
|
34882ba69f | ||
|
ac8b8469b0 | ||
|
e767e514f7 | ||
|
bf6bdbd821 | ||
|
fe4d646c47 | ||
|
19161ca3e4 | ||
|
9767363a7e | ||
|
184de1931e | ||
|
4ba1b8671d | ||
|
6a0b30dd7b | ||
|
58d07f9c6c | ||
|
b4608794ab | ||
|
76f33a45ba | ||
|
eb28ca3f43 | ||
|
15a34a1895 | ||
|
548ff25396 | ||
|
b3129e0e91 | ||
|
05d6efd107 | ||
|
e9fa2082d9 | ||
|
ea7ceacc12 | ||
|
23142488c2 | ||
|
eb0e2b0997 | ||
|
c988fc3bdd | ||
|
92bd98ea28 | ||
|
bdd502174d | ||
|
b07941be75 | ||
|
e54dbedec8 | ||
|
8a934b4a68 | ||
|
acb27766a8 | ||
|
a5a307c076 | ||
|
96daa8789a | ||
|
8324fe52ec | ||
|
99e369088a | ||
|
0e7ff63c9a | ||
|
4f43c56cf9 | ||
|
bf99845379 | ||
|
6d93db79b8 | ||
|
2d7d898bfe | ||
|
544e86073a | ||
|
756b31a4ea | ||
|
b075f020a3 | ||
|
87f160f4c4 | ||
|
e443a8ed6f | ||
|
1ff93b6959 | ||
|
baff1a1d35 | ||
20afd6a2ad | |||
|
ddc0afa65a | ||
|
101c5f5b7d | ||
|
8d6b09c800 | ||
5379386ecc | |||
07bff2d71c | |||
|
0db1360853 | ||
|
ac2327d2f2 | ||
|
47184fe878 | ||
a32d871cca | |||
|
a205f9372d | ||
|
4ed9a0169a | ||
9f39e3ca1c | |||
392b76c53d | |||
|
8ef2cacc79 | ||
06574ccbcf | |||
|
0aad48ad49 | ||
5428113706 | |||
|
98bf2d6a93 | ||
|
9ecaf6900a | ||
|
165626fc6c | ||
|
a31a530c7c | ||
|
05e6e4d2bd | ||
|
175125996e | ||
|
4f3eac9977 | ||
|
d567b5fbdd | ||
|
4519d16af8 | ||
|
c461ff5b7c | ||
|
9e0c6b1741 | ||
|
19ac40c5b3 | ||
|
97543ced06 | ||
|
8abb662546 | ||
|
bea1a83f90 | ||
3a4f41f758 | |||
8ede0ea304 | |||
6037c0b3eb | |||
b62f8d32b7 | |||
dbafcc065c | |||
be0a37dbc8 | |||
812c4dabf7 | |||
|
a3060866e9 | ||
|
499027a8f1 | ||
b8476aa107 | |||
00e238a028 | |||
d6c6920840 | |||
c02ededf9f | |||
c5b201f456 | |||
8b48cf38ce | |||
527912e49b | |||
72a41a0b8a | |||
d0a541bc34 | |||
1db57bd957 | |||
f2ed7069a6 | |||
|
7a0ec98ed4 | ||
|
ff48cb8982 | ||
|
fff3c7a716 | ||
bea35292f8 | |||
8e324d8f2b | |||
e6f16fce50 | |||
b07a1eba1e | |||
825d9be1e0 | |||
73cb775af2 | |||
dd4af48b8e | |||
76d58cb100 | |||
58c61a0d05 | |||
|
f1dc2eb733 | ||
|
e807003d42 | ||
d17d89f7f9 | |||
|
a151d37a4e | ||
|
bc925e1a1e | ||
|
e95082cefb | ||
|
95dbb2cd34 | ||
a650994626 | |||
|
d1f837e5f7 | ||
|
320360afb3 | ||
|
caa7f8c59d | ||
39b45a03d0 | |||
fd05370280 | |||
|
67f5b1d5e2 | ||
d8a3e029b1 | |||
c8eb6f598f | |||
666950590b | |||
b9c4223a5e | |||
|
32b747ebb7 | ||
|
4d1c12a9d9 | ||
f89f21f979 | |||
765a96f48b | |||
30ca937461 | |||
f08fb9e349 | |||
9d245736b3 | |||
d34c75a647 | |||
6e1e473aff | |||
|
9214155425 | ||
|
964b144657 | ||
bafcfd46d6 | |||
ef43ed2f7f | |||
|
4e91d101aa | ||
|
b7ca97208a | ||
|
e239f519e4 | ||
|
2b0a5cd876 | ||
|
23e1ddc8cf | ||
|
80d3d3265e | ||
|
1cf21f057f | ||
532b80ea84 | |||
c0f4fcd62f | |||
97d075e210 | |||
03166de709 | |||
84d02a38f9 | |||
b9221099c2 | |||
6ad634cc5b | |||
6cc651bfcc | |||
|
6e7ae16e33 | ||
|
bff4ab2e97 | ||
|
866672eb47 | ||
|
2f5aa1e0e7 | ||
3e7c843d7b | |||
6b512ee110 | |||
|
a0d1992829 | ||
ebc70fdff0 | |||
f76207e75b | |||
8e852d7ff2 | |||
54ba7b389c | |||
6d4bc38ea6 | |||
0a4be1e502 | |||
|
ec8eec2960 | ||
|
eee1f3a84a | ||
|
72189af353 | ||
|
71d8b886f6 | ||
|
110598ea85 | ||
|
627c996f89 | ||
14b9b6a8f0 | |||
26751ff931 | |||
c67992fc37 | |||
|
3195918dd1 | ||
bc2687b8cb | |||
5d4106e0b3 | |||
f49877b792 | |||
c09618f191 | |||
d940b6c49a | |||
|
d9740d7275 | ||
|
a2508e4df5 | ||
|
64a9d02e7c | ||
|
c550c2474e | ||
|
3303a48787 | ||
7391431501 | |||
ebedfd9fb5 | |||
|
654a00d647 | ||
|
50207181f9 | ||
|
91c706ed4a | ||
|
c005ef744d | ||
|
68d299f894 | ||
|
160ed992df | ||
|
88e4636e88 | ||
|
7ee5e0f39b | ||
|
036457117c | ||
|
2475c66830 | ||
|
d8cbe480ad | ||
|
e0e8adac19 | ||
|
94895f78e0 | ||
|
e06e2f3ba1 | ||
|
fec93a0660 | ||
|
850f759cde | ||
|
1baeac1fe5 | ||
|
ae26ecd112 | ||
|
e4d4305fc1 | ||
|
8e9dabe951 | ||
|
4c8602b37d | ||
|
73895c9ddb | ||
|
8a94bf5766 | ||
|
a04e2051a8 | ||
|
2aaddec3a3 | ||
|
5c41c62c85 | ||
|
a1ca8596b8 | ||
|
179fb3e741 | ||
|
3eb5b2c867 | ||
|
bd8b5381ea | ||
|
3d2fce6ac0 | ||
|
b2337b1955 | ||
|
c94a511ace | ||
|
52d6947d3e | ||
|
b12e021e99 | ||
|
a086923804 | ||
|
adff9667af | ||
|
aab63bfb13 | ||
|
1f0861c519 | ||
|
2996c63981 | ||
|
4a135e50d6 | ||
|
504f7cd434 | ||
|
ed55459019 | ||
|
67c416f870 | ||
|
ef0e1b792a | ||
|
3af1d120d7 | ||
|
fb4209b13f | ||
|
e2eaa73ba1 | ||
|
0bf2e0aabd | ||
|
5ba8675c39 | ||
|
ac19efd847 | ||
|
1261d93a17 | ||
|
dc8349a4e8 | ||
|
916ee58690 | ||
|
40592ffae8 | ||
|
ae2cefd6a5 | ||
|
0b0b0198df | ||
|
b8ba6bb443 | ||
|
f58fbd8364 | ||
|
1dcd05af10 | ||
|
1b06e20c84 | ||
|
83ea03ab60 | ||
|
02f56f25fb | ||
|
d7046a1036 | ||
|
2a4706654f | ||
|
9e0a364bc8 | ||
|
e6446217a8 | ||
|
7dbfb10229 | ||
|
305a40c8c5 | ||
|
87363d204a | ||
|
8721f9e45b | ||
|
e7f74eb08d | ||
|
05d9edbbdb | ||
|
823ab7b8d8 | ||
|
315361e2b2 | ||
|
4ad9828f2c | ||
|
06466b7743 | ||
|
78b96d9ade | ||
|
40a9823b19 | ||
|
c93e28cdc7 | ||
|
89ee0450e9 | ||
|
8ae74d97d4 | ||
|
18eeb76079 | ||
|
5a6910b447 | ||
|
48f0997864 | ||
|
240551f34c | ||
|
e3a777a800 | ||
|
f26f1539ec | ||
|
c62f38e693 | ||
|
50f5a79c30 | ||
|
0b8dbcc35d | ||
|
12d12cdd39 | ||
|
f8d8126c0e | ||
|
7091b1ba31 | ||
|
7c1510a272 | ||
|
75106e2c12 | ||
|
5bcc99dfba | ||
|
024bba8260 | ||
|
417a695a6b | ||
|
c3006f9fb2 | ||
|
7f7116e843 | ||
|
68e5a4a081 | ||
|
03c591c974 | ||
|
38ae98478c | ||
|
2e7c045e71 | ||
|
1377bad6b9 | ||
|
08b39b16c9 | ||
|
9bb6a383d5 |
23
.atomignore
Executable file
|
@ -0,0 +1,23 @@
|
|||
.git
|
||||
.github
|
||||
.gradle
|
||||
.idea
|
||||
build
|
||||
gradle
|
||||
.gitlab-ci.yml
|
||||
*.iml
|
||||
local.properties
|
||||
settings.gradle
|
||||
gradlew
|
||||
gradlew.bat
|
||||
LICENSE.md
|
||||
app/build
|
||||
app/.gitignore
|
||||
app/pom.xml
|
||||
app/proguard-rules.pro
|
||||
.hidden
|
||||
.travis.yml
|
||||
circle.yml
|
||||
CODE_OF_CONDUCT*
|
||||
gradle.properties
|
||||
LICENSE*
|
50
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,40 +1,24 @@
|
|||
#### General information
|
||||
|
||||
* **Device:** eg Nexus 5, Samsung Galaxy S6
|
||||
* **Android Version:** eg Android 6.0.1 Stock or Android 4.2 CM
|
||||
* **Pod:** eg pod.geraspora.de, self hosted
|
||||
* **Diaspora pod version:** eg 0.5.99.0-p9bd2337c (can be found on the bottom)
|
||||
* **App source:** eg HEAD, F-Droid, PlayStore, self build (latest HEAD)
|
||||
* **App version:** eg 0.1.1, or commit
|
||||
* **App version:**
|
||||
* **System:**
|
||||
* **Pod:**
|
||||
|
||||
#### Description
|
||||
|
||||
|
||||
#### Log
|
||||
|
||||
<!--
|
||||
I have:
|
||||
Look for already reported issues before posting!
|
||||
Also take a look at documentation and wiki, or write in the project chat.
|
||||
|
||||
- searched open and closed issues for duplicates
|
||||
- read <https://github.com/Diaspora-for-Android/diaspora-android/blob/master/CONTRIBUTING.md>
|
||||
- not submitted translations - see [Crowdin](https://crowdin.com/project/diaspora-for-android/invite)
|
||||
App version: The version of the app installed and the installation source. Example: v0.3.5 F-Droid
|
||||
Please keep in mind that only the latest downloadable version is supported and that there are no backports to older versions.
|
||||
System: Information about where the app is running. Give all details you know, but at least the Android OS version.
|
||||
Example: Android 8.0.1, Nexus 5, LineageOS
|
||||
|
||||
Description:
|
||||
What this is about, what happens and what is expected to happen. What needs to be done for it to happen.
|
||||
If a crash is happening a log is needed. Screenshots or demonstration videos are always helpful too.
|
||||
-->
|
||||
|
||||
#### Steps to reproduce
|
||||
|
||||
1. …
|
||||
2. …
|
||||
3. …
|
||||
|
||||
|
||||
#### Expected result
|
||||
|
||||
What is the expected output? What do you see instead?
|
||||
|
||||
Upload screenshots via drag&drop if needed and apply resizing:
|
||||
`<img width="30%" height="30%" src="https://cloud.githubusercontent.com/assets/67..b55.jpg">`
|
||||
|
||||
|
||||
#### Debug output
|
||||
|
||||
Please post the output of adb logcat. The log should begin with the start of Diaspora for Android and include all the steps it takes to reproduce the problem.
|
||||
|
||||
````
|
||||
adb logcat -s com.github.dfa.diaspora_android
|
||||
````
|
||||
|
|
27
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Hello, and thanks for contributing!
|
||||
|
||||
Please always do auto-reformat on code before creating a PR.
|
||||
In Android-Studio do a right-click on java->Reformat and check the first two options.
|
||||
|
||||
After creating the PR please wait patiently till somebody from the team has time to give a review.
|
||||
The top-priority requirement for this to get merged is, that building/tests don't fail.
|
||||
If theres an continious integration system integrated in this project, you should see a colored checkmark in the PR window which tells the status.
|
||||
|
||||
## Contributors document
|
||||
Add yourself! When adding your information to the `CONTRIBUTORS.md` file, please use the following format:
|
||||
|
||||
Schema: **[Name](Reference)**<br/>~° Text
|
||||
Where:
|
||||
* Name: username, first/lastname
|
||||
* Reference: E-Mail, Webpage
|
||||
* Text: Information about / kind of contribution
|
||||
Example:
|
||||
* **[Nice Guy](http://niceguy.web)**<br/>~° German localization
|
||||
-->
|
68
.github/workflows/build-android-project.yml
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
##############################################################################################################################
|
||||
# # Cleanup:
|
||||
#const sleep = ms => () => new Promise((resolve, reject) => window.setTimeout(resolve, ms));
|
||||
#Promise.resolve()
|
||||
#.then(() => { document.getElementsByClassName("details-overlay details-reset position-relative d-inline-block ")[3].children[0].click(); })
|
||||
#.then(sleep(500))
|
||||
#.then(() => { document.getElementsByClassName("dropdown-item btn-link menu-item-danger")[0].click(); })
|
||||
#.then(sleep(1000))
|
||||
#.then(() => { document.getElementsByClassName("btn btn-block btn-danger")[0].click();});
|
||||
#
|
||||
# while [ 1 ] ; do sleep 4; xdotool key Up; sleep 0.1; xdotool key Return; done
|
||||
##############################################################################################################################
|
||||
|
||||
name: "CI"
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, 'ci skip') && (!contains(github.event_name, 'pull_request') || (contains(github.event_name, 'pull_request') && github.event.pull_request.head.repo.full_name != github.repository))"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: "Checkout: Code"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: "Checkout: Code (PR)"
|
||||
uses: actions/checkout@v2
|
||||
if: "contains(github.event_name, 'pull_request')"
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: "Setup: Java"
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
|
||||
- name: "Cache: Gradle"
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle
|
||||
.gradle
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('gradle/wrapper/gradle-wrapper.*') }}
|
||||
|
||||
- name: "Build: Project with make"
|
||||
run: make clean all
|
||||
|
||||
- name: "Build: List dist files"
|
||||
if: always()
|
||||
run: find dist -type f -maxdepth 2
|
||||
|
||||
- name: "Artifacts: All"
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v2.2.1
|
||||
with:
|
||||
name: "all"
|
||||
path: dist
|
||||
retention-days: 5
|
||||
|
||||
- name: "Artifacts: Android APK"
|
||||
uses: actions/upload-artifact@v2.2.1
|
||||
with:
|
||||
name: "android-apk"
|
||||
path: |
|
||||
dist/*.apk
|
116
.gitignore
vendored
|
@ -1,39 +1,76 @@
|
|||
*~
|
||||
##############
|
||||
### Common ###
|
||||
*~*
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.log
|
||||
|
||||
# Gradle
|
||||
.gradle/
|
||||
################
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
*.iml
|
||||
/out/
|
||||
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
## User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
## Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
build/
|
||||
/*/build/
|
||||
dist/
|
||||
gradle-app.setting
|
||||
|
||||
# User-specific configurations
|
||||
local.properties
|
||||
crowdin.yaml
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
.idea
|
||||
.idea/libraries/
|
||||
.idea/runConfigurations.xml
|
||||
.idea/gradle.xml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/.name
|
||||
.idea/compiler.xml
|
||||
.idea/copyright/profiles_settings.xml
|
||||
.idea/encodings.xml
|
||||
.idea/misc.xml
|
||||
.idea/modules.xml
|
||||
.idea/scopes/scope_settings.xml
|
||||
.idea/vcs.xml
|
||||
*.iml
|
||||
###############
|
||||
### Eclipse ###
|
||||
#.project
|
||||
*.pydevproject
|
||||
.metadata
|
||||
*.swp
|
||||
*~.nib
|
||||
.settings/
|
||||
.loadpath
|
||||
.externalToolBuilders/
|
||||
*.launch
|
||||
.cproject
|
||||
.classpath
|
||||
.factorypath
|
||||
.buildpath
|
||||
.target
|
||||
.texlipse
|
||||
|
||||
# OS-specific files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
############
|
||||
### Java ###
|
||||
*.class
|
||||
.mtj.tmp/
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
hs_err_pid*
|
||||
|
||||
###############
|
||||
### Android ###
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
|
@ -41,14 +78,27 @@ Thumbs.db
|
|||
# Files for the Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard
|
||||
proguard/
|
||||
*.log
|
||||
|
||||
# Android Studio Stuff
|
||||
.navigation/
|
||||
gen-external-apklibs
|
||||
|
||||
### Project ##
|
||||
app/src/main/res/raw/changelog.*
|
||||
app/src/main/res/raw/license.*
|
||||
app/src/main/res/raw/readme.*
|
||||
app/src/main/res/raw/contributors.*
|
||||
app/flavor*
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
|
|
1
.hidden
|
@ -1,4 +1,3 @@
|
|||
build
|
||||
crowdin.yaml
|
||||
diaspora-android.iml
|
||||
gradle
|
||||
|
|
32
.travis.yml
|
@ -1,32 +0,0 @@
|
|||
language: android
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- tools # TODO https://github.com/travis-ci/travis-ci/issues/6193
|
||||
- platform-tools
|
||||
- build-tools-24.0.1
|
||||
- android-24
|
||||
- extra-android-m2repository
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
script: "./gradlew $TASK"
|
||||
env:
|
||||
- TASK="lintDebug"
|
||||
- TASK="build check --stacktrace"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- l10n_master
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/e462044d3105a7bb4b4f
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: never # options: [always|never|change] default: always
|
170
CHANGELOG.md
|
@ -1,6 +1,162 @@
|
|||
# v0.2.0 (WIP)
|
||||
### Recent changes
|
||||
- See [Discussions](https://github.com/gsantner/dandelion/discussions), [Issues](https://github.com/gsantner/dandelion/issues) and [Project page](https://github.com/gsantner/dandelion#readme) to see what is going on.
|
||||
|
||||
# v0.1.5
|
||||
### v1.4.0
|
||||
- Add seconds to 'save picture' date format
|
||||
- Updated translations
|
||||
- Added german F-Droid description translation
|
||||
- Update to Android SDK 29
|
||||
|
||||
### v1.3.0
|
||||
- Add option to open youtube links external/in YouTube app (optional)
|
||||
- Pull to refresh
|
||||
|
||||
### v1.2.3
|
||||
**Improved:**
|
||||
- More supported languages, more complete translations!
|
||||
|
||||
### v1.2.1
|
||||
**App release: dandelior**
|
||||
- Added an (rebranded) flavor of dandelion: dandelior
|
||||
- Only differenties in use are other (black) icon and AMOLED colors by default enabled
|
||||
- Already available on F-Droid
|
||||
|
||||
**New features:**
|
||||
- All new Aspects and Tags, using a searchable dialog
|
||||
|
||||
**Fixed:**
|
||||
- Sometimes the Stream went white, which is due an still (>3 years) unfixed Android Support library bug. It should not occur very often anymore due less use of fragments.
|
||||
|
||||
**Improved:**
|
||||
- Various small tweaks
|
||||
- Updated translation files
|
||||
|
||||
### v1.1.3
|
||||
- Improve sharing *a lot*, add support for multiple filetypes
|
||||
- Support for downloading GIFs ;)
|
||||
- Rework screenshot saving and sharing; add new share options:
|
||||
- Merge license and changelog dialog on first start
|
||||
|
||||
### v1.1.2
|
||||
- Fix: loading non-pod links outside customtab/external browser
|
||||
- Fix: webview-js dialog not dismissing correctly
|
||||
|
||||
### v1.1.0
|
||||
- Added: App shortcuts (Android 7+)
|
||||
- Updated: podlist
|
||||
- More supported languages
|
||||
- File sharing fixes
|
||||
|
||||
### v1.0.8
|
||||
- Modified: Navigation - Merge bottom toolbar into top
|
||||
- Updated: Build for Android O/27
|
||||
- Updated: Language change preference
|
||||
- Added: B/W coloring of toolbar popup
|
||||
|
||||
### v1.0.5
|
||||
- Updated: Language preference
|
||||
|
||||
### v1.0.4
|
||||
- Updated: README
|
||||
- Added: Hide statusbar option
|
||||
- Fixed: Language list
|
||||
- Added: Sardinian,Malayalam,Turkish translation
|
||||
|
||||
### v1.0.3
|
||||
- Update opoc
|
||||
- Better visibility for counter badge
|
||||
- Refactor DiasporaPod model
|
||||
- Update PodList (many new pods!)
|
||||
- Fix CustomTab bug
|
||||
|
||||
### v1.0.2 (2017-08-05)
|
||||
- Improve build script
|
||||
- Update translation file license
|
||||
|
||||
### v1.0.1 (2017-07-30)
|
||||
- Update SimpleMarkdownParser
|
||||
- Move untranslatable strings
|
||||
|
||||
### v1.0.0 (2017-06-14)
|
||||
- Added AMOLED mode
|
||||
- Improve NavDrawer
|
||||
- Improve Shared by notice
|
||||
- Use opoc/Helpers,AdBlock
|
||||
|
||||
### v0.2.7 (2017-05-26)
|
||||
- Small improvements
|
||||
|
||||
### v0.2.6 (2017-05-03)
|
||||
- Fixed #156 #158 #159
|
||||
- Added chinese traditional language
|
||||
- Added NavSlider option: Statistics
|
||||
- Changed shared-by-notice text
|
||||
- Fix bottom bar hint text background color (Fix #157)
|
||||
- Color improvements
|
||||
|
||||
### v0.2.5 (2017-04-10)
|
||||
- Introduce minimalistic Markdown Parser
|
||||
- Show LICENSE at first start
|
||||
- Show CHANGELOG after update
|
||||
- Convert existing Markup files to Markdown
|
||||
- Update existing markdown files
|
||||
- Update AboutActivity to use new Parser
|
||||
- Added translations: Danish, Korean, Galician
|
||||
|
||||
### v0.2.4 (2017-03-19)
|
||||
- Different icon and color for secondlion
|
||||
- Language switcher
|
||||
- Handle dia.so links
|
||||
- Improve security at internal browser decision
|
||||
- More icons for notification dropdown
|
||||
- Update gradle build scripts
|
||||
- Added CircleCI
|
||||
|
||||
### v0.2.3 (2017-02-24)
|
||||
- Add Czech translation (thanks @bezcitu)
|
||||
- Add option to copy image urls to clipboard
|
||||
- Fixed some bugs related to image upload/download
|
||||
- Published secondlion\* (nighly version of dandelion\*)
|
||||
|
||||
### v0.2.2
|
||||
- Move "toggle mobile/deskop" to nav-slider
|
||||
- Reduce messages sent via broadcast
|
||||
- Allow to jump to last visited page on stream
|
||||
- New language: Hungarian
|
||||
- FIX NullPtr in shared text methods
|
||||
- FIX #117 - Reset NavHeader on change account, reset web profile
|
||||
- FIX #92 Roation settings
|
||||
- FIX #111 Remove legacy code
|
||||
|
||||
### v0.2.1
|
||||
- App name changed to **dandelion***
|
||||
- Rotation options
|
||||
- Top toolbar loads screen again (toggleable in settings)
|
||||
- Fixed overlapping fragments
|
||||
- Visual rework of the About-section of the app
|
||||
|
||||
### v0.2.0a
|
||||
- Added: Customizable Theme Colors!
|
||||
- Improved account setup with easy tor hidden service configuration
|
||||
- Eye candy for the settings activity
|
||||
- Added: "Contacts" shortcut in the navigation slider
|
||||
- Increased the overall performance by using Fragments
|
||||
- Lots of bugfixes
|
||||
- Fixes for the bugfixes!
|
||||
|
||||
### v0.1.6
|
||||
- Added: New languages
|
||||
- Changed: New delicious visual style + launcher icon
|
||||
- Changed: Notifications-/Messages-indicator does now display number of events!
|
||||
- Changed: Redesigned Navigation Drawer
|
||||
- Fixed: Immediately apply preference changes
|
||||
- Added: About screen that shows useful information
|
||||
- Changed: Updated NetCipher library to 2.0.0-alpha1
|
||||
- Fixed: Do not reload stream on orientation changes
|
||||
- Fixed: Image upload for older devices
|
||||
- Added: Option to open external links in Chrome CustomTab
|
||||
|
||||
### v0.1.5
|
||||
- Update title depending on what the user is doing
|
||||
- New greenish color scheme
|
||||
- Replaced SwipeToRefresh functionality with refresh button
|
||||
|
@ -15,7 +171,7 @@
|
|||
- Allow slider customization
|
||||
- Show aspect name after selection
|
||||
|
||||
# v0.1.4 (2016-07-31)
|
||||
### v0.1.4 (2016-07-31)
|
||||
- by @vanitasvitae, @gsantner, @di72nn
|
||||
- Allow turning off toolbar intellihide
|
||||
- Handle links from browseable intent filter #38
|
||||
|
@ -30,7 +186,7 @@
|
|||
- Share screenshot fix; Minor Aspects rework
|
||||
- Update to SDK 24 (Android N)
|
||||
|
||||
# v0.1.3 (2016-07-04)
|
||||
### v0.1.3 (2016-07-04)
|
||||
- Added titles on top toolbar (by @scoute-dich)
|
||||
- Made bottom toolbar automatically disappear
|
||||
- Added option to share images to external app
|
||||
|
@ -41,7 +197,7 @@
|
|||
- Removed swipe-to-refresh functionality in some places
|
||||
- Big thanks and good luck to @scoute-dich and @martinchodev for accompanying this project :)
|
||||
|
||||
# v0.1.2 (2016-06-05)
|
||||
### v0.1.2 (2016-06-05)
|
||||
- Extract and show aspects (by @gsantner)
|
||||
- Cache last podlist
|
||||
- Better sharing from app
|
||||
|
@ -54,7 +210,7 @@
|
|||
- Lots of refactoring; Reworked Splash,PodSelectionActivity; Switch Pod; Clear settings;
|
||||
- Activity transitions, usability MainActivity, green accent color
|
||||
|
||||
# v0.1.1
|
||||
### v0.1.1
|
||||
- Sharing updated (by @scoute-dich)
|
||||
- Screenshotting updated
|
||||
- Gitter integration (by @gsantner)
|
||||
|
@ -64,7 +220,7 @@
|
|||
- Travis CI integration
|
||||
- Bump Gradle, Build-Tools, Libs to Android Studio 2.1 defaults
|
||||
|
||||
# v0.1.0 (Diaspora for Android)
|
||||
### v0.1.0 (Diaspora for Android)
|
||||
First version of the organization *Diaspora for Android*
|
||||
Consists mostly of code from:
|
||||
- Diaspora-Native-Webapp (by @martinchodev )
|
||||
|
|
74
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at <gsantner AT mailbox DOT org>. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -1,6 +0,0 @@
|
|||
We are always open for any kind of contribution. (PR's, bug reports, feature requests, translations, ..)
|
||||
If you got any questions feel free to join our XMPP/Jabber conference at `diaspora-android@conference.jabberhead.tk` or [Gitter](https://gitter.im/Diaspora-for-Android/diaspora-android).
|
||||
Note that the main project members are mostly busy with their job/university/school and may not react or start coding immediately.
|
||||
|
||||
We use Crowdin to translate Diaspora for Android. Join our project here: <https://crowdin.com/project/diaspora-for-android/invite>
|
||||
If your desired language is not listed please contact the maintainers/owner.
|
32
CONTRIBUTORS.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!--
|
||||
This file contains references to people who contributed to the app.
|
||||
|
||||
Schema: **[Name](Reference)**<br/>~° Text
|
||||
|
||||
Where:
|
||||
* Name: username, first/lastname
|
||||
* Reference: E-Mail, Webpage
|
||||
* Text: Information about / kind of contribution
|
||||
|
||||
|
||||
|
||||
## LIST OF CONTRIBUTORS
|
||||
-->
|
||||
* **[Gregor Santner](http://github.com/gsantner)**<br/>~° Development of dandelion
|
||||
* **[Paul Schaub](https://github.com/vanitasvitae)**<br/>~° Development of dandelion
|
||||
* **[Martín Vukovic](martinvukovic AT protonmail DOT com)**<br/>~° Diaspora Native WebApp
|
||||
* **[Gaukler Faun](https://github.com/scoute-dich)**<br/>~° Diaspora Native WebApp additions
|
||||
* **[Airon90](https://diasp.eu/u/airon90)**<br/>~° Italian translation
|
||||
* **[Nacho Fernández](nacho_f AT joindiaspora DOT com)**<br/>~° Spanish translation
|
||||
* **[Naofumi Fukue](https://github.com/naofum)**<br/>~° Japanese translation
|
||||
* **[pskosinski](email AT pskosinski DOT pl)**<br/>~° Polish translation
|
||||
* **[SansPseudoFix](https://github.com/SansPseudoFix)**<br/>~° French translation
|
||||
* **[Zsolt Szakács](maxigaz AT diaspora DOT zone)**<br/>~° Hungarian translation
|
||||
* **[Luís F.S. Rosa](https://github.com/luisfsr)**<br/>~° Brazilian Portuguese translation
|
||||
* **[Danilo Raffaelli](https://crowdin.com/profile/Daraf)**<br/>~° Italian translation
|
||||
* **[Âng Iōngchun](https://pubpod.alqualonde.org/u/iongchun)**<br/>~° Chinese traditional translation
|
||||
* **[Mikkel Kirkgaard Nielsen](http://www.mikini.dk)**<br/>~° Danish translation
|
||||
* **[Jean Lucas](jean AT 4ray DOT co)**<br/>~° Spanish translation
|
||||
* **[asereze](https://github.com/asereze)**<br/>~° Sardinian translation
|
||||
* **[Xosé M. Lamas](http://xmgz.eu)**<br />~° Galician translation
|
||||
* **[massimiliano](https://framagit.org/massimiliano)**<br />~° Contributor
|
19
LICENSE.md
|
@ -1,6 +1,6 @@
|
|||
# App
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
# dandelion\*
|
||||
`---------------`
|
||||
<small>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.
|
||||
|
@ -11,8 +11,15 @@ 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 http://www.gnu.org/licenses/.
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.</small>
|
||||
`---------------`
|
||||
|
||||
If you want to publish dandelion\* in an app store, you have to change the app name (dandelion\*), package name & launcher icon (blue). See "7. Additional Terms" of GPL.
|
||||
You also have to provide the modifications in source code somewhere online for free. This is explicitly not about building the app and sharing with some friends, it's about app stores.
|
||||
The reason is, that most app stores allow an app id just once, which would block our uploads if somebody else uploaded. Also, we want to keep control on where the app is published, and want to make sure there is no malware in it.
|
||||
The F-Droid project team is explicitly allowed to publish dandelion\* without listed required modifications above at official F-Droid repository.
|
||||
|
||||
# Splashscreen-Images
|
||||
The splashscreen images can be found on [flickr](https://www.flickr.com/photos/129581906@N06/sets/72157651933980136/with/16594947123/).
|
||||
## Miscellaneous
|
||||
|
||||
We took some inspiration and code from LeafPic. Go check it out, its free software as well!
|
||||
<https://github.com/HoraApps/LeafPic>
|
||||
|
|
99
Makefile
Normal file
|
@ -0,0 +1,99 @@
|
|||
# License of Makefile: Public Domain / CC0
|
||||
.PHONY: $(shell sed -n -e '/^$$/ { n ; /^[^ .\#][^ ]*:/ { s/:.*$$// ; p ; } ; }' $(MAKEFILE_LIST))
|
||||
.NOTPARALLEL: clean
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
env-%:
|
||||
@: $(if ${${*}},,$(error Environment variable $* not set))
|
||||
####################################################################################
|
||||
|
||||
DIST_DIR = dist
|
||||
MOVE = mv
|
||||
|
||||
all: $(DIST_DIR) spellcheck lint deptree test build aapt_dump_badging
|
||||
|
||||
####################################################################################
|
||||
|
||||
$(DIST_DIR):
|
||||
mkdir -p ${DIST_DIR}
|
||||
|
||||
ANDROID_BUILD_TOOLS := $(shell test -n "$ANDROID_SDK_ROOT" && find "${ANDROID_SDK_ROOT}/build-tools" -iname "aapt" | sort -r | head -n1 | xargs dirname)
|
||||
TOOL_SPELLCHECKING_ISPELL := $(shell command -v ispell 2> /dev/null)
|
||||
|
||||
FLAVOR := $(or ${FLAVOR},${FLAVOR},Atest)
|
||||
|
||||
.NOTPARALLEL: gradle gradle-analyze-log
|
||||
gradle: env-ANDROID_SDK_ROOT
|
||||
mkdir -p $(DIST_DIR)/log/
|
||||
chmod +x gradlew
|
||||
./gradlew --no-daemon --parallel --stacktrace $A 2>&1 | tee "$(DIST_DIR)/log/gradle.log"
|
||||
@echo "-----------------------------------------------------------------------------------"
|
||||
|
||||
gradle-analyze-log:
|
||||
mv "$(DIST_DIR)/log/gradle.log" "$(DIST_DIR)/log/gradle$A.log"
|
||||
cat "$(DIST_DIR)/log/gradle$A.log" | grep "BUILD " | tail -n1 | grep -q "BUILD SUCCESSFUL in"
|
||||
|
||||
adb: env-ANDROID_SDK_ROOT
|
||||
"${ANDROID_SDK_ROOT}/platform-tools/adb" $A 2>&1 | tee "$(DIST_DIR)/log/adb-$L.log"
|
||||
|
||||
aapt: env-ANDROID_SDK_ROOT
|
||||
"${ANDROID_BUILD_TOOLS}/aapt" $A 2>&1 | grep -v 'application-label-' | tee "$(DIST_DIR)/log/aapt$L.log"
|
||||
|
||||
build:
|
||||
rm -f $(DIST_DIR)/*.apk
|
||||
$(MAKE) A="clean assembleFlavor$(FLAVOR) -x lint" gradle
|
||||
find app -type f -newermt '-300 seconds' -iname '*.apk' -not -iname '*unsigned.apk' | xargs cp -R -t $(DIST_DIR)/
|
||||
$(MAKE) A="-build" gradle-analyze-log
|
||||
|
||||
lint:
|
||||
rm -Rf $(DIST_DIR)/lint
|
||||
mkdir -p $(DIST_DIR)/lint/
|
||||
$(MAKE) A="lintFlavorDefaultDebug" gradle
|
||||
find app -type f -iname 'lint-results-*' | grep -v 'intermediates' | xargs cp -R -t $(DIST_DIR)/lint
|
||||
$(MAKE) A="-lint" gradle-analyze-log
|
||||
|
||||
test:
|
||||
rm -Rf $(DIST_DIR)/tests
|
||||
$(MAKE) A="testFlavorDefaultDebugUnitTest -x lint" gradle
|
||||
mkdir -p app/build/test-results/testFlavorDefaultDebugUnitTest && echo 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHRlc3RzdWl0ZSBuYW1lPSJkdW1teSIgdGVzdHM9IjEiIHNraXBwZWQ9IjAiIGZhaWx1cmVzPSIwIiBlcnJvcnM9IjAiIHRpbWVzdGFtcD0iMjAyMC0xMi0wOFQwMDowMDowMCIgaG9zdG5hbWU9ImxvY2FsaG9zdCIgdGltZT0iMC4wMSI+CiAgPHByb3BlcnRpZXMvPgogIDx0ZXN0Y2FzZSBuYW1lPSJkdW1teSIgY2xhc3NuYW1lPSJkdW1teSIgdGltZT0iMC4wMSIvPgogIDxzeXN0ZW0tb3V0PjwhW0NEQVRBW11dPjwvc3lzdGVtLW91dD4KICA8c3lzdGVtLWVycj48IVtDREFUQVtdXT48L3N5c3RlbS1lcnI+CjwvdGVzdHN1aXRlPgo=' | base64 -d > 'app/build/test-results/testFlavorDefaultDebugUnitTest/TEST-dummy.xml'
|
||||
find app -type d -iname 'testFlavorDefaultDebugUnitTest' | xargs cp -R -t $(DIST_DIR)/
|
||||
mv ${DIST_DIR}/testFlavorDefaultDebugUnitTest $(DIST_DIR)/tests
|
||||
$(MAKE) A="-test" gradle-analyze-log
|
||||
|
||||
deptree:
|
||||
$(MAKE) A="app:dependencies --configuration flavor$(FLAVOR)DebugRuntimeClasspath" gradle
|
||||
$(MAKE) A="-dependency-tree" gradle-analyze-log
|
||||
|
||||
clean:
|
||||
$(MAKE) A="clean" gradle
|
||||
rm -Rf $(DIST_DIR) app/build app/flavor* .idea dist
|
||||
find . -type f -iname "*.iml" -delete
|
||||
$(MAKE) $(DIST_DIR)
|
||||
@echo "-----------------------------------------------------------------------------------"
|
||||
|
||||
install:
|
||||
$(MAKE) A="install -r $(DIST_DIR)/*.apk" L="install" adb
|
||||
|
||||
run:
|
||||
$(MAKE) A="shell monkey -p $$(aapt dump badging $(DIST_DIR)/*.apk | grep package: | sed 's@.* name=@@' | sed 's@ .*@@' | xargs | head -n1) -c android.intent.category.LAUNCHER 1" L="run" adb
|
||||
|
||||
aapt_dump_badging:
|
||||
$(MAKE) A="dump badging $(DIST_DIR)/*.apk" aapt
|
||||
@echo "-----------------------------------------------------------------------------------"
|
||||
|
||||
spellcheck:
|
||||
mkdir -p "$(DIST_DIR)/lint/"
|
||||
ifndef TOOL_SPELLCHECKING_ISPELL
|
||||
@echo "Tool ispell (spellcheck) not found in PATH. Spellcheck skipped." > "$(DIST_DIR)/lint/stringsxml-spellcheck.txt"
|
||||
else
|
||||
@echo "Use ispell for spellchecking the original values/strings.xml"
|
||||
find . -iname "strings.xml" -path "*/main*/values/*" | head -n1 | xargs cat \
|
||||
| grep "<string name=" | sed 's@.*">@@' | sed 's@</string>@@' | sed 's@\\n@ @g' | sed 's@\\@@g' \
|
||||
| ispell -W3 -a | grep ^\& | sed 's@[0-9]@@g' | sort | uniq | cut -d, -f1-4 \
|
||||
| sed 's@^..@- @' | column -t -s: \
|
||||
> "$(DIST_DIR)/lint/stringsxml-spellcheck.txt"
|
||||
@echo "\nPotential words with bad spelling:"
|
||||
endif
|
||||
@cat "$(DIST_DIR)/lint/stringsxml-spellcheck.txt"
|
||||
@echo "-----------------------------------------------------------------------------------"
|
||||
|
96
NEWS.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
# dandelion - News
|
||||
|
||||
## General
|
||||
|
||||
### Installation
|
||||
You can install and update from [F-Droid](https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android) or [GitHub](https://github.com/gsantner/dandelion/releases/latest).
|
||||
|
||||
F-Droid is a store for free & open source apps.
|
||||
The *.apk's available for download are signed by the F-Droid team and guaranteed to correspond to the (open source) source code of dandelion.
|
||||
Generally this is the recommended way to install dandelion & keep it updated.
|
||||
|
||||
|
||||
### Get informed
|
||||
* Check the [project readme](https://github.com/gsantner/dandelion/tree/news#readme) for general project information.
|
||||
* Check the [project news](https://github.com/gsantner/dandelion/blob/master/NEWS.md#readme) for more details on what is going on.
|
||||
* Check the [project git history](https://github.com/gsantner/dandelion/commits/master) for most recent code changes.
|
||||
|
||||
### The right place to ask
|
||||
If you have questions or found an issue please head to the [dandelion project](https://github.com/gsantner/dandelion/issues/new/choose) and ask there.
|
||||
[Search](https://github.com/gsantner/dandelion/issues?q=#js-issues-search) for same/similar and related issues/questions before, it might be already answered or resolved.
|
||||
|
||||
|
||||
### Navigation
|
||||
* [dandelion v1.2 - Add dandelior - Searchable Tags and Aspects](#dandelion-v12---add-dandelior---searchable-tags-and-aspects)
|
||||
* [dandelion v0.1.2 - Aspekte, Pod wechseln](#dandelion-v012---aspekte-pod-wechseln)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# dandelion\* v1.2 - Add dandelior\* - Searchable Tags and Aspects
|
||||
_12. August 2018_
|
||||
|
||||
## dandelior\* is a rebranded version of dandelion\*
|
||||
dandelior\* is based 100% on the same code and resources as dandelion\*. Its from the same code repository, just a different build flavor.
|
||||
The main purpose of dandelior\* is the most requested feature till date - to support multiple accounts / another account at dandelion\*.
|
||||
|
||||
- Added an (rebranded) flavor of dandelion: dandelior
|
||||
- Only differenties in use are other (black) icon and AMOLED colors by default enabled
|
||||
- Already available on F-Droid
|
||||
|
||||
**New features:**
|
||||
- All new Aspects and Tags, using a searchable dialog
|
||||
|
||||
**Fixed:**
|
||||
- Sometimes the Stream went white, which is due an still (3+ years) unfixed Android Support library bug. It should not occur very often anymore due less use of fragments.
|
||||
|
||||
**Improved:**
|
||||
- Various small tweaks
|
||||
- Updated translation files
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# dandelion v0.1.2 - Aspekte, Pod wechseln
|
||||
_05. Juni 2016_
|
||||
|
||||
In den letzten Tagen hat @gsantner viel Zeit in die inoffizielle diaspora\* Android App ([dandelion\*](https://github.com/gsantner/dandelion)) investiert.
|
||||
|
||||
Dabei wurden unter anderem folgende Änderungen beigesteuert:
|
||||
|
||||
- Allgemeines zur Usability
|
||||
- Animationen für den Activity-Wechsel und Startup, WebView-Scroll-Top
|
||||
- Podliste caching
|
||||
- Aspekt-Liste und Aspekte hinzugefügt
|
||||
- Verbessertes Sharing aus der App
|
||||
- Material Progressbar
|
||||
- Suche verbessert
|
||||
- Collapsing top menu
|
||||
- toolbar/actions/menu geändert, fab entfernt
|
||||
- Refactoring layout & menu files, dialogs
|
||||
- Überarbeitete Main,Splash,PodSelectionActivity
|
||||
- Pod wechseln
|
106
README.md
|
@ -1,43 +1,81 @@
|
|||
[](https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android)
|
||||
[](https://github.com/gsantner/dandelion/releases)
|
||||
[](https://github.com/gsantner/dandelion/releases)
|
||||
[](https://crowdin.com/project/diaspora-for-android/invite)
|
||||
[](https://matrix.to/#/#dandelion:matrix.org)
|
||||
[](https://github.com/gsantner/dandelion/actions)
|
||||
[](https://www.codacy.com/app/gsantner/dandelion)
|
||||
|
||||
[](https://travis-ci.org/Diaspora-for-Android/diaspora-android)
|
||||
[](https://crowdin.com/project/diaspora-for-android)
|
||||
[](https://gitter.im/Diaspora-for-Android/diaspora-android?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
# dandelion\*
|
||||
<img src="/app/src/main/ic_launcher-web.png" align="left" width="100" hspace="10" vspace="10">
|
||||
This is an unofficial webview based client for the community-run, distributed social network <b><a href="https://diasporafoundation.org/">diaspora*</a></b>.
|
||||
|
||||
<div style="display:flex;" >
|
||||
<a href="https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android">
|
||||
<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="80">
|
||||
</a>
|
||||
<!--<a href="https://play.google.com/store/apps/details?id=com.github.dfa.diaspora_android">
|
||||
<img alt="Get it on Google Play" height="80" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" />
|
||||
</a>-->
|
||||
</div></br>
|
||||
|
||||
|
||||
# Diaspora for Android
|
||||
## Description
|
||||
This is an unofficial webview based client for the community-run, distributed social network <b><a href="https://diasporafoundation.org/">diaspora*</a></b>.
|
||||
It's currently under development and should be used with that in mind. Please submit any bugs you might find.
|
||||
|
||||
This is an unofficial webview based client for the community-run, distributed social network **[Diaspora](https://joindiaspora.com/)**. It's currently under development and should be used with that in mind. Please submit any bugs you might find.
|
||||
**Notice:** This is the repo of the latest version of the unoffical Diaspora Android App.
|
||||
#### WebApp
|
||||
The app is developed as a WebApp because currently diaspora\* doesn't have an functional API that can be used to create a native interface to retrieve the user's data, publications, direct messages and so on. That's why there are currently only WebApps for diaspora\* out there.
|
||||
[Stay tuned on diaspora\* issues](https://github.com/diaspora/diaspora/labels/api) about API.
|
||||
|
||||
- Download ([F-Droid](https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android), [Release Archive](https://github.com/Diaspora-for-Android/diaspora-android/releases))
|
||||
- Watch [Changelog](https://github.com/Diaspora-for-Android/diaspora-android/blob/master/CHANGELOG.md)
|
||||
- See [Screenshots](https://github.com/Diaspora-for-Android/diaspora-android/blob/master/SCREENSHOTS.md)
|
||||
|
||||
## Contributions
|
||||
We are always open for any kind of contribution. (PR's, bug reports, feature requests, translations, ..)
|
||||
If you got any questions feel free to join our XMPP/Jabber conference at `diaspora-android@conference.jabberhead.tk` or [Gitter](https://gitter.im/Diaspora-for-Android/diaspora-android).
|
||||
Note that the main project members are mostly busy with their job/university/school and may not react or start coding immediately.
|
||||
|
||||
We use Crowdin to translate Diaspora for Android. Join our project here: <https://crowdin.com/project/diaspora-for-android/invite>
|
||||
If your desired language is not listed please contact the maintainers/owner.
|
||||
|
||||
### License
|
||||
It's released under GNU GENERAL PUBLIC LICENSE (see [LICENCE](https://github.com/Diaspora-for-Android/diaspora-android/blob/master/LICENSE.md)).
|
||||
|
||||
### WebApp
|
||||
The app is developed as an WebApp because currently Diaspora doesn't have an API that can be used to create a native interface to retrieve the user's data, publications, direct messages and so on, that's why there are only WebApps for Diaspora out there.
|
||||
API is discussed frequently on Diaspora, but the main developers seem to not give the API and mobile view the attention it needs. [Stay tuned on Diaspora* Issues](https://github.com/diaspora/diaspora/labels/api).
|
||||
|
||||
Why a WebApp is better than using the mobile site on a browser?
|
||||
Why is a WebApp better than using the mobile site on a browser?
|
||||
Basically it provides better integration with the system (events coming into and going out of the app), notifications, customized interface and functions and a nice little icon that takes you directly to your favorite social network :)
|
||||
|
||||
### Device Requirements
|
||||
The minimum version supported is Jelly Bean, Android v4.2.0 / API 17
|
||||
#### Device Requirements
|
||||
The minimum Android version supported is Jelly Bean, Android v4.2.0 / API 17
|
||||
|
||||
### App Permissions
|
||||
It requires access to the Internet and to external storage to be able to upload photos when creating a new post and for taking screenshots.
|
||||
### Privacy & Permissions<a name="privacy"></a>
|
||||
dandelion\* requires access to the Internet and to external storage to be able to upload photos when creating a new post and for taking screenshots.
|
||||
|
||||
## Maintainers
|
||||
- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.github.io))
|
||||
- vanitasvitae ([GitHub](https://github.com/vanitasvitae))
|
||||
|
||||
## Contributions
|
||||
The project is always open for contributions and accepts pull requests.
|
||||
The project uses [AOSP Java Code Style](https://source.android.com/source/code-style#follow-field-naming-conventions), with one exception: private members are `_camelCase` instead of `mBigCamel`. You may use Android Studios _auto reformat feature_ before sending a PR.
|
||||
|
||||
Translations can be contributed on GitHub. You can use Stringlate ([](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git)) to translate the project directly on your Android phone. It allows you to export as E-Mail attachement and to post on GitHub.
|
||||
|
||||
Join our Matrix channel and say hello! Don't be afraid to start talking. [](https://matrix.to/#/#dandelion:matrix.org)
|
||||
Note that the main project members are working on this project for free during leisure time, are mostly busy with their job/university/school, and may not react or start coding immediately.
|
||||
|
||||
|
||||
#### Resources
|
||||
* Project: [Changelog](/CHANGELOG.md) | [Issues level/beginner](https://github.com/gsantner/dandelion/issues?q=is%3Aissue+is%3Aopen+label%3Alevel%2Fbeginner) | [License](/LICENSE.txt) | [CoC](/CODE_OF_CONDUCT.md)
|
||||
* Project diaspora\* account: [dandelion00@diasp.org](https://diasp.org/people/48b78420923501341ef3782bcb452bd5)
|
||||
* diaspora\*: [GitHub](https://github.com/diaspora/diaspora) | [Web](https://diasporafoundation.org) | [d\* HQ account](https://pod.diaspora.software/people/7bca7c80311b01332d046c626dd55703)
|
||||
* App on F-Droid: [Metadata](https://gitlab.com/fdroid/fdroiddata/blob/master/metadata/com.github.dfa.diaspora_android.txt) | [Page](https://f-droid.org/packages/com.github.dfa.diaspora_android/) | [Wiki](https://f-droid.org/wiki/page/com.github.dfa.diaspora_android) | [Build log](https://f-droid.org/wiki/page/com.github.dfa.diaspora_android/lastbuild)
|
||||
|
||||
|
||||
## Licensing
|
||||
dandelion\* is released under GNU GENERAL PUBLIC LICENSE (see [LICENCE](https://github.com/gsantner/dandelion/blob/master/LICENSE.md)).
|
||||
The app is licensed GPL v3. Localization files and resources (strings\*.xml) are licensed CC0 1.0.
|
||||
For more licensing informations, see [`3rd party licenses`](/app/src/main/res/raw/licenses_3rd_party.md).
|
||||
|
||||
## Screenshots
|
||||
<div style="display:flex;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/01.png" width="19%" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/02.png" width="19%" style="margin-left:10px;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/03.png" width="19%" style="margin-left:10px;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/04.png" width="19%" style="margin-left:10px;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/05.png" width="19%" style="margin-left:10px;" >
|
||||
</div>
|
||||
|
||||
<div style="display:flex;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/06.png" width="19%" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/07.png" width="19%" style="margin-left:10px;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/08.png" width="19%" style="margin-left:10px;" >
|
||||
<img src="https://raw.githubusercontent.com/gsantner/dandelion/master/metadata/en-US/phoneScreenshots/09.png" width="19%" style="margin-left:10px;" >
|
||||
</div>
|
||||
|
||||
### Notice
|
||||
#### Maintainers
|
||||
- gsantner ([GitHub](https://github.com/gsantner), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c))
|
||||
- vanitasvitae ([GitHub](https://github.com/vanitasvitae), [diaspora*](https://pod.geraspora.de/people/bbd7af90fbec013213e34860008dbc6c))
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806540/ada77adc-2b45-11e6-86a0-23467d4c5fc2.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806541/ada7f908-2b45-11e6-8c88-5e141ae1786f.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806544/adab9630-2b45-11e6-8337-0a84bd9c195d.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806542/adaa1580-2b45-11e6-95d9-ab4317dc0e05.png" height="60%" width="60%"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806543/adaada24-2b45-11e6-96b2-9cb391aad0f9.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806545/adac1114-2b45-11e6-8875-5ba414cb1fbd.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806546/adc6caae-2b45-11e6-86f9-48402b752000.png" height="60%" width="60%"></td>
|
||||
<td><img src="https://cloud.githubusercontent.com/assets/6735650/15806547/adc73890-2b45-11e6-9e46-3bb6b2ecc1c9.png" height="60%" width="60%"></td>
|
||||
</tr>
|
||||
</table>
|
|
@ -1,8 +0,0 @@
|
|||
#aaaaaaa>> This file contains references to people who helped translating the app
|
||||
#aaaaaab>> Please send a message on crowdin, and you will get included in the next commit
|
||||
#aaaaaac>>
|
||||
#aaaaaad>> Schemes:
|
||||
#aaaaaae>> Firstname Lastname (Link)
|
||||
#aaaaaaf>> Firstname Lastname (E-Mail)
|
||||
#aaaaaag>> Username (Link)
|
||||
#aaaaaah>> Username (E-Mail)
|
128
app/build.gradle
|
@ -1,18 +1,63 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'android-apt'
|
||||
if (enable_plugin_kotlin) {
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion "24.0.1"
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
buildToolsVersion rootProject.ext.version_buildTools
|
||||
compileSdkVersion rootProject.ext.version_compileSdk
|
||||
|
||||
defaultConfig {
|
||||
resValue "string", "manifest_package_id", "com.github.dfa.diaspora_android"
|
||||
applicationId "com.github.dfa.diaspora_android"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 24
|
||||
versionCode 6
|
||||
versionName "0.1.5"
|
||||
versionName "1.3.5"
|
||||
versionCode 46
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
minSdkVersion rootProject.ext.version_minSdk
|
||||
targetSdkVersion rootProject.ext.version_compileSdk
|
||||
buildConfigField "boolean", "IS_TEST_BUILD", "false"
|
||||
buildConfigField "boolean", "IS_GPLAY_BUILD", "false"
|
||||
buildConfigField "String[]", "DETECTED_ANDROID_LOCALES", "${findUsedAndroidLocales()}"
|
||||
buildConfigField "String", "BUILD_DATE", "\"${getBuildDate()}\""
|
||||
buildConfigField "String", "GITHASH", "\"${getGitHash()}\""
|
||||
setProperty("archivesBaseName", applicationId + "-v" + versionCode + "-" + versionName)
|
||||
}
|
||||
|
||||
flavorDimensions "default"
|
||||
productFlavors {
|
||||
flavorDefault {
|
||||
}
|
||||
|
||||
/*
|
||||
flavorGplay {
|
||||
buildConfigField "boolean", "IS_GPLAY_BUILD", "true"
|
||||
}*/
|
||||
|
||||
flavorDandelior {
|
||||
applicationId "net.gsantner.dandelior"
|
||||
}
|
||||
|
||||
flavorAtest {
|
||||
applicationId "net.gsantner.secondlion"
|
||||
versionCode = Integer.parseInt(new Date().format('yyMMdd'))
|
||||
versionName = new Date().format('yyMMdd')
|
||||
buildConfigField "boolean", "IS_TEST_BUILD", "true"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main { assets.srcDirs = ['src/main/assets'] }
|
||||
if (enable_plugin_kotlin) {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
main.java.srcDirs += 'thirdparty/java'
|
||||
main.res.srcDirs += 'thirdparty/res'
|
||||
main.assets.srcDirs += 'thirdparty/assets'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
@ -20,27 +65,72 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
eachDependency { details ->
|
||||
if (details.requested.group == 'com.android.support') {
|
||||
if (details.requested.name != 'multidex' && details.requested.name != 'multidex-instrumentation') {
|
||||
details.useVersion "${rootProject.ext.version_library_appcompat}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE-LGPL-2.1.txt'
|
||||
exclude 'META-INF/LICENSE-LGPL-3.txt'
|
||||
exclude 'META-INF/LICENSE-W3C-TEST'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
encoding = 'UTF-8'
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
disable 'MissingTranslation', 'InvalidPackage', 'ObsoleteLintCustomCheck', 'DefaultLocale', 'UnusedAttribute', 'VectorRaster', 'InflateParams', 'IconLocation', 'UnusedResources', 'TypographyEllipsis'
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Sub-Projects
|
||||
//compile project(':subprojectFromRoot')
|
||||
//implementation project(':subprojectFromRoot')
|
||||
|
||||
// Jars
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testCompile 'junit:junit:4.12'
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testImplementation 'junit:junit:4.13'
|
||||
|
||||
// Android standard libs
|
||||
compile 'com.android.support:appcompat-v7:24.1.1'
|
||||
compile 'com.android.support:design:24.1.1'
|
||||
compile 'com.android.support:support-v4:24.1.1'
|
||||
implementation "com.android.support:appcompat-v7:${version_library_appcompat}"
|
||||
implementation "com.android.support:design:${version_library_appcompat}"
|
||||
implementation "com.android.support:support-v4:${version_library_appcompat}"
|
||||
implementation "com.android.support:customtabs:${version_library_appcompat}"
|
||||
implementation "com.android.support:cardview-v7:${version_library_appcompat}"
|
||||
implementation "com.android.support:preference-v7:${version_library_appcompat}"
|
||||
|
||||
// More libraries
|
||||
compile 'com.jakewharton:butterknife:8.0.1'
|
||||
compile 'info.guardianproject.netcipher:netcipher:1.2.1'
|
||||
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||
// UI libraries
|
||||
implementation "com.github.DASAR:ShiftColorPicker:v0.5"
|
||||
|
||||
// Tool libraries
|
||||
implementation 'commons-io:commons-io:2.6'
|
||||
implementation "info.guardianproject.netcipher:netcipher:${version_library_netcipher}"
|
||||
implementation "info.guardianproject.netcipher:netcipher-webkit:${version_library_netcipher}"
|
||||
//noinspection AnnotationProcessorOnCompilePath
|
||||
implementation "com.jakewharton:butterknife:${version_library_butterknife}"
|
||||
if (enable_plugin_kotlin) {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${version_plugin_kotlin}"
|
||||
}
|
||||
|
||||
// Processors
|
||||
def anpros = ["com.jakewharton:butterknife-compiler:${version_library_butterknife}"]
|
||||
for (anpro in anpros) {
|
||||
if (enable_plugin_kotlin) {
|
||||
kapt anpro
|
||||
} else {
|
||||
annotationProcessor anpro
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
app/src/flavorAtest/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/flavorAtest/res/drawable-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/flavorAtest/res/drawable-ldpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/flavorAtest/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/flavorAtest/res/drawable-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/flavorAtest/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/flavorAtest/res/drawable-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/flavorAtest/res/drawable-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
app/src/flavorAtest/res/drawable-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
app/src/flavorAtest/res/drawable-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
app/src/flavorAtest/res/drawable-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M0.025,-0.07h19.95v20.14H0.025z"
|
||||
android:fillColor="#492600"/>
|
||||
</vector>
|
12
app/src/flavorAtest/res/drawable/ic_launcher_foreground.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="36.363636"
|
||||
android:viewportHeight="36.363636">
|
||||
<group android:translateX="8.181818"
|
||||
android:translateY="8.181818">
|
||||
<path
|
||||
android:pathData="M11.337,14.123l-0.963,-1.345c-0.257,-0.36 -0.466,-0.64 -0.477,-0.64 -0.012,0 -0.416,0.544 -0.958,1.287a83.9,83.9 0,0 1,-0.947 1.287c-0.015,0 -1.86,-1.3 -1.865,-1.313 -0.002,-0.007 0.415,-0.62 0.927,-1.361 0.512,-0.742 0.931,-1.36 0.931,-1.375 0,-0.023 -0.166,-0.081 -1.468,-0.515l-1.485,-0.496c-0.013,-0.005 0.063,-0.263 0.327,-1.094 0.19,-0.599 0.349,-1.093 0.354,-1.099 0.005,-0.006 0.707,0.219 1.56,0.5 0.852,0.28 1.556,0.509 1.565,0.509 0.008,0 0.018,-0.013 0.022,-0.03 0.003,-0.015 0.01,-0.74 0.016,-1.612 0.006,-0.87 0.015,-1.59 0.02,-1.6 0.009,-0.012 0.248,-0.015 1.127,-0.015 0.614,0 1.123,0.004 1.13,0.01 0.01,0.006 0.027,0.485 0.056,1.56 0.046,1.766 0.047,1.79 0.075,1.79 0.01,0 0.686,-0.226 1.501,-0.503a50.795,50.795 0,0 1,1.49 -0.492c0.016,0.019 0.685,2.194 0.676,2.202 -0.004,0.005 -0.684,0.237 -1.51,0.517 -1.137,0.386 -1.504,0.515 -1.507,0.531 -0.003,0.012 0.388,0.597 0.886,1.324 0.49,0.716 0.888,1.308 0.886,1.314a96.945,96.945 0,0 1,-1.852 1.364c-0.006,0 -0.239,-0.317 -0.517,-0.705z"
|
||||
android:fillColor="#fafafa"/>
|
||||
</group>
|
||||
</vector>
|
BIN
app/src/flavorAtest/res/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 27 KiB |
4
app/src/flavorAtest/res/values/strings-flavor.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">secondlion*</string>
|
||||
</resources>
|
BIN
app/src/flavorDandelior/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 26 KiB |
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
app/src/flavorDandelior/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/flavorDandelior/res/drawable-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/flavorDandelior/res/drawable-ldpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6 KiB |
BIN
app/src/flavorDandelior/res/drawable-ldpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6 KiB |
BIN
app/src/flavorDandelior/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
app/src/flavorDandelior/res/drawable-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
app/src/flavorDandelior/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
app/src/flavorDandelior/res/drawable-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
app/src/flavorDandelior/res/drawable-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
app/src/flavorDandelior/res/drawable-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M0.025,-0.07h19.95v20.14H0.025z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="36.363636"
|
||||
android:viewportHeight="36.363636">
|
||||
<group android:translateX="8.181818"
|
||||
android:translateY="8.181818">
|
||||
<path
|
||||
android:pathData="M11.337,14.123l-0.963,-1.345c-0.257,-0.36 -0.466,-0.64 -0.477,-0.64 -0.012,0 -0.416,0.544 -0.958,1.287a83.9,83.9 0,0 1,-0.947 1.287c-0.015,0 -1.86,-1.3 -1.865,-1.313 -0.002,-0.007 0.415,-0.62 0.927,-1.361 0.512,-0.742 0.931,-1.36 0.931,-1.375 0,-0.023 -0.166,-0.081 -1.468,-0.515l-1.485,-0.496c-0.013,-0.005 0.063,-0.263 0.327,-1.094 0.19,-0.599 0.349,-1.093 0.354,-1.099 0.005,-0.006 0.707,0.219 1.56,0.5 0.852,0.28 1.556,0.509 1.565,0.509 0.008,0 0.018,-0.013 0.022,-0.03 0.003,-0.015 0.01,-0.74 0.016,-1.612 0.006,-0.87 0.015,-1.59 0.02,-1.6 0.009,-0.012 0.248,-0.015 1.127,-0.015 0.614,0 1.123,0.004 1.13,0.01 0.01,0.006 0.027,0.485 0.056,1.56 0.046,1.766 0.047,1.79 0.075,1.79 0.01,0 0.686,-0.226 1.501,-0.503a50.795,50.795 0,0 1,1.49 -0.492c0.016,0.019 0.685,2.194 0.676,2.202 -0.004,0.005 -0.684,0.237 -1.51,0.517 -1.137,0.386 -1.504,0.515 -1.507,0.531 -0.003,0.012 0.388,0.597 0.886,1.324 0.49,0.716 0.888,1.308 0.886,1.314a96.945,96.945 0,0 1,-1.852 1.364c-0.006,0 -0.239,-0.317 -0.517,-0.705z"
|
||||
android:fillColor="#fafafa"/>
|
||||
</group>
|
||||
</vector>
|
4
app/src/flavorDandelior/res/values/strings-flavor.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">dandelior*</string>
|
||||
</resources>
|
BIN
app/src/main/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 29 KiB |
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
This file is part of the dandelion*.
|
||||
|
||||
Diaspora for Android is free software: you can redistribute it and/or modify
|
||||
dandelion* 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.
|
||||
|
||||
Diaspora for Android is distributed in the hope that it will be useful,
|
||||
dandelion* 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 the Diaspora for Android.
|
||||
along with the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
@ -23,30 +23,54 @@ import android.app.Application;
|
|||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.CookieSyncManager;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import com.github.dfa.diaspora_android.data.AppSettings;
|
||||
import com.github.dfa.diaspora_android.data.PodUserProfile;
|
||||
import com.github.dfa.diaspora_android.util.AvatarImageLoader;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaUserProfile;
|
||||
import com.github.dfa.diaspora_android.service.AvatarImageLoader;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
|
||||
public class App extends Application {
|
||||
public static final String TAG = "DIASPORA_";
|
||||
import net.gsantner.opoc.util.AdBlock;
|
||||
import net.gsantner.opoc.util.ContextUtils;
|
||||
import net.gsantner.opoc.util.ShareUtil;
|
||||
|
||||
public class App extends Application {
|
||||
private volatile static App app;
|
||||
private AppSettings appSettings;
|
||||
private AvatarImageLoader avatarImageLoader;
|
||||
private CookieManager cookieManager;
|
||||
private PodUserProfile podUserProfile;
|
||||
private DiasporaUserProfile diasporaUserProfile;
|
||||
|
||||
public static App get() {
|
||||
return app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
ShareUtil.setFileProviderAuthority(BuildConfig.APPLICATION_ID);
|
||||
app = this;
|
||||
final Context c = getApplicationContext();
|
||||
appSettings = new AppSettings(c);
|
||||
appSettings = AppSettings.get();
|
||||
|
||||
String a = new ContextUtils(this).bcstr("FLAVOR", "");
|
||||
a += "__";
|
||||
|
||||
if (appSettings.isAppFirstStart() && "flavorDandelior".equals(new ContextUtils(this).bcstr("FLAVOR", ""))) {
|
||||
appSettings.setAmoledColorMode(true);
|
||||
}
|
||||
|
||||
// Init app log
|
||||
AppLog.setLoggingEnabled(appSettings.isLoggingEnabled());
|
||||
AppLog.setLoggingSpamEnabled(appSettings.isLoggingSpamEnabled());
|
||||
|
||||
// Init pod profile
|
||||
avatarImageLoader = new AvatarImageLoader(c);
|
||||
podUserProfile = new PodUserProfile(this);
|
||||
diasporaUserProfile = new DiasporaUserProfile(this);
|
||||
|
||||
|
||||
// Get cookie manager
|
||||
|
@ -56,10 +80,12 @@ public class App extends Application {
|
|||
CookieSyncManager.createInstance(c);
|
||||
}
|
||||
cookieManager.setAcceptCookie(true);
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
AdBlock.getInstance().loadHostsFromRawAssetsAsync(this);
|
||||
}
|
||||
|
||||
public void resetPodData(@Nullable WebView webView){
|
||||
if(webView != null){
|
||||
public void resetPodData(@Nullable WebView webView) {
|
||||
if (webView != null) {
|
||||
webView.stopLoading();
|
||||
webView.loadUrl(DiasporaUrlHelper.URL_BLANK);
|
||||
webView.clearFormData();
|
||||
|
@ -70,8 +96,11 @@ public class App extends Application {
|
|||
// Clear avatar image
|
||||
new AvatarImageLoader(this).clearAvatarImage();
|
||||
|
||||
// Clear preferences
|
||||
appSettings.clearPodSettings();
|
||||
// Clear preferences__master
|
||||
appSettings.resetPodSettings();
|
||||
|
||||
// Clear User profile - reload empty AppSettingsBase data
|
||||
diasporaUserProfile.loadFromAppSettings();
|
||||
|
||||
// Clear cookies
|
||||
//noinspection deprecation
|
||||
|
@ -81,8 +110,8 @@ public class App extends Application {
|
|||
}
|
||||
}
|
||||
|
||||
public PodUserProfile getPodUserProfile(){
|
||||
return podUserProfile;
|
||||
public DiasporaUserProfile getDiasporaUserProfile() {
|
||||
return diasporaUserProfile;
|
||||
}
|
||||
|
||||
public AppSettings getSettings() {
|
||||
|
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.listener.IntellihideToolbarActivityListener;
|
||||
import com.github.dfa.diaspora_android.ui.HtmlTextView;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemeHelper;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedActivity;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedFragment;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* Activity that holds some fragments that show information about the app in a tab layout
|
||||
*/
|
||||
public class AboutActivity extends ThemedActivity
|
||||
implements IntellihideToolbarActivityListener {
|
||||
|
||||
@BindView(R.id.about__appbar)
|
||||
protected AppBarLayout _appBarLayout;
|
||||
|
||||
@BindView(R.id.main__topbar)
|
||||
protected Toolbar _toolbar;
|
||||
|
||||
@BindView(R.id.appbar_linear_layout)
|
||||
protected LinearLayout _linearLayout;
|
||||
|
||||
@BindView(R.id.tabs)
|
||||
protected TabLayout _tabLayout;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.about__activity);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
setSupportActionBar(_toolbar);
|
||||
_toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24px));
|
||||
_toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
AboutActivity.this.onBackPressed();
|
||||
}
|
||||
});
|
||||
// Create the adapter that will return a fragment for each of the three
|
||||
// primary sections of the activity.
|
||||
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
|
||||
|
||||
// Set up the ViewPager with the sections adapter.
|
||||
ViewPager mViewPager = ButterKnife.findById(this, R.id.container);
|
||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||
|
||||
_tabLayout.setupWithViewPager(mViewPager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setToolbarIntellihide(getAppSettings().isIntellihideToolbars());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyColorToViews() {
|
||||
ThemeHelper.updateToolbarColor(_toolbar);
|
||||
ThemeHelper.updateTabLayoutColor(_tabLayout);
|
||||
ThemeHelper.setPrimaryColorAsBackground(_linearLayout);
|
||||
}
|
||||
|
||||
public void setToolbarIntellihide(boolean enable) {
|
||||
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) _linearLayout.getLayoutParams();
|
||||
if (enable) {
|
||||
AppLog.d(this, "Enable Intellihide");
|
||||
params.setScrollFlags(toolbarDefaultScrollFlags);
|
||||
|
||||
} else {
|
||||
AppLog.d(this, "Disable Intellihide");
|
||||
params.setScrollFlags(0); // clear all scroll flags
|
||||
}
|
||||
_appBarLayout.setExpanded(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragment that shows general information about the app
|
||||
*/
|
||||
public static class AboutFragment extends ThemedFragment {
|
||||
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.AboutFragment";
|
||||
|
||||
@BindView(R.id.fragment_about__app_version)
|
||||
TextView appVersion;
|
||||
|
||||
@BindView(R.id.fragment_about__spread_the_word_text)
|
||||
HtmlTextView spreadText;
|
||||
|
||||
@BindView(R.id.fragment_about__contribute_button)
|
||||
Button contributeBtn;
|
||||
|
||||
@BindView(R.id.fragment_about__translate_button)
|
||||
Button translateBtn;
|
||||
|
||||
@BindView(R.id.fragment_about__feedback_button)
|
||||
Button feedbackBtn;
|
||||
|
||||
@BindView(R.id.fragment_about__spread_the_word_button)
|
||||
Button spreadBtn;
|
||||
|
||||
public AboutFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutResId() {
|
||||
return R.layout.about__fragment_about;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
ButterKnife.bind(this, view);
|
||||
if (isAdded()) {
|
||||
try {
|
||||
PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
|
||||
appVersion.setText(getString(R.string.app_version_with_arg, pInfo.versionName + " (" + pInfo.versionCode + ")"));
|
||||
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyColorToViews() {
|
||||
ThemeHelper.getInstance(getAppSettings());
|
||||
ThemeHelper.updateTextViewLinkColor(spreadText);
|
||||
ThemeHelper.updateButtonTextColor(contributeBtn);
|
||||
ThemeHelper.updateButtonTextColor(feedbackBtn);
|
||||
ThemeHelper.updateButtonTextColor(spreadBtn);
|
||||
ThemeHelper.updateButtonTextColor(translateBtn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@OnClick({R.id.fragment_about__contribute_button, R.id.fragment_about__translate_button, R.id.fragment_about__feedback_button, R.id.fragment_about__spread_the_word_button})
|
||||
public void buttonClicked(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.fragment_about__contribute_button:
|
||||
ContextUtils.get().openWebpageInExternalBrowser(getString(R.string.fragment_about__contribute_link));
|
||||
break;
|
||||
case R.id.fragment_about__translate_button:
|
||||
ContextUtils.get().openWebpageInExternalBrowser(getString(R.string.fragment_about__translate_link));
|
||||
break;
|
||||
case R.id.fragment_about__feedback_button:
|
||||
ContextUtils.get().openWebpageInExternalBrowser(getString(R.string.fragment_About__feedback_link));
|
||||
break;
|
||||
case R.id.fragment_about__spread_the_word_button:
|
||||
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.app_name));
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, getString(R.string.hey_checkout_dandelion_tag__appspecific, getString(R.string.fragment_about__fdroid_link)));
|
||||
startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.share_dotdotdot)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragment that shows information about the license of the app and used 3rd party libraries
|
||||
*/
|
||||
public static class LicenseFragment extends ThemedFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.LicenseFragment";
|
||||
|
||||
@BindView(R.id.fragment_license__maintainers_text)
|
||||
HtmlTextView maintainers;
|
||||
|
||||
@BindView(R.id.fragment_license__contributors_text)
|
||||
HtmlTextView contributors;
|
||||
|
||||
@BindView(R.id.fragment_license__thirdparty_libs_text)
|
||||
HtmlTextView thirdPartyLibs;
|
||||
|
||||
@BindView(R.id.fragment_license__license_button)
|
||||
Button licenseBtn;
|
||||
|
||||
@BindView(R.id.fragment_license__leafpic_button)
|
||||
Button leafpicBtn;
|
||||
|
||||
private String accentColor;
|
||||
|
||||
|
||||
public LicenseFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutResId() {
|
||||
return R.layout.about__fragment_license;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
ButterKnife.bind(this, view);
|
||||
accentColor = ContextUtils.get().colorToHexString(ThemeHelper.getAccentColor());
|
||||
|
||||
maintainers.setTextFormatted(getString(R.string.this_app_is_currently_developed_and_maintained_by_witharg,
|
||||
ContextUtils.get().loadMarkdownForTextViewFromRaw(R.raw.maintainers, "")));
|
||||
contributors.setTextFormatted(getString(R.string.thank_you_witharg,
|
||||
ContextUtils.get().loadMarkdownForTextViewFromRaw(R.raw.contributors, "")));
|
||||
thirdPartyLibs.setTextFormatted(
|
||||
ContextUtils.get().loadMarkdownForTextViewFromRaw(R.raw.licenses_3rd_party, ""));
|
||||
}
|
||||
|
||||
@OnClick({R.id.fragment_license__leafpic_button, R.id.fragment_license__license_button})
|
||||
public void buttonClicked(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.fragment_license__leafpic_button:
|
||||
ContextUtils.get().openWebpageInExternalBrowser(getString(R.string.fragment_licesen__misc_leafpic_link));
|
||||
break;
|
||||
case R.id.fragment_license__license_button:
|
||||
ContextUtils.get().openWebpageInExternalBrowser(getString(R.string.fragment_license__license_gpl_link));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyColorToViews() {
|
||||
ThemeHelper.getInstance(getAppSettings());
|
||||
ThemeHelper.updateButtonTextColor(leafpicBtn);
|
||||
ThemeHelper.updateButtonTextColor(licenseBtn);
|
||||
ThemeHelper.updateTextViewLinkColor(maintainers);
|
||||
ThemeHelper.updateTextViewLinkColor(thirdPartyLibs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragment that shows debug information like app version, pod version...
|
||||
*/
|
||||
public static class DebugFragment extends Fragment implements Observer {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.DebugFragment";
|
||||
|
||||
@BindView(R.id.fragment_debug__package_name)
|
||||
TextView packageName;
|
||||
|
||||
@BindView(R.id.fragment_debug__app_version)
|
||||
TextView appVersion;
|
||||
|
||||
@BindView(R.id.fragment_debug__android_version)
|
||||
TextView osVersion;
|
||||
|
||||
@BindView(R.id.fragment_debug__device_name)
|
||||
TextView deviceName;
|
||||
|
||||
@BindView(R.id.fragment_debug__account_profile_name)
|
||||
TextView podName;
|
||||
|
||||
@BindView(R.id.fragment_debug__account_profile_domain)
|
||||
TextView podDomain;
|
||||
|
||||
@BindView(R.id.fragment_debug__log_box)
|
||||
TextView logBox;
|
||||
|
||||
public DebugFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.about__fragment_debug, container, false);
|
||||
ButterKnife.bind(this, rootView);
|
||||
App app = (App) getActivity().getApplication();
|
||||
logBox.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (isAdded()) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("DEBUG_LOG", AppLog.Log.getLogBuffer());
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(DebugFragment.this.getActivity(), R.string.debug_log_copied_to_clipboard, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
AppLog.d(this, "Not Added!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
AppLog.Log.addLogObserver(this);
|
||||
update(AppLog.Log.getInstance(), null);
|
||||
|
||||
if (isAdded()) {
|
||||
try {
|
||||
PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
|
||||
AppSettings appSettings = ((App) getActivity().getApplication()).getSettings();
|
||||
packageName.setText(pInfo.packageName);
|
||||
appVersion.setText(getString(R.string.app_version_with_arg, pInfo.versionName + " (" + pInfo.versionCode + ")"));
|
||||
|
||||
osVersion.setText(getString(R.string.android_version_witharg, Build.VERSION.RELEASE));
|
||||
deviceName.setText(getString(R.string.device_name_witharg, Build.MANUFACTURER + " " + Build.MODEL));
|
||||
if (app.getSettings().getPod() != null) {
|
||||
podDomain.setText(getString(R.string.pod_domain_witharg__appspecific, app.getSettings().getPod().getPodUrl()));
|
||||
podName.setText(getString(R.string.pod_profile_name_witharg__appspecific, app.getSettings().getPod().getName()));
|
||||
}
|
||||
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
AppLog.Log.removeLogObserver(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable observable, Object o) {
|
||||
if (logBox != null) {
|
||||
logBox.setText(AppLog.Log.getLogBuffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
||||
* one of the sections/tabs/pages.
|
||||
*/
|
||||
public class SectionsPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
public SectionsPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0: //About
|
||||
return new AboutFragment();
|
||||
case 1: //License
|
||||
return new LicenseFragment();
|
||||
case 2: //Debug
|
||||
default:
|
||||
return new DebugFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
// Show 3 total pages.
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return getString(R.string.about);
|
||||
case 1:
|
||||
return getString(R.string.license);
|
||||
case 2:
|
||||
return getString(R.string.debugging);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.BuildConfig;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaUserProfile;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedAlertDialogBuilder;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
import com.github.dfa.diaspora_android.web.BrowserFragment;
|
||||
import com.github.dfa.diaspora_android.web.DiasporaStreamWebChromeClient;
|
||||
import com.github.dfa.diaspora_android.web.FileUploadWebChromeClient;
|
||||
import com.github.dfa.diaspora_android.web.WebHelper;
|
||||
|
||||
import net.gsantner.opoc.util.PermissionChecker;
|
||||
import net.gsantner.opoc.util.ShareUtil;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Fragment that displays the Stream of the diaspora* user
|
||||
* Created by vanitas on 26.09.16.
|
||||
*/
|
||||
|
||||
public class DiasporaStreamFragment extends BrowserFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.StreamFragment";
|
||||
|
||||
protected DiasporaUrlHelper urls;
|
||||
|
||||
private ValueCallback<Uri[]> imageUploadFilePathCallbackNew;
|
||||
private ValueCallback<Uri> imageUploadFilePathCallbackOld;
|
||||
private String mCameraPhotoPath;
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
this.urls = new DiasporaUrlHelper(appSettings);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
webView.setWebChromeClient(new DiasporaStreamWebChromeClient(webView, progressBar, fileUploadCallback, sharedTextCallback));
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
webView.addJavascriptInterface(new JavaScriptInterface(), "AndroidBridge");
|
||||
if (((MainActivity) getActivity()).getTextToBeShared() != null) {
|
||||
loadUrl(urls.getNewPostUrl());
|
||||
} else if (webView.getUrl() == null) {
|
||||
loadUrl(urls.getStreamUrl());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.stream__menu_top, menu);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
menu.findItem(R.id.action_share_pdf).setVisible(true);
|
||||
}
|
||||
|
||||
final boolean darkBg = ContextUtils.get().shouldColorOnTopBeLight(AppSettings.get().getPrimaryColor());
|
||||
ContextUtils.get().tintMenuItems(menu, true, ContextCompat.getColor(getActivity(), darkBg ? R.color.white : R.color.black));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
AppLog.d(this, "onActivityResult(): " + requestCode);
|
||||
switch (requestCode) {
|
||||
case MainActivity.INPUT_FILE_REQUEST_CODE_NEW:
|
||||
case MainActivity.INPUT_FILE_REQUEST_CODE_OLD:
|
||||
AppLog.v(this, "INPUT_FILE_REQUEST_CODE: " + requestCode);
|
||||
onImageUploadResult(requestCode, resultCode, data);
|
||||
return;
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
AppLog.d(this, "StreamFragment.onOptionsItemSelected()");
|
||||
ShareUtil shu = new ShareUtil(getContext());
|
||||
PermissionChecker permc = new PermissionChecker(getActivity());
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_reload: {
|
||||
if (WebHelper.isOnline(getContext())) {
|
||||
reloadUrl();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case R.id.action_go_to_top: {
|
||||
ObjectAnimator anim = ObjectAnimator.ofInt(webView, "scrollY", webView.getScrollY(), 0);
|
||||
anim.setDuration(400);
|
||||
anim.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_share_link: {
|
||||
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, webView.getTitle());
|
||||
sharingIntent.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
|
||||
startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.share_dotdotdot)));
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_share_pdf: {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
shu.createPdf(webView, "dandelion-" + ShareUtil.SDF_SHORT.format(new Date()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_share_link_to_clipboard: {
|
||||
shu.setClipboard(webView.getUrl());
|
||||
Toast.makeText(getContext(), R.string.link_adress_copied, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_create_launcher_shortcut: {
|
||||
if (webView.getUrl() != null) {
|
||||
Intent intent = new Intent(getContext(), MainActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(webView.getUrl()));
|
||||
shu.createLauncherDesktopShortcut(intent, R.drawable.ic_launcher, webView.getTitle());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_take_screenshot: {
|
||||
if (permc.doIfExtStoragePermissionGranted(getString(R.string.screenshot_permission__appspecific))) {
|
||||
File fileSaveDirectory = appSettings.getAppSaveDirectory();
|
||||
if (permc.mkdirIfStoragePermissionGranted(fileSaveDirectory)) {
|
||||
Bitmap bmp = ShareUtil.getBitmapFromWebView(webView);
|
||||
String filename = "dandelion-" + ShareUtil.SDF_SHORT.format(new Date()) + ".jpg";
|
||||
_cu.writeImageToFile(new File(fileSaveDirectory, filename), bmp);
|
||||
Snackbar.make(webView, getString(R.string.saving_screenshot_as)
|
||||
+ " " + filename, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.action_share_screenshot: {
|
||||
if (permc.doIfExtStoragePermissionGranted(getString(R.string.screenshot_permission__appspecific))) {
|
||||
shu.shareImage(ShareUtil.getBitmapFromWebView(webView));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void onImageUploadResult(int requestCode, int resultCode, Intent data) {
|
||||
AppLog.d(this, "onImageUploadResult");
|
||||
switch (requestCode) {
|
||||
case MainActivity.INPUT_FILE_REQUEST_CODE_NEW: {
|
||||
AppLog.v(this, "Upload image using recent method (Lollipop+)");
|
||||
if (imageUploadFilePathCallbackNew == null || resultCode != Activity.RESULT_OK) {
|
||||
AppLog.e(this, "Callback is null: " + (imageUploadFilePathCallbackNew == null)
|
||||
+ " resultCode: " + resultCode);
|
||||
if (imageUploadFilePathCallbackNew != null)
|
||||
imageUploadFilePathCallbackNew.onReceiveValue(new Uri[]{});
|
||||
return;
|
||||
}
|
||||
Uri[] results = null;
|
||||
if (data == null) {
|
||||
if (mCameraPhotoPath != null) {
|
||||
AppLog.v(this, "Intent data is null. Try to parse cameraPhotoPath");
|
||||
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
|
||||
} else {
|
||||
AppLog.w(this, "Intent data is null and cameraPhotoPath is null");
|
||||
}
|
||||
} else {
|
||||
String dataString = data.getDataString();
|
||||
if (dataString != null) {
|
||||
AppLog.v(this, "Intent has data. Try to parse dataString");
|
||||
results = new Uri[]{Uri.parse(dataString)};
|
||||
} else {
|
||||
AppLog.w(this, "dataString is null");
|
||||
}
|
||||
}
|
||||
AppLog.v(this, "handle received result over to callback");
|
||||
imageUploadFilePathCallbackNew.onReceiveValue(results);
|
||||
imageUploadFilePathCallbackNew = null;
|
||||
return;
|
||||
}
|
||||
case MainActivity.INPUT_FILE_REQUEST_CODE_OLD: {
|
||||
AppLog.v(this, "Upload image using legacy method (Jelly Bean, Kitkat)");
|
||||
if (imageUploadFilePathCallbackOld == null || resultCode != Activity.RESULT_OK) {
|
||||
AppLog.e(this, "Callback is null: " + (imageUploadFilePathCallbackOld == null)
|
||||
+ " resultCode: " + resultCode);
|
||||
if (imageUploadFilePathCallbackOld != null)
|
||||
imageUploadFilePathCallbackOld.onReceiveValue(null);
|
||||
return;
|
||||
}
|
||||
Uri results = null;
|
||||
if (data == null) {
|
||||
if (mCameraPhotoPath != null) {
|
||||
AppLog.v(this, "Intent has no data. Try to parse cameraPhotoPath");
|
||||
results = Uri.parse(mCameraPhotoPath);
|
||||
} else {
|
||||
AppLog.w(this, "Intent has no data and cameraPhotoPath is null");
|
||||
}
|
||||
} else {
|
||||
String dataString = data.getDataString();
|
||||
if (dataString != null) {
|
||||
AppLog.v(this, "Intent has data. Try to parse dataString");
|
||||
results = Uri.parse(dataString);
|
||||
} else {
|
||||
AppLog.w(this, "dataString is null");
|
||||
}
|
||||
}
|
||||
AppLog.v(this, "handle received result over to callback");
|
||||
imageUploadFilePathCallbackOld.onReceiveValue(results);
|
||||
imageUploadFilePathCallbackOld = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected DiasporaStreamWebChromeClient.SharedTextCallback sharedTextCallback = new DiasporaStreamWebChromeClient.SharedTextCallback() {
|
||||
@Override
|
||||
public String getSharedText() {
|
||||
if (getActivity() != null) {
|
||||
return ((MainActivity) getActivity()).getTextToBeShared();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSharedText(String shared) {
|
||||
((MainActivity) getActivity()).setTextToBeShared(shared);
|
||||
}
|
||||
};
|
||||
|
||||
protected FileUploadWebChromeClient.FileUploadCallback fileUploadCallback = new FileUploadWebChromeClient.FileUploadCallback() {
|
||||
@Override
|
||||
public boolean imageUpload(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
int hasWRITE_EXTERNAL_STORAGE = getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (hasWRITE_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) {
|
||||
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
new ThemedAlertDialogBuilder(getContext(), appSettings)
|
||||
.setMessage(R.string.image_permission_description__appspecific)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 23)
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
MainActivity.REQUEST_CODE_ASK_PERMISSIONS);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
return false;
|
||||
}
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
MainActivity.REQUEST_CODE_ASK_PERMISSIONS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
AppLog.v(this, "onOpenFileChooser");
|
||||
imageUploadFilePathCallbackNew = filePathCallback;
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(getContext().getPackageManager()) != null) {
|
||||
// Create the File where the photo should go
|
||||
File photoFile;
|
||||
try {
|
||||
photoFile = ContextUtils.get().createImageFile();
|
||||
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
|
||||
} catch (IOException ex) {
|
||||
AppLog.e(this, "ERROR creating temp file: " + ex.toString());
|
||||
// Error occurred while creating the File
|
||||
Snackbar.make(webView, R.string.unable_to_load_image, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
// Continue only if the File was successfully created
|
||||
if (photoFile != null) {
|
||||
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||
Uri.fromFile(photoFile));
|
||||
} else {
|
||||
takePictureIntent = null;
|
||||
}
|
||||
}
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
contentSelectionIntent.setType("image/*");
|
||||
Intent[] intentArray;
|
||||
if (takePictureIntent != null) {
|
||||
intentArray = new Intent[]{takePictureIntent};
|
||||
} else {
|
||||
intentArray = new Intent[0];
|
||||
}
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
AppLog.d(this, "startActivityForResult");
|
||||
startActivityForResult(chooserIntent, MainActivity.INPUT_FILE_REQUEST_CODE_NEW);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void legacyImageUpload(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
|
||||
AppLog.v(this, "openFileChooser(ValCallback<Uri>, String, String");
|
||||
imageUploadFilePathCallbackOld = uploadMsg;
|
||||
Intent intent = new Intent();
|
||||
intent.setType("image/*");
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
intent.putExtra("return-data", true);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
AppLog.v(this, "startActivityForResult");
|
||||
startActivityForResult(Intent.createChooser(intent, "Select Picture"), MainActivity.INPUT_FILE_REQUEST_CODE_OLD);
|
||||
}
|
||||
};
|
||||
|
||||
private class JavaScriptInterface {
|
||||
@SuppressWarnings("unused")
|
||||
@JavascriptInterface
|
||||
public void setUserProfile(final String webMessage) throws JSONException {
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
App app = ((App) activity.getApplication());
|
||||
final DiasporaUserProfile pup = app.getDiasporaUserProfile();
|
||||
if (pup.isRefreshNeeded()) {
|
||||
try {
|
||||
// Try to very fail-safe check if user information gets really loaded from correct pod
|
||||
if (!webView.getUrl().startsWith(app.getSettings().getPod().getPodUrl().getBaseUrl())) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
return;
|
||||
}
|
||||
AppLog.v(this, "DiasporaUserProfile needs refresh; Try to parse JSON");
|
||||
pup.parseJson(webMessage);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
pup.analyzeUrl(webView.getUrl());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@JavascriptInterface
|
||||
public void contentHasBeenShared() {
|
||||
if (getActivity() != null) {
|
||||
((MainActivity) getActivity()).setTextToBeShared(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.util.Linkify;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.CookieManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.task.GetPodsService;
|
||||
import com.github.dfa.diaspora_android.util.Helpers;
|
||||
import com.github.dfa.diaspora_android.util.WebHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.OnItemClick;
|
||||
|
||||
|
||||
public class PodSelectionActivity extends AppCompatActivity {
|
||||
private App app;
|
||||
|
||||
@BindView(R.id.podselection__edit_filter)
|
||||
public EditText editFilter;
|
||||
|
||||
@BindView(R.id.podselection__listpods)
|
||||
public ListView listPods;
|
||||
|
||||
@BindView(R.id.toolbar)
|
||||
public Toolbar toolbar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.podselection__activity);
|
||||
ButterKnife.bind(this);
|
||||
app = (App) getApplication();
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
|
||||
listPods.setTextFilterEnabled(true);
|
||||
setListedPods(app.getSettings().getPreviousPodlist());
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(podListReceiver, new IntentFilter(GetPodsService.MESSAGE_PODS_RECEIVED));
|
||||
|
||||
if (!WebHelper.isOnline(PodSelectionActivity.this)) {
|
||||
Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final BroadcastReceiver podListReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.hasExtra("pods")) {
|
||||
Bundle extras = intent.getExtras();
|
||||
String[] pods = extras.getStringArray("pods");
|
||||
if (pods != null && pods.length > 0) {
|
||||
app.getSettings().setPreviousPodlist(pods);
|
||||
setListedPods(pods);
|
||||
} else {
|
||||
setListedPods(app.getSettings().getPreviousPodlist());
|
||||
Snackbar.make(listPods, R.string.podlist_error, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@OnClick(R.id.podselection__button_select_pod)
|
||||
public void onButtonSelectPodClicked(View view) {
|
||||
if (editFilter.getText().length() > 4 && editFilter.getText().toString().contains("")) {
|
||||
showPodConfirmationDialog(editFilter.getText().toString());
|
||||
} else {
|
||||
Snackbar.make(listPods, R.string.valid_pod, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Intent i = new Intent(PodSelectionActivity.this, GetPodsService.class);
|
||||
startService(i);
|
||||
}
|
||||
|
||||
|
||||
private void setListedPods(String[] listedPodsArr) {
|
||||
final ArrayList<String> listedPodsList = new ArrayList<>();
|
||||
for (String pod : listedPodsArr) {
|
||||
listedPodsList.add(pod.toLowerCase());
|
||||
}
|
||||
|
||||
final ArrayAdapter<String> adapter = new ArrayAdapter<>(
|
||||
PodSelectionActivity.this,
|
||||
android.R.layout.simple_list_item_1,
|
||||
listedPodsList);
|
||||
|
||||
// save index and top position
|
||||
int index = listPods.getFirstVisiblePosition();
|
||||
View v = listPods.getChildAt(0);
|
||||
int top = (v == null) ? 0 : (v.getTop() - listPods.getPaddingTop());
|
||||
listPods.setAdapter(adapter);
|
||||
listPods.setSelectionFromTop(index, top);
|
||||
|
||||
adapter.getFilter().filter(editFilter.getText());
|
||||
editFilter.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
(adapter).getFilter().filter(s.toString());
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@OnItemClick(R.id.podselection__listpods)
|
||||
public void onListPodsItemClicked(int position) {
|
||||
showPodConfirmationDialog((String) listPods.getAdapter().getItem(position));
|
||||
}
|
||||
|
||||
private void showPodConfirmationDialog(final String selectedPod) {
|
||||
// Make a clickable link
|
||||
final SpannableString dialogMessage = new SpannableString(getString(R.string.confirm_pod, selectedPod));
|
||||
Linkify.addLinks(dialogMessage, Linkify.ALL);
|
||||
|
||||
// Check if online
|
||||
if (!WebHelper.isOnline(PodSelectionActivity.this)) {
|
||||
Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
new AlertDialog.Builder(PodSelectionActivity.this)
|
||||
.setTitle(getString(R.string.confirmation))
|
||||
.setMessage(dialogMessage)
|
||||
.setPositiveButton(android.R.string.yes,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
onPodSelectionConfirmed(selectedPod);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
public void onPodSelectionConfirmed(String selectedPod) {
|
||||
app.getSettings().setPodDomain(selectedPod);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
try {
|
||||
CookieManager.getInstance().removeAllCookies(null);
|
||||
CookieManager.getInstance().removeSessionCookies(null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
CookieManager.getInstance().removeSessionCookie();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Helpers.animateToActivity(this, MainActivity.class, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
Snackbar.make(listPods, R.string.confirm_exit, Snackbar.LENGTH_LONG)
|
||||
.setAction(android.R.string.yes, new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
finish();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(podListReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.pods__menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_reload: {
|
||||
if (WebHelper.isOnline(PodSelectionActivity.this)) {
|
||||
Intent i = new Intent(PodSelectionActivity.this, GetPodsService.class);
|
||||
startService(i);
|
||||
return true;
|
||||
} else {
|
||||
Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.widget.AppCompatButton;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaPodList;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaPodList.DiasporaPod;
|
||||
import com.github.dfa.diaspora_android.service.FetchPodsService;
|
||||
import com.github.dfa.diaspora_android.ui.PodSelectionDialog;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedFragment;
|
||||
import com.github.dfa.diaspora_android.util.ActivityUtils;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* Fragment that lets the user choose a Pod
|
||||
* Created by vanitas on 01.10.16.
|
||||
*/
|
||||
|
||||
public class PodSelectionFragment extends ThemedFragment implements SearchView.OnQueryTextListener, PodSelectionDialog.PodSelectionDialogResultListener {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.PodSelectionFragment";
|
||||
|
||||
@BindView(R.id.podselection__fragment__listpods)
|
||||
protected ListView listViewPod;
|
||||
|
||||
@BindView(R.id.podselection__fragment__root)
|
||||
RelativeLayout rootView;
|
||||
|
||||
@BindView(R.id.podselection__fragment__button_use_custom_pod)
|
||||
AppCompatButton buttonUseCustomPod;
|
||||
|
||||
|
||||
protected App app;
|
||||
protected AppSettings appSettings;
|
||||
private DiasporaPodList podList;
|
||||
private ArrayAdapter<String> listViewPodAdapter;
|
||||
private String filterString = "";
|
||||
|
||||
@Override
|
||||
protected int getLayoutResId() {
|
||||
return R.layout.podselection__fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
ButterKnife.bind(this, view);
|
||||
app = (App) getActivity().getApplication();
|
||||
appSettings = app.getSettings();
|
||||
|
||||
// Load local podlist
|
||||
podList = new DiasporaPodList();
|
||||
mergePodlistWithRessources(podList);
|
||||
podList.setTrackMergeChanges(true);
|
||||
updateListedPods();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
listViewPod.setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
listViewPod.setTextFilterEnabled(true);
|
||||
listViewPod.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
String text = ((TextView) view).getText().toString();
|
||||
for (DiasporaPod pod : podList) {
|
||||
if (pod.getPodUrl().getHost().equals(text)) {
|
||||
showPodSelectionDialog(pod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
LocalBroadcastManager.getInstance(getContext()).registerReceiver(podListReceiver, new IntentFilter(FetchPodsService.MESSAGE_PODS_RECEIVED));
|
||||
ActivityUtils.get(getActivity()).showInfoIfUserNotConnectedToInternet(listViewPod);
|
||||
}
|
||||
|
||||
public void mergePodlistWithRessources(DiasporaPodList podlist) {
|
||||
String sPodlist = ContextUtils.get().readTextfileFromRawRes(R.raw.podlist, "", "");
|
||||
try {
|
||||
JSONObject jPodlist = new JSONObject(sPodlist);
|
||||
podlist.mergeWithNewerEntries(new DiasporaPodList().fromJson(jPodlist));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.podselection__fragment__button_use_custom_pod)
|
||||
public void onPodButtonClicked(View v) {
|
||||
showPodSelectionDialog(new DiasporaPod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
private final BroadcastReceiver podListReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.hasExtra(FetchPodsService.EXTRA_PODLIST)) {
|
||||
Bundle extras = intent.getExtras();
|
||||
DiasporaPodList newPods = (DiasporaPodList) extras.get(FetchPodsService.EXTRA_PODLIST);
|
||||
if (newPods != null && newPods.getPods().size() > 0) {
|
||||
try {
|
||||
podList.mergeWithNewerEntries(newPods);
|
||||
updateListedPods();
|
||||
} catch (JSONException ignored) {
|
||||
}
|
||||
} else {
|
||||
Snackbar.make(listViewPod, R.string.could_not_retrieve_list_of_pods__appspecific, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void applyColorToViews() {
|
||||
int dividerHeight = listViewPod.getDividerHeight();
|
||||
rootView.setBackgroundColor(appSettings.isAmoledColorMode() ? Color.BLACK : Color.WHITE);
|
||||
listViewPod.setDivider(new ColorDrawable(Color.GRAY));
|
||||
listViewPod.setDividerHeight(dividerHeight);
|
||||
int bgcolor = appSettings.isAmoledColorMode() ? Color.DKGRAY : appSettings.getAccentColor();
|
||||
buttonUseCustomPod.setBackgroundColor(bgcolor);
|
||||
buttonUseCustomPod.setTextColor(_cu.shouldColorOnTopBeLight(bgcolor) ? Color.WHITE : Color.BLACK);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Intent i = new Intent(getContext(), FetchPodsService.class);
|
||||
getContext().startService(i);
|
||||
}
|
||||
|
||||
private void updateListedPods() {
|
||||
final ArrayList<String> listedPodsList = new ArrayList<>();
|
||||
for (DiasporaPod pod : this.podList) {
|
||||
listedPodsList.add(pod.getPodUrl().getHost());
|
||||
}
|
||||
|
||||
listViewPodAdapter = new ArrayAdapter<String>(
|
||||
getContext(),
|
||||
android.R.layout.simple_list_item_1,
|
||||
listedPodsList) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = super.getView(position, convertView, parent);
|
||||
TextView textView = view.findViewById(android.R.id.text1);
|
||||
textView.setTextColor(appSettings.isAmoledColorMode() ? Color.GRAY : Color.BLACK);
|
||||
return view;
|
||||
}
|
||||
};
|
||||
|
||||
// save index and top position
|
||||
int index = listViewPod.getFirstVisiblePosition();
|
||||
View v = listViewPod.getChildAt(0);
|
||||
int top = (v == null) ? 0 : (v.getTop() - listViewPod.getPaddingTop());
|
||||
listViewPod.setAdapter(listViewPodAdapter);
|
||||
listViewPod.setSelectionFromTop(index, top);
|
||||
|
||||
listViewPodAdapter.getFilter().filter(filterString);
|
||||
}
|
||||
|
||||
private void showPodSelectionDialog(final DiasporaPod selectedPod) {
|
||||
PodSelectionDialog dialog = PodSelectionDialog.newInstance(selectedPod, this);
|
||||
dialog.show(getFragmentManager(), PodSelectionDialog.TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(podListReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.podselection__menu, menu);
|
||||
|
||||
MenuItem searchItem = menu.findItem(R.id.podselection__action_search);
|
||||
if (searchItem != null) {
|
||||
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
|
||||
searchView.setOnQueryTextListener(this);
|
||||
}
|
||||
|
||||
final boolean darkBg = ContextUtils.get().shouldColorOnTopBeLight(AppSettings.get().getPrimaryColor());
|
||||
ContextUtils.get().tintMenuItems(menu, true, ContextCompat.getColor(getActivity(), darkBg ? R.color.white : R.color.black));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_reload: {
|
||||
if (!ActivityUtils.get(getActivity()).showInfoIfUserNotConnectedToInternet(listViewPod)) {
|
||||
Intent i = new Intent(getContext(), FetchPodsService.class);
|
||||
getContext().startService(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
if (listViewPodAdapter != null) {
|
||||
(listViewPodAdapter).getFilter().filter(newText);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPodSelectionDialogResult(DiasporaPod pod, boolean accepted) {
|
||||
System.out.println(accepted + ": " + pod.toString());
|
||||
if (accepted) {
|
||||
app.getSettings().setPod(pod);
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().removeAllCookies(null);
|
||||
CookieManager.getInstance().removeSessionCookies(null);
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
//noinspection deprecation
|
||||
CookieManager.getInstance().removeSessionCookie();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
MainActivity mainActivity = (MainActivity) getActivity();
|
||||
DiasporaUrlHelper urlHelper = new DiasporaUrlHelper(appSettings);
|
||||
mainActivity.onPodSelectionDialogResult(pod, accepted);
|
||||
mainActivity.openDiasporaUrl(urlHelper.getSignInUrl());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dummy implementations
|
||||
*/
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedIntellihide() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,122 +1,232 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ColorPalette;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemeHelper;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedActivity;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedAlertDialogBuilder;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedPreferenceFragment;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
import com.github.dfa.diaspora_android.web.ProxyHandler;
|
||||
|
||||
/**
|
||||
* @author vanitas
|
||||
*/
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
private boolean activityRestartRequired;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import uz.shift.colorpicker.LineColorPicker;
|
||||
import uz.shift.colorpicker.OnColorChangedListener;
|
||||
|
||||
public class SettingsActivity extends ThemedActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
//Toolbar
|
||||
@BindView(R.id.settings__appbar)
|
||||
protected AppBarLayout appBarLayout;
|
||||
|
||||
@BindView(R.id.settings__toolbar)
|
||||
protected Toolbar toolbar;
|
||||
|
||||
private ProxyHandler.ProxySettings oldProxySettings;
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
setContentView(R.layout.settings__activity);
|
||||
ButterKnife.bind(this);
|
||||
toolbar.setTitle(R.string.settings);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24px));
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SettingsActivity.this.onBackPressed();
|
||||
}
|
||||
});
|
||||
getAppSettings().registerPreferenceChangedListener(this);
|
||||
oldProxySettings = getAppSettings().getProxySettings();
|
||||
showFragment(SettingsFragmentMaster.TAG, false);
|
||||
}
|
||||
|
||||
protected void showFragment(String tag, boolean addToBackStack) {
|
||||
PreferenceFragment fragment = (PreferenceFragment) getFragmentManager().findFragmentByTag(tag);
|
||||
if (fragment == null) {
|
||||
switch (tag) {
|
||||
case SettingsFragmentThemes.TAG:
|
||||
fragment = new SettingsFragmentThemes();
|
||||
break;
|
||||
case SettingsFragmentNavSlider.TAG:
|
||||
fragment = new SettingsFragmentNavSlider();
|
||||
break;
|
||||
case SettingsFragmentProxy.TAG:
|
||||
fragment = new SettingsFragmentProxy();
|
||||
break;
|
||||
case SettingsFragmentDebugging.TAG:
|
||||
fragment = new SettingsFragmentDebugging();
|
||||
break;
|
||||
case SettingsFragmentMaster.TAG:
|
||||
default:
|
||||
fragment = new SettingsFragmentMaster();
|
||||
break;
|
||||
}
|
||||
}
|
||||
FragmentTransaction t = getFragmentManager().beginTransaction();
|
||||
if (addToBackStack) {
|
||||
t.addToBackStack(tag);
|
||||
}
|
||||
t.replace(R.id.settings__fragment_container, fragment, tag).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
|
||||
public void applyColorToViews() {
|
||||
//Toolbar
|
||||
ThemeHelper.updateToolbarColor(toolbar);
|
||||
}
|
||||
|
||||
public void setActivityRestartRequired(boolean b) {
|
||||
this.activityRestartRequired = b;
|
||||
@Override
|
||||
protected void onStop() {
|
||||
ProxyHandler.ProxySettings newProxySettings = getAppSettings().getProxySettings();
|
||||
if (!oldProxySettings.equals(newProxySettings)) {
|
||||
AppLog.d(this, "ProxySettings changed.");
|
||||
//Proxy on-off? => Restart app
|
||||
if (oldProxySettings.isEnabled() && !newProxySettings.isEnabled()) {
|
||||
AppLog.d(this, "Proxy deactivated. Restarting app...");
|
||||
Intent restartActivity = new Intent(SettingsActivity.this, MainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(SettingsActivity.this, 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
AlarmManager mgr = (AlarmManager) SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
|
||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
|
||||
System.exit(0);
|
||||
} //Proxy changed? => Update
|
||||
else {
|
||||
ProxyHandler.getInstance().updateProxySettings(this);
|
||||
}
|
||||
}
|
||||
getAppSettings().unregisterPreferenceChangedListener(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
sharedPreferences = getPreferenceScreen().getSharedPreferences();
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
setPreferenceSummaries();
|
||||
sharedPreferences.edit().putBoolean(getString(R.string.pref_key__proxy_was_enabled),
|
||||
sharedPreferences.getBoolean(getString(R.string.pref_key__proxy_enabled), false)).apply();
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
ThemedPreferenceFragment top = getTopFragment();
|
||||
if (top != null && top.getFragmentTag().equals(SettingsFragmentProxy.TAG)) {
|
||||
ProxyHandler.ProxySettings newProxySettings = getAppSettings().getProxySettings();
|
||||
if (oldProxySettings.isEnabled() && !newProxySettings.isEnabled()) {
|
||||
Toast.makeText(this, R.string.app_needs_restart_to_disable_proxy_usage, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
private void setPreferenceSummaries() {
|
||||
String[] editTextKeys = new String[]{
|
||||
getString(R.string.pref_key__proxy_host), getString(R.string.pref_key__proxy_port)
|
||||
};
|
||||
for (String key : editTextKeys) {
|
||||
EditTextPreference p = (EditTextPreference) findPreference(key);
|
||||
p.setSummary(p.getText());
|
||||
}
|
||||
/**
|
||||
* Return the fragment which is currently displayed in R.id.fragment_container
|
||||
*
|
||||
* @return top fragment or null if there is none displayed
|
||||
*/
|
||||
private ThemedPreferenceFragment getTopFragment() {
|
||||
return (ThemedPreferenceFragment) getFragmentManager().findFragmentById(R.id.settings__fragment_container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
updatePreference(findPreference(key));
|
||||
if (key.equals(getString(R.string.pref_key__screen_rotation))) {
|
||||
this.updateScreenRotation();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePreference(Preference preference) {
|
||||
if (preference == null) {
|
||||
return;
|
||||
}
|
||||
if (preference instanceof EditTextPreference) {
|
||||
EditTextPreference textPref = (EditTextPreference) preference;
|
||||
textPref.setSummary(textPref.getText());
|
||||
return;
|
||||
}
|
||||
if (preference instanceof ListPreference) {
|
||||
ListPreference listPref = (ListPreference) preference;
|
||||
listPref.setSummary(listPref.getEntry());
|
||||
public static class SettingsFragmentMaster extends ThemedPreferenceFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.settings.SettingsFragmentMaster";
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences__master);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewColors() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
|
||||
if (isAdded() && preference.hasKey()) {
|
||||
AppSettings settings = ((App) getActivity().getApplication()).getSettings();
|
||||
DiasporaUrlHelper diasporaUrlHelper = new DiasporaUrlHelper(settings);
|
||||
String key = preference.getKey();
|
||||
/** Sub-Categories */
|
||||
if (settings.isKeyEqual(key, R.string.pref_key__cat_themes)) {
|
||||
((SettingsActivity) getActivity()).showFragment(SettingsFragmentThemes.TAG, true);
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__cat_nav_slider)) {
|
||||
((SettingsActivity) getActivity()).showFragment(SettingsFragmentNavSlider.TAG, true);
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__cat_proxy)) {
|
||||
((SettingsActivity) getActivity()).showFragment(SettingsFragmentProxy.TAG, true);
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__cat_debugging)) {
|
||||
((SettingsActivity) getActivity()).showFragment(SettingsFragmentDebugging.TAG, true);
|
||||
return true;
|
||||
}
|
||||
/** Usability */
|
||||
else if (settings.isKeyEqual(key, R.string.pref_key__is_overview_statusbar_hidden)) {
|
||||
AppSettings.get().setRecreateMainActivity(true);
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__language)) {
|
||||
AppSettings.get().setRecreateMainActivity(true);
|
||||
}
|
||||
/** Network */
|
||||
else if (settings.isKeyEqual(key, R.string.pref_key__clear_cache)) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
String podDomain = ((App) getActivity().getApplication()).getSettings().getPodDomain();
|
||||
switch (preference.getTitleRes()) {
|
||||
case R.string.pref_title__personal_settings: {
|
||||
intent.setAction(MainActivity.ACTION_OPEN_URL);
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, "https://" + podDomain + "/user/edit");
|
||||
break;
|
||||
intent.setAction(MainActivity.ACTION_CLEAR_CACHE);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
}
|
||||
case R.string.pref_title__manage_tags: {
|
||||
/** Pod Settings */
|
||||
if (settings.isKeyEqual(key, R.string.pref_key__personal_settings)) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.setAction(MainActivity.ACTION_OPEN_URL);
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, "https://" + podDomain + "/tag_followings/manage");
|
||||
break;
|
||||
}
|
||||
case R.string.pref_title__manage_contacts: {
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getPersonalSettingsUrl());
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__manage_tags)) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.setAction(MainActivity.ACTION_OPEN_URL);
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, "https://" + podDomain + "/contacts");
|
||||
break;
|
||||
}
|
||||
case R.string.pref_title__change_account: {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getManageTagsUrl());
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__manage_contacts)) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.setAction(MainActivity.ACTION_OPEN_URL);
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getContactsUrl());
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
} else if (settings.isKeyEqual(key, R.string.pref_key__change_account)) {
|
||||
new ThemedAlertDialogBuilder(getActivity(), AppSettings.get())
|
||||
.setTitle(getString(R.string.confirmation))
|
||||
.setMessage(getString(R.string.pref_warning__change_account))
|
||||
.setMessage(getString(R.string.logout_warning_description))
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.setPositiveButton(android.R.string.yes,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
@ -129,41 +239,263 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
})
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
case R.string.pref_title__clear_cache: {
|
||||
intent.setAction(MainActivity.ACTION_CLEAR_CACHE);
|
||||
break;
|
||||
}
|
||||
case R.string.pref_title__intellihide_toolbars: {
|
||||
((SettingsActivity) getActivity()).setActivityRestartRequired(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
intent = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (preference.getKey() != null && preference.getKey().startsWith("pref_key__visibility_nav__")) {
|
||||
((SettingsActivity) getActivity()).setActivityRestartRequired(true);
|
||||
return true;
|
||||
}
|
||||
if (intent != null) {
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
}
|
||||
return super.onPreferenceTreeClick(screen, preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragmentThemes extends ThemedPreferenceFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.settings.SettingsFragmentThemes";
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences__sub_themes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewColors() {
|
||||
if (isAdded()) {
|
||||
//Trigger redraw of whole preference screen in order to reflect changes
|
||||
setPreferenceScreen(null);
|
||||
addPreferencesFromResource(R.xml.preferences__sub_themes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
if (activityRestartRequired) {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.setAction(MainActivity.ACTION_RELOAD_ACTIVITY);
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
|
||||
AppSettings settings = ((App) getActivity().getApplication()).getSettings();
|
||||
DiasporaUrlHelper diasporaUrlHelper = new DiasporaUrlHelper(settings);
|
||||
if (isAdded() && preference.hasKey()) {
|
||||
String key = preference.getKey();
|
||||
if (key.equals(getString(R.string.pref_key__primary_color__preference_click))) {
|
||||
showColorPickerDialog(1);
|
||||
return true;
|
||||
} else if (key.equals(getString(R.string.pref_key__accent_color__preference_click))) {
|
||||
showColorPickerDialog(2);
|
||||
return true;
|
||||
} else if (key.equals(getString(R.string.pref_key__manage_theme))) {
|
||||
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||
intent.setAction(MainActivity.ACTION_OPEN_URL);
|
||||
intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getThemeUrl());
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(screen, preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a colorPicker Dialog
|
||||
*
|
||||
* @param type 1 -> Primary Color, 2 -> Accent Color
|
||||
*/
|
||||
@SuppressLint("InflateParams")
|
||||
public void showColorPickerDialog(final int type) {
|
||||
final AppSettings appSettings = ((App) getActivity().getApplication()).getSettings();
|
||||
final Context context = getActivity();
|
||||
|
||||
//Inflate dialog layout
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View dialogLayout = inflater.inflate(R.layout.ui__dialog__color_picker, null);
|
||||
final ThemedAlertDialogBuilder builder = new ThemedAlertDialogBuilder(context, appSettings);
|
||||
builder.setView(dialogLayout);
|
||||
|
||||
final FrameLayout titleBackground = dialogLayout.findViewById(R.id.color_picker_dialog__title_background);
|
||||
final TextView title = dialogLayout.findViewById(R.id.color_picker_dialog__title);
|
||||
final LineColorPicker base = dialogLayout.findViewById(R.id.color_picker_dialog__base_picker);
|
||||
final LineColorPicker shade = dialogLayout.findViewById(R.id.color_picker_dialog__shade_picker);
|
||||
|
||||
title.setText(type == 1 ? R.string.primary_colors : R.string.accent_color);
|
||||
title.setTextColor(getResources().getColor(R.color.white));
|
||||
final int[] current = (type == 1 ? appSettings.getPrimaryColorSettings() : appSettings.getAccentColorSettings());
|
||||
base.setColors((type == 1 ? ColorPalette.getBaseColors(context) : ColorPalette.getAccentColors(context)));
|
||||
base.setSelectedColor(current[0]);
|
||||
shade.setColors(ColorPalette.getColors(context, current[0]));
|
||||
shade.setSelectedColor(current[1]);
|
||||
titleBackground.setBackgroundColor(shade.getColor());
|
||||
base.setOnColorChangedListener(new OnColorChangedListener() {
|
||||
@Override
|
||||
public void onColorChanged(int i) {
|
||||
shade.setColors(ColorPalette.getColors(context, i));
|
||||
titleBackground.setBackgroundColor(i);
|
||||
if (i == current[0]) {
|
||||
shade.setSelectedColor(current[1]);
|
||||
titleBackground.setBackgroundColor(shade.getColor());
|
||||
} else {
|
||||
shade.setSelectedColor(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
shade.setOnColorChangedListener(new OnColorChangedListener() {
|
||||
@Override
|
||||
public void onColorChanged(int i) {
|
||||
titleBackground.setBackgroundColor(i);
|
||||
}
|
||||
});
|
||||
|
||||
//Build dialog
|
||||
builder
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (type == 1) {
|
||||
appSettings.setPrimaryColorSettings(base.getColor(), shade.getColor());
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
getActivity().getWindow().setStatusBarColor(ThemeHelper.getPrimaryDarkColor());
|
||||
}
|
||||
((SettingsActivity) getActivity()).applyColorToViews();
|
||||
} else {
|
||||
appSettings.setAccentColorSettings(base.getColor(), shade.getColor());
|
||||
}
|
||||
updateViewColors();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragmentNavSlider extends ThemedPreferenceFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.settings.SettingsFragmentNavSlider";
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences__sub_navslider_vis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewColors() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragmentProxy extends ThemedPreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.settings.SettingsFragmentProxy";
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences__sub_proxy);
|
||||
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle bundle) {
|
||||
super.onActivityCreated(bundle);
|
||||
updateSummaries();
|
||||
}
|
||||
|
||||
public void updateSummaries() {
|
||||
if (isAdded()) {
|
||||
AppSettings settings = ((App) getActivity().getApplication()).getSettings();
|
||||
findPreference(settings.rstr(R.string.pref_key__http_proxy_host)).setSummary(settings.getProxyHttpHost());
|
||||
findPreference(settings.rstr(R.string.pref_key__http_proxy_port)).setSummary(Integer.toString(settings.getProxyHttpPort()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
|
||||
if (isAdded() && preference.hasKey()) {
|
||||
AppSettings appSettings = ((App) getActivity().getApplication()).getSettings();
|
||||
String key = preference.getKey();
|
||||
if (appSettings.isKeyEqual(key, R.string.pref_key__http_proxy_load_tor_preset)) {
|
||||
appSettings.setProxyHttpHost("127.0.0.1");
|
||||
appSettings.setProxyHttpPort(8118);
|
||||
Toast.makeText(screen.getContext(), R.string.orbot_proxy_preset_loaded, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(screen, preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewColors() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (isAdded()) {
|
||||
if (key.equals(getString(R.string.pref_key__http_proxy_host)) ||
|
||||
key.equals(getString(R.string.pref_key__http_proxy_port))) {
|
||||
updateSummaries();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragmentDebugging extends ThemedPreferenceFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.settings.SettingsFragmentDebugging";
|
||||
|
||||
public void onCreate(Bundle savedInstances) {
|
||||
super.onCreate(savedInstances);
|
||||
getPreferenceManager().setSharedPreferencesName("app");
|
||||
addPreferencesFromResource(R.xml.preferences__sub_debugging);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewColors() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFragmentTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
|
||||
if (isAdded() && preference.hasKey()) {
|
||||
AppSettings appSettings = ((App) getActivity().getApplication()).getSettings();
|
||||
String key = preference.getKey();
|
||||
if (appSettings.isKeyEqual(key, R.string.pref_key__wipe_settings)) {
|
||||
showWipeSettingsDialog();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(screen, preference);
|
||||
}
|
||||
|
||||
private void showWipeSettingsDialog() {
|
||||
final AppSettings appSettings = AppSettings.get();
|
||||
|
||||
ThemedAlertDialogBuilder builder = new ThemedAlertDialogBuilder(getActivity(), appSettings);
|
||||
builder.setTitle(R.string.confirmation)
|
||||
.setMessage(R.string.wipe_settings_warning__appspecific)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
appSettings.resetAppSettings();
|
||||
appSettings.resetPodSettings();
|
||||
new net.gsantner.opoc.util.ContextUtils(appSettings.getContext()).restartApp(MainActivity.class);
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, null)
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.dfa.diaspora_android.activity;
|
||||
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.Helpers;
|
||||
import com.github.dfa.diaspora_android.util.WebHelper;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
private App app;
|
||||
|
||||
@BindView(R.id.splash__splashimage)
|
||||
public ImageView imgSplash;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.splash__activity);
|
||||
ButterKnife.bind(this);
|
||||
app = (App) getApplication();
|
||||
|
||||
TypedArray images = getResources().obtainTypedArray(R.array.splash_images);
|
||||
int choice = (int) (Math.random() * images.length());
|
||||
imgSplash.setImageResource(images.getResourceId(choice, R.drawable.splashscreen1));
|
||||
images.recycle();
|
||||
|
||||
int delay = getResources().getInteger(R.integer.splash_delay);
|
||||
new Handler().postDelayed(startActivityRunnable, delay);
|
||||
}
|
||||
|
||||
final Runnable startActivityRunnable = new Runnable() {
|
||||
public void run() {
|
||||
boolean hasPodDomain = app.getSettings().hasPodDomain();
|
||||
Helpers.animateToActivity(SplashActivity.this,
|
||||
hasPodDomain ? MainActivity.class : PodSelectionActivity.class,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.data;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
|
||||
/**
|
||||
* Created by gsantner (https://gsantner.github.io/) on 20.03.16. Part of Diaspora for Android.
|
||||
*/
|
||||
public class AppSettings {
|
||||
private final SharedPreferences prefApp;
|
||||
private final SharedPreferences prefPod;
|
||||
private final Context context;
|
||||
|
||||
public AppSettings(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
prefApp = this.context.getSharedPreferences("app", Context.MODE_PRIVATE);
|
||||
prefPod = this.context.getSharedPreferences("pod0", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public Context getApplicationContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void clearPodSettings() {
|
||||
prefPod.edit().clear().apply();
|
||||
}
|
||||
|
||||
public void clearAppSettings() {
|
||||
prefApp.edit().clear().apply();
|
||||
}
|
||||
|
||||
private void setString(SharedPreferences pref, int keyRessourceId, String value) {
|
||||
pref.edit().putString(context.getString(keyRessourceId), value).apply();
|
||||
}
|
||||
|
||||
private void setInt(SharedPreferences pref, int keyRessourceId, int value) {
|
||||
pref.edit().putInt(context.getString(keyRessourceId), value).apply();
|
||||
}
|
||||
|
||||
private void setBool(SharedPreferences pref, int keyRessourceId, boolean value) {
|
||||
pref.edit().putBoolean(context.getString(keyRessourceId), value).apply();
|
||||
}
|
||||
|
||||
private void setStringArray(SharedPreferences pref, int keyRessourceId, Object[] values) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Object value : values) {
|
||||
sb.append("%%%");
|
||||
sb.append(value.toString());
|
||||
}
|
||||
setString(pref, keyRessourceId, sb.toString().replaceFirst("%%%", ""));
|
||||
}
|
||||
|
||||
private String[] getStringArray(SharedPreferences pref, int keyRessourceId) {
|
||||
String value = pref.getString(context.getString(keyRessourceId), "%%%");
|
||||
if (value.equals("%%%")) {
|
||||
return new String[0];
|
||||
}
|
||||
return value.split("%%%");
|
||||
}
|
||||
|
||||
private String getString(SharedPreferences pref, int ressourceId, String defaultValue) {
|
||||
return pref.getString(context.getString(ressourceId), defaultValue);
|
||||
}
|
||||
|
||||
private boolean getBoolean(SharedPreferences pref, int ressourceId, boolean defaultValue) {
|
||||
return pref.getBoolean(context.getString(ressourceId), defaultValue);
|
||||
}
|
||||
|
||||
private int getInt(SharedPreferences pref, int ressourceId, int defaultValue) {
|
||||
return pref.getInt(context.getString(ressourceId), defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Setters & Getters
|
||||
*/
|
||||
public String getProfileId() {
|
||||
return getString(prefPod, R.string.pref_key__podprofile_id, "");
|
||||
}
|
||||
|
||||
public void setProfileId(String profileId) {
|
||||
setString(prefPod, R.string.pref_key__podprofile_id, profileId);
|
||||
}
|
||||
|
||||
public boolean isLoadImages() {
|
||||
return getBoolean(prefApp, R.string.pref_key__load_images, true);
|
||||
}
|
||||
|
||||
public int getMinimumFontSize() {
|
||||
switch (getString(prefApp, R.string.pref_key__font_size, "")) {
|
||||
case "huge":
|
||||
return 20;
|
||||
case "large":
|
||||
return 16;
|
||||
case "normal":
|
||||
return 8;
|
||||
default:
|
||||
setString(prefApp, R.string.pref_key__font_size, "normal");
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAvatarUrl() {
|
||||
return getString(prefPod, R.string.pref_key__podprofile_avatar_url, "");
|
||||
}
|
||||
|
||||
public void setAvatarUrl(String avatarUrl) {
|
||||
setString(prefPod, R.string.pref_key__podprofile_avatar_url, avatarUrl);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getString(prefPod, R.string.pref_key__podprofile_name, "");
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
setString(prefPod, R.string.pref_key__podprofile_name, name);
|
||||
}
|
||||
|
||||
public String getPodDomain() {
|
||||
return getString(prefPod, R.string.pref_key__poddomain, "");
|
||||
}
|
||||
|
||||
public void setPodDomain(String podDomain) {
|
||||
setString(prefPod, R.string.pref_key__poddomain, podDomain);
|
||||
}
|
||||
|
||||
public boolean hasPodDomain() {
|
||||
return !getString(prefPod, R.string.pref_key__poddomain, "").equals("");
|
||||
}
|
||||
|
||||
public String[] getPreviousPodlist() {
|
||||
return getStringArray(prefApp, R.string.pref_key__previous_podlist);
|
||||
}
|
||||
|
||||
public void setPreviousPodlist(String[] pods) {
|
||||
setStringArray(prefApp, R.string.pref_key__previous_podlist, pods);
|
||||
}
|
||||
|
||||
public void setPodAspects(PodAspect[] aspects) {
|
||||
setStringArray(prefPod, R.string.pref_key__podprofile_aspects, aspects);
|
||||
}
|
||||
|
||||
public PodAspect[] getPodAspects() {
|
||||
String[] s = getStringArray(prefPod, R.string.pref_key__podprofile_aspects);
|
||||
PodAspect[] aspects = new PodAspect[s.length];
|
||||
for (int i = 0; i < aspects.length; i++) {
|
||||
aspects[i] = new PodAspect(s[i]);
|
||||
}
|
||||
return aspects;
|
||||
}
|
||||
|
||||
public String[] getFollowedTags() {
|
||||
return getStringArray(prefPod, R.string.pref_key__podprofile_followed_tags);
|
||||
}
|
||||
|
||||
public void setFollowedTags(String[] tags) {
|
||||
setStringArray(prefPod, R.string.pref_key__podprofile_followed_tags, tags);
|
||||
}
|
||||
|
||||
public int getUnreadMessageCount() {
|
||||
return getInt(prefPod, R.string.pref_key__podprofile_unread_message_count, 0);
|
||||
}
|
||||
|
||||
public void setUnreadMessageCount(int unreadMessageCount) {
|
||||
setInt(prefPod, R.string.pref_key__podprofile_unread_message_count, unreadMessageCount);
|
||||
}
|
||||
|
||||
public int getNotificationCount() {
|
||||
return getInt(prefPod, R.string.pref_key__podprofile_notification_count, 0);
|
||||
}
|
||||
|
||||
public void setNotificationCount(int notificationCount) {
|
||||
setInt(prefPod, R.string.pref_key__podprofile_notification_count, notificationCount);
|
||||
}
|
||||
|
||||
public boolean isAppendSharedViaApp() {
|
||||
return getBoolean(prefApp, R.string.pref_key__append_shared_via_app, true);
|
||||
}
|
||||
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
public void setProxyEnabled(boolean enabled) {
|
||||
//commit instead of apply because the app is likely to be killed before apply is called.
|
||||
prefApp.edit().putBoolean(context.getString(R.string.pref_key__proxy_enabled), enabled).commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default return value: false
|
||||
*
|
||||
* @return whether proxy is enabled or not
|
||||
*/
|
||||
public boolean isProxyEnabled() {
|
||||
return getBoolean(prefApp, R.string.pref_key__proxy_enabled, false);
|
||||
}
|
||||
|
||||
public boolean wasProxyEnabled() {
|
||||
return getBoolean(prefApp, R.string.pref_key__proxy_was_enabled, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed in order to determine, whether the proxy has just been disabled (trigger app restart)
|
||||
* or if proxy was disabled before (do not restart app)
|
||||
*
|
||||
* @param b new value
|
||||
*/
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
public void setProxyWasEnabled(boolean b) {
|
||||
prefApp.edit().putBoolean(context.getString(R.string.pref_key__proxy_was_enabled), b).commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: ""
|
||||
*
|
||||
* @return proxy host
|
||||
*/
|
||||
public String getProxyHost() {
|
||||
return getString(prefApp, R.string.pref_key__proxy_host, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value: 0
|
||||
*
|
||||
* @return proxy port
|
||||
*/
|
||||
public int getProxyPort() {
|
||||
try {
|
||||
return Integer.parseInt(getString(prefApp, R.string.pref_key__proxy_port, "0"));
|
||||
} catch (Exception e) {
|
||||
setString(prefApp, R.string.pref_key__proxy_port, "0");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIntellihideToolbars() {
|
||||
return getBoolean(prefApp, R.string.pref_key__intellihide_toolbars, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavExit() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__exit, false);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavHelp_license() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__help_license, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavPublic_activities() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__public_activities, false);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavMentions() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__mentions, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavCommented() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__commented, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavLiked() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__liked, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavActivities() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__activities, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavAspects() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__aspects, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavFollowed_tags() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__followed_tags, true);
|
||||
}
|
||||
|
||||
public boolean isVisibleInNavProfile() {
|
||||
return getBoolean(prefApp, R.string.pref_key__visibility_nav__profile, false);
|
||||
}
|
||||
}
|
|
@ -1,43 +1,44 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
This file is part of the dandelion*.
|
||||
|
||||
Diaspora for Android is free software: you can redistribute it and/or modify
|
||||
dandelion* 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.
|
||||
|
||||
Diaspora for Android is distributed in the hope that it will be useful,
|
||||
dandelion* 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 the Diaspora for Android.
|
||||
along with the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.data;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class PodAspect {
|
||||
public class DiasporaAspect {
|
||||
public long id;
|
||||
public String name;
|
||||
public boolean selected;
|
||||
|
||||
public PodAspect(long id, String name, boolean selected) {
|
||||
public DiasporaAspect(long id, String name, boolean selected) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
|
||||
public PodAspect(String shareabletext) {
|
||||
public DiasporaAspect(String shareabletext) {
|
||||
// fromShareAbleText
|
||||
String[] str = shareabletext.split("%");
|
||||
selected = Integer.parseInt(str[0]) == 1;
|
||||
|
@ -45,7 +46,7 @@ public class PodAspect {
|
|||
name = shareabletext.substring(shareabletext.indexOf(str[1]) + str[1].length() + 1);
|
||||
}
|
||||
|
||||
public PodAspect(JSONObject json) throws JSONException {
|
||||
public DiasporaAspect(JSONObject json) throws JSONException {
|
||||
if (json.has("id")) {
|
||||
id = json.getLong("id");
|
||||
}
|
||||
|
@ -70,8 +71,8 @@ public class PodAspect {
|
|||
public String toHtmlLink(final App app) {
|
||||
final AppSettings appSettings = app.getSettings();
|
||||
return String.format(Locale.getDefault(),
|
||||
"<a href='https://%s/aspects?a_ids[]=%d' style='color: #000000; text-decoration: none;'>%s</a>",
|
||||
appSettings.getPodDomain(), id, name);
|
||||
"<a href='%s/aspects?a_ids[]=%d' style='color: #000000; text-decoration: none;'>%s</a>",
|
||||
appSettings.getPod().getPodUrl().getBaseUrl(), id, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,7 +82,7 @@ public class PodAspect {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PodAspect && ((PodAspect) o).id == id;
|
||||
return o instanceof DiasporaAspect && ((DiasporaAspect) o).id == id;
|
||||
}
|
||||
|
||||
public String toShareAbleText() {
|
|
@ -0,0 +1,524 @@
|
|||
package com.github.dfa.diaspora_android.data;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Created by gsantner (gsantner AT mailbox DOT org on 30.09.16.
|
||||
* DiasporaPodList - List container for DiasporaPod's, with methods to merge with other DiasporaPodLists
|
||||
* DiasporaPod - Data container for a Pod, can include N DiasporaPodUrl's
|
||||
* DiasporaPodUrl - A Url of an DiasporaPod
|
||||
* For all Classes a loading and saving to JSON method is available
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "UnusedReturnValue", "JavaDoc", "FieldCanBeLocal"})
|
||||
public class DiasporaPodList implements Iterable<DiasporaPodList.DiasporaPod>, Serializable {
|
||||
private static final boolean EXPORT_TOJSON_POST_COUNT_LOCAL = true;
|
||||
private List<DiasporaPod> pods = new ArrayList<>();
|
||||
private boolean trackMergeChanges = false;
|
||||
private Integer trackAddedIndexStart = -1;
|
||||
private List<Integer> trackUpdatedIndexes = new ArrayList<>();
|
||||
private boolean keepOldNameDuringMerge = false;
|
||||
private long timestamp;
|
||||
|
||||
public DiasporaPodList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load DiasporaPodList from Json
|
||||
*
|
||||
* @param json Json Object
|
||||
*/
|
||||
public DiasporaPodList fromJson(JSONObject json) throws JSONException {
|
||||
JSONArray jarr;
|
||||
pods.clear();
|
||||
|
||||
if (json.has("pods")) {
|
||||
jarr = json.getJSONArray("pods");
|
||||
for (int i = 0; i < jarr.length(); i++) {
|
||||
DiasporaPod pod = new DiasporaPod().fromJson(jarr.getJSONObject(i));
|
||||
pods.add(pod);
|
||||
}
|
||||
}
|
||||
if (json.has("timestamp")) {
|
||||
timestamp = json.getLong("timestamp");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert DiasporaPodList to JSON
|
||||
*/
|
||||
public JSONObject toJson() throws JSONException {
|
||||
JSONObject json = new JSONObject();
|
||||
JSONArray jpods = new JSONArray();
|
||||
for (DiasporaPod pod : pods) {
|
||||
jpods.put(pod.toJson());
|
||||
}
|
||||
json.put("pods", jpods);
|
||||
json.put("timestamp", System.currentTimeMillis());
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge newer entries into this podlist
|
||||
* Will add new pods, and update data of pods with data from the new list
|
||||
*
|
||||
* @param newPodList Another podlist
|
||||
*/
|
||||
public void mergeWithNewerEntries(final DiasporaPodList newPodList) throws JSONException {
|
||||
if (isTrackMergeChanges()) {
|
||||
trackAddedIndexStart = -1;
|
||||
trackUpdatedIndexes.clear();
|
||||
}
|
||||
for (DiasporaPod newPod : newPodList) {
|
||||
int index = pods.indexOf(newPod);
|
||||
if (index >= 0) {
|
||||
DiasporaPod updatePodBak = new DiasporaPod().fromJson(pods.get(index).toJson());
|
||||
DiasporaPod updatePod = pods.get(index);
|
||||
updatePod.fromJson(newPod.toJson());
|
||||
|
||||
// Restore Pod id (if was set to zero)
|
||||
if (updatePodBak.getId() != 0 && updatePod.getId() == 0) {
|
||||
updatePod.setId(updatePodBak.getId());
|
||||
}
|
||||
if (updatePodBak.getPostCountLocal() != 0 && updatePod.getPostCountLocal() == 0) {
|
||||
updatePod.setPostCountLocal(updatePodBak.getPostCountLocal());
|
||||
}
|
||||
if (updatePodBak.getScore() != 0 && updatePod.getScore() == 0) {
|
||||
updatePod.setScore(updatePodBak.getScore());
|
||||
}
|
||||
if (!updatePodBak.getName().equals("") && keepOldNameDuringMerge) {
|
||||
updatePod.setName(updatePodBak.getName());
|
||||
}
|
||||
if (isTrackMergeChanges()) {
|
||||
trackUpdatedIndexes.add(index);
|
||||
}
|
||||
} else {
|
||||
pods.add(newPod);
|
||||
if (isTrackMergeChanges() && trackAddedIndexStart == -1) {
|
||||
trackAddedIndexStart = pods.size() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the pod list
|
||||
*/
|
||||
public void sortPods() {
|
||||
Collections.sort(pods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for Iterable interface (forEach, ..)
|
||||
*/
|
||||
public Iterator<DiasporaPod> iterator() {
|
||||
return pods.iterator();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return pods.size();
|
||||
}
|
||||
|
||||
public int indexOf(DiasporaPod pod) {
|
||||
return pods.indexOf(pod);
|
||||
}
|
||||
|
||||
public List<DiasporaPod> getPods() {
|
||||
return pods;
|
||||
}
|
||||
|
||||
public void setPods(List<DiasporaPod> pods) {
|
||||
this.pods = pods;
|
||||
}
|
||||
|
||||
public DiasporaPod getPodAt(int index) {
|
||||
if (index >= 0 && index < pods.size()) {
|
||||
return pods.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isTrackMergeChanges() {
|
||||
return trackMergeChanges;
|
||||
}
|
||||
|
||||
public void setTrackMergeChanges(boolean trackMergeChanges) {
|
||||
this.trackMergeChanges = trackMergeChanges;
|
||||
}
|
||||
|
||||
public Integer getTrackAddedIndexStart() {
|
||||
return trackAddedIndexStart;
|
||||
}
|
||||
|
||||
public List<Integer> getTrackUpdatedIndexes() {
|
||||
return trackUpdatedIndexes;
|
||||
}
|
||||
|
||||
public boolean isKeepOldNameDuringMerge() {
|
||||
return keepOldNameDuringMerge;
|
||||
}
|
||||
|
||||
public void setKeepOldNameDuringMerge(boolean keepOldNameDuringMerge) {
|
||||
this.keepOldNameDuringMerge = keepOldNameDuringMerge;
|
||||
}
|
||||
|
||||
|
||||
/* ██████╗ ██████╗ ██████╗
|
||||
* ██╔══██╗██╔═══██╗██╔══██╗
|
||||
* ██████╔╝██║ ██║██║ ██║
|
||||
* ██╔═══╝ ██║ ██║██║ ██║
|
||||
* ██║ ╚██████╔╝██████╔╝
|
||||
* ╚═╝ ╚═════╝ ╚═════╝
|
||||
*/
|
||||
public static class DiasporaPod implements Iterable<DiasporaPodList.DiasporaPod.DiasporaPodUrl>, Comparable<DiasporaPod>, Serializable {
|
||||
private List<DiasporaPodUrl> _podUrls = new ArrayList<>();
|
||||
private List<String> _mainLangs = new ArrayList<>();
|
||||
private String _name = "";
|
||||
private int _score = 0;
|
||||
private int _id = 0;
|
||||
private long _postCountLocal = 0;
|
||||
|
||||
|
||||
public DiasporaPod() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a DiasporaPod from JSON
|
||||
*
|
||||
* @param json Json Object
|
||||
*/
|
||||
public DiasporaPod fromJson(JSONObject json) throws JSONException {
|
||||
JSONArray jarr;
|
||||
|
||||
if (json.has("name")) {
|
||||
_name = json.getString("name");
|
||||
}
|
||||
if (json.has("mainLangs")) {
|
||||
jarr = json.getJSONArray("mainLangs");
|
||||
for (int i = 0; i < jarr.length(); i++) {
|
||||
String val = jarr.getString(i);
|
||||
if (!_mainLangs.contains(val)) {
|
||||
_mainLangs.add(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (json.has("podUrls")) {
|
||||
jarr = json.getJSONArray("podUrls");
|
||||
for (int i = 0; i < jarr.length(); i++) {
|
||||
DiasporaPodUrl podUrl = new DiasporaPodUrl().fromJson(jarr.getJSONObject(i));
|
||||
if (!_podUrls.contains(podUrl)) {
|
||||
_podUrls.add(podUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (json.has("score")) {
|
||||
_score = json.getInt("score");
|
||||
}
|
||||
if (json.has("postCountLocal")) {
|
||||
_postCountLocal = json.getLong("postCountLocal");
|
||||
}
|
||||
if (json.has("id")) {
|
||||
_id = json.getInt("id");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert DiasporaPod to JSON
|
||||
*/
|
||||
public JSONObject toJson() throws JSONException {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("name", _name);
|
||||
json.put("id", _id);
|
||||
|
||||
if (_score != 0) {
|
||||
json.put("score", _score);
|
||||
}
|
||||
|
||||
// Only export active6 (frequently changing if told to do)
|
||||
if (EXPORT_TOJSON_POST_COUNT_LOCAL && _postCountLocal > 0) {
|
||||
json.put("postCountLocal", _postCountLocal);
|
||||
}
|
||||
|
||||
// Pod urls
|
||||
JSONArray jarr = new JSONArray();
|
||||
for (DiasporaPodUrl value : _podUrls) {
|
||||
jarr.put(value.toJson());
|
||||
}
|
||||
json.put("podUrls", jarr);
|
||||
|
||||
// main langs
|
||||
jarr = new JSONArray();
|
||||
for (String value : _mainLangs) {
|
||||
jarr.put(value);
|
||||
}
|
||||
json.put("mainLangs", jarr);
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
boolean ret = false;
|
||||
if (o instanceof DiasporaPod) {
|
||||
DiasporaPod otherPod = (DiasporaPod) o;
|
||||
|
||||
// Check if id is equal
|
||||
ret = _id != 0 && _id == otherPod._id;
|
||||
|
||||
// Check if _host is the same (fallback if id is 0)
|
||||
if (!ret) {
|
||||
for (DiasporaPodUrl podUrl : _podUrls) {
|
||||
for (DiasporaPodUrl otherPodUrl : otherPod.getPodUrls()) {
|
||||
if (podUrl.getBaseUrl().equals(otherPodUrl.getBaseUrl())) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DiasporaPod otherPod) {
|
||||
if (otherPod != null) {
|
||||
List<DiasporaPodUrl> myPodUrls = getPodUrls();
|
||||
List<DiasporaPodUrl> otherPodUrls = otherPod.getPodUrls();
|
||||
if (!myPodUrls.isEmpty() && !otherPodUrls.isEmpty()) {
|
||||
return myPodUrls.get(0).getHost().compareTo(otherPodUrls.get(0).getHost());
|
||||
}
|
||||
return _name.compareTo(otherPod.getName());
|
||||
}
|
||||
return _name.compareTo("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return _name + "(" + _id + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for Iterable interface (forEach, ..)
|
||||
*/
|
||||
public Iterator<DiasporaPodUrl> iterator() {
|
||||
return _podUrls.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* Getter & Setter
|
||||
*/
|
||||
public List<DiasporaPodUrl> getPodUrls() {
|
||||
return _podUrls;
|
||||
}
|
||||
|
||||
public DiasporaPod setPodUrls(List<DiasporaPodUrl> podUrls) {
|
||||
_podUrls = podUrls;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getMainLangs() {
|
||||
return _mainLangs;
|
||||
}
|
||||
|
||||
public DiasporaPod setMainLangs(List<String> mainLangs) {
|
||||
_mainLangs = mainLangs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiasporaPod appendMainLangs(String... values) {
|
||||
_mainLangs.addAll(Arrays.asList(values));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first DiasporaPodUrl in the list
|
||||
*/
|
||||
public DiasporaPodUrl getPodUrl() {
|
||||
if (_podUrls.size() > 0) {
|
||||
return _podUrls.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DiasporaPod appendPodUrls(DiasporaPodUrl... values) {
|
||||
_podUrls.addAll(Arrays.asList(values));
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public DiasporaPod setName(String name) {
|
||||
_name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return _score;
|
||||
}
|
||||
|
||||
public DiasporaPod setScore(int score) {
|
||||
_score = score;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getPostCountLocal() {
|
||||
return _postCountLocal;
|
||||
}
|
||||
|
||||
public DiasporaPod setPostCountLocal(long postCountLocal) {
|
||||
_postCountLocal = postCountLocal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
public DiasporaPod setId(int id) {
|
||||
_id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* ██████╗ ██████╗ ██████╗ ██╗ ██╗██████╗ ██╗
|
||||
* ██╔══██╗██╔═══██╗██╔══██╗ ██║ ██║██╔══██╗██║
|
||||
* ██████╔╝██║ ██║██║ ██║ ██║ ██║██████╔╝██║
|
||||
* ██╔═══╝ ██║ ██║██║ ██║ ██║ ██║██╔══██╗██║
|
||||
* ██║ ╚██████╔╝██████╔╝ ╚██████╔╝██║ ██║███████╗
|
||||
* ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
||||
*/
|
||||
public static class DiasporaPodUrl implements Serializable {
|
||||
private String _host = "";
|
||||
private String _protocol = "https";
|
||||
private Integer _port = 443;
|
||||
|
||||
public DiasporaPodUrl() {
|
||||
}
|
||||
|
||||
public DiasporaPodUrl(JSONObject json) throws JSONException {
|
||||
fromJson(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base url
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getBaseUrl() {
|
||||
return _protocol + "://" + _host + (isPortNeeded() ? _port : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert JSON to DiasporaPodList
|
||||
*
|
||||
* @param json JSON Object
|
||||
*/
|
||||
public DiasporaPodUrl fromJson(JSONObject json) throws JSONException {
|
||||
if (json.has("host")) {
|
||||
_host = json.getString("host");
|
||||
}
|
||||
if (json.has("protocol")) {
|
||||
_protocol = json.getString("protocol");
|
||||
}
|
||||
if (json.has("port")) {
|
||||
_port = json.getInt("port");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* Convert DiasporaPodList to JSON
|
||||
*/
|
||||
public JSONObject toJson() throws JSONException {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("host", _host);
|
||||
if (!_protocol.equals("https")) {
|
||||
json.put("protocol", _protocol);
|
||||
}
|
||||
if (_port != 443) {
|
||||
json.put("port", _port);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default values for https
|
||||
*/
|
||||
public void setHttpsDefaults() {
|
||||
setProtocol("https");
|
||||
setPort(443);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set default values for http
|
||||
*/
|
||||
public void setHttpDefaults() {
|
||||
setProtocol("http");
|
||||
setPort(80);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the ports needs to shown
|
||||
*/
|
||||
public boolean isPortNeeded() {
|
||||
return !((_port == 80 && _protocol.equals("http")) || (_port == 443 && _protocol.equals("https")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getBaseUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof DiasporaPodUrl) {
|
||||
return getBaseUrl().equals(((DiasporaPodUrl) o).getBaseUrl());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* GETTER & SETTER
|
||||
*/
|
||||
public String getHost() {
|
||||
return _host;
|
||||
}
|
||||
|
||||
public DiasporaPodUrl setHost(String host) {
|
||||
_host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return _protocol;
|
||||
}
|
||||
|
||||
public DiasporaPodUrl setProtocol(String protocol) {
|
||||
_protocol = protocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return _port;
|
||||
}
|
||||
|
||||
public DiasporaPodUrl setPort(Integer port) {
|
||||
_port = port;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +1,87 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
This file is part of the dandelion*.
|
||||
|
||||
Diaspora for Android is free software: you can redistribute it and/or modify
|
||||
dandelion* 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.
|
||||
|
||||
Diaspora for Android is distributed in the hope that it will be useful,
|
||||
dandelion* 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 the Diaspora for Android.
|
||||
along with the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.data;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.listener.WebUserProfileChangedListener;
|
||||
import com.github.dfa.diaspora_android.listener.DiasporaUserProfileChangedListener;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Created by gsantner (https://gsantner.github.io/) on 24.03.16. Part of Diaspora for Android.
|
||||
* User profile
|
||||
* Created by gsantner (gsantner AT mailbox DOT org) on 24.03.16. Part of dandelion*.
|
||||
*/
|
||||
public class PodUserProfile {
|
||||
private static final int MINIMUM_WEBUSERPROFILE_LOAD_TIMEDIFF = 5000;
|
||||
public class DiasporaUserProfile {
|
||||
private static final int MINIMUM_USERPROFILE_LOAD_TIMEDIFF = 5000;
|
||||
|
||||
private Handler callbackHandler;
|
||||
private WebUserProfileChangedListener listener;
|
||||
private App app;
|
||||
private AppSettings appSettings;
|
||||
private DiasporaUserProfileChangedListener listener;
|
||||
private final App app;
|
||||
private final AppSettings appSettings;
|
||||
DiasporaUrlHelper urls;
|
||||
private JSONObject json;
|
||||
private long lastLoaded;
|
||||
private long userProfileLastLoadedTimestamp;
|
||||
private boolean isWebUserProfileLoaded;
|
||||
|
||||
private String avatarUrl;
|
||||
private String guid;
|
||||
private String name;
|
||||
private PodAspect[] podAspects;
|
||||
private DiasporaAspect[] aspects;
|
||||
private String[] followedTags;
|
||||
private int notificationCount;
|
||||
private int unreadMessagesCount;
|
||||
private long lastVisitedPositionInStream = -1;
|
||||
|
||||
|
||||
public PodUserProfile(App app) {
|
||||
public DiasporaUserProfile(App app) {
|
||||
this.app = app;
|
||||
appSettings = app.getSettings();
|
||||
urls = new DiasporaUrlHelper(appSettings);
|
||||
loadFromAppSettings();
|
||||
}
|
||||
|
||||
public void loadFromAppSettings() {
|
||||
avatarUrl = appSettings.getAvatarUrl();
|
||||
guid = appSettings.getProfileId();
|
||||
name = appSettings.getName();
|
||||
podAspects = appSettings.getPodAspects();
|
||||
aspects = appSettings.getAspects();
|
||||
followedTags = appSettings.getFollowedTags();
|
||||
notificationCount = appSettings.getNotificationCount();
|
||||
unreadMessagesCount = appSettings.getUnreadMessageCount();
|
||||
lastVisitedPositionInStream = appSettings.getLastVisitedPositionInStream();
|
||||
}
|
||||
|
||||
public PodUserProfile(App app, Handler callbackHandler, WebUserProfileChangedListener listener) {
|
||||
public DiasporaUserProfile(App app, Handler callbackHandler, DiasporaUserProfileChangedListener listener) {
|
||||
this(app);
|
||||
this.listener = listener;
|
||||
this.callbackHandler = callbackHandler;
|
||||
}
|
||||
|
||||
public boolean isRefreshNeeded() {
|
||||
return (System.currentTimeMillis() - lastLoaded) >= MINIMUM_WEBUSERPROFILE_LOAD_TIMEDIFF;
|
||||
return (System.currentTimeMillis() - userProfileLastLoadedTimestamp) >= MINIMUM_USERPROFILE_LOAD_TIMEDIFF;
|
||||
}
|
||||
|
||||
public boolean isWebUserProfileLoaded() {
|
||||
|
@ -81,19 +91,19 @@ public class PodUserProfile {
|
|||
public boolean parseJson(String jsonStr) {
|
||||
try {
|
||||
json = new JSONObject(jsonStr);
|
||||
lastLoaded = System.currentTimeMillis();
|
||||
userProfileLastLoadedTimestamp = System.currentTimeMillis();
|
||||
|
||||
// Avatar
|
||||
if (json.has("avatar")) {
|
||||
JSONObject avatarJson = json.getJSONObject("avatar");
|
||||
if (avatarJson.has("medium") && setAvatarUrl(avatarJson.getString("medium"))) {
|
||||
if (avatarJson.has("large") && setAvatarUrl(avatarJson.getString("large"))) {
|
||||
app.getAvatarImageLoader().clearAvatarImage();
|
||||
appSettings.setAvatarUrl(avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// GUID (User id)
|
||||
if (json.has("guid") && loadGuid(json.getString("guid"))) {
|
||||
if (json.has("guid") && loadGuid(json.getString("guid")) && !guid.isEmpty()) {
|
||||
appSettings.setProfileId(guid);
|
||||
}
|
||||
|
||||
|
@ -114,7 +124,7 @@ public class PodUserProfile {
|
|||
|
||||
// Aspect
|
||||
if (json.has("aspects") && loadAspects(json.getJSONArray("aspects"))) {
|
||||
appSettings.setPodAspects(podAspects);
|
||||
appSettings.setPodAspects(aspects);
|
||||
}
|
||||
|
||||
// Followed tags
|
||||
|
@ -125,13 +135,23 @@ public class PodUserProfile {
|
|||
|
||||
isWebUserProfileLoaded = true;
|
||||
} catch (JSONException e) {
|
||||
Log.d(App.TAG, e.getMessage());
|
||||
AppLog.d(this, e.getMessage());
|
||||
isWebUserProfileLoaded = false;
|
||||
}
|
||||
lastLoaded = System.currentTimeMillis();
|
||||
userProfileLastLoadedTimestamp = System.currentTimeMillis();
|
||||
return isWebUserProfileLoaded;
|
||||
}
|
||||
|
||||
public void analyzeUrl(String url) {
|
||||
String prefix = urls.getPodUrl() + DiasporaUrlHelper.SUBURL_STREAM_WITH_TIMESTAMP;
|
||||
if (url.startsWith(prefix)) {
|
||||
try {
|
||||
setLastVisitedPositionInStream(Long.parseLong(url.replace(prefix, "")));
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Getters & Setters
|
||||
*/
|
||||
|
@ -156,24 +176,48 @@ public class PodUserProfile {
|
|||
return unreadMessagesCount;
|
||||
}
|
||||
|
||||
public PodAspect[] getAspects() {
|
||||
return podAspects;
|
||||
public DiasporaAspect[] getAspects() {
|
||||
return aspects;
|
||||
}
|
||||
|
||||
public String[] getFollowedTags() {
|
||||
return followedTags;
|
||||
}
|
||||
|
||||
public long getLastVisitedPositionInStream() {
|
||||
return lastVisitedPositionInStream;
|
||||
}
|
||||
|
||||
public void setLastVisitedPositionInStream(long lastVisitedPositionInStream) {
|
||||
this.lastVisitedPositionInStream = lastVisitedPositionInStream;
|
||||
appSettings.setLastVisitedPositionInStream(lastVisitedPositionInStream);
|
||||
}
|
||||
|
||||
public boolean hasLastVisitedTimestampInStream() {
|
||||
return appSettings.getLastVisitedPositionInStream() != -1;
|
||||
}
|
||||
|
||||
public void resetLastVisitedPositionInStream() {
|
||||
appSettings.setLastVisitedPositionInStream(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Private property setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the avatar, returns true if this was a new one, false if already the old one
|
||||
*
|
||||
* @param avatarUrl url
|
||||
* @return true if new avatar url
|
||||
*/
|
||||
private boolean setAvatarUrl(final String avatarUrl) {
|
||||
if (!this.avatarUrl.equals(avatarUrl)) {
|
||||
this.avatarUrl = avatarUrl;
|
||||
if (listener != null && callbackHandler != null) {
|
||||
callbackHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
listener.onUserProfileAvatarChanged(avatarUrl);
|
||||
listener.onUserProfileAvatarChanged(DiasporaUserProfile.this, avatarUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -196,7 +240,7 @@ public class PodUserProfile {
|
|||
if (listener != null && callbackHandler != null) {
|
||||
callbackHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
listener.onUserProfileNameChanged(name);
|
||||
listener.onUserProfileNameChanged(DiasporaUserProfile.this, name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -211,7 +255,7 @@ public class PodUserProfile {
|
|||
if (listener != null && callbackHandler != null) {
|
||||
callbackHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
listener.onNotificationCountChanged(notificationCount);
|
||||
listener.onNotificationCountChanged(DiasporaUserProfile.this, notificationCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -221,9 +265,9 @@ public class PodUserProfile {
|
|||
}
|
||||
|
||||
private boolean loadAspects(final JSONArray jsonAspects) throws JSONException {
|
||||
podAspects = new PodAspect[jsonAspects.length()];
|
||||
aspects = new DiasporaAspect[jsonAspects.length()];
|
||||
for (int i = 0; i < jsonAspects.length(); i++) {
|
||||
podAspects[i] = new PodAspect(jsonAspects.getJSONObject(i));
|
||||
aspects[i] = new DiasporaAspect(jsonAspects.getJSONObject(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -242,7 +286,7 @@ public class PodUserProfile {
|
|||
if (listener != null && callbackHandler != null) {
|
||||
callbackHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
listener.onUnreadMessageCountChanged(unreadMessagesCount);
|
||||
listener.onUnreadMessageCountChanged(DiasporaUserProfile.this, unreadMessagesCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -259,11 +303,11 @@ public class PodUserProfile {
|
|||
this.callbackHandler = callbackHandler;
|
||||
}
|
||||
|
||||
public WebUserProfileChangedListener getListener() {
|
||||
public DiasporaUserProfileChangedListener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public void setListener(WebUserProfileChangedListener listener) {
|
||||
public void setListener(DiasporaUserProfileChangedListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.listener;
|
||||
|
||||
import com.github.dfa.diaspora_android.data.DiasporaUserProfile;
|
||||
|
||||
/**
|
||||
* Created by gsantner (gsantner AT mailbox DOT org) on 26.03.16.
|
||||
* Interface that needs to be implemented by classes that listen for Profile related changes
|
||||
*/
|
||||
public interface DiasporaUserProfileChangedListener {
|
||||
/**
|
||||
* Called when the DiasporaUserProfile name changed
|
||||
*
|
||||
* @param diasporaUserProfile The profile
|
||||
* @param name The new name
|
||||
*/
|
||||
void onUserProfileNameChanged(DiasporaUserProfile diasporaUserProfile, String name);
|
||||
|
||||
/**
|
||||
* Called when the DiasporaUserProfile avatarUrl changed
|
||||
*
|
||||
* @param diasporaUserProfile The profile
|
||||
* @param avatarUrl The new name
|
||||
*/
|
||||
void onUserProfileAvatarChanged(DiasporaUserProfile diasporaUserProfile, String avatarUrl);
|
||||
|
||||
/**
|
||||
* Called when the DiasporaUserProfile notificationCount changed
|
||||
*
|
||||
* @param diasporaUserProfile The profile
|
||||
* @param notificationCount The new notificationCount
|
||||
*/
|
||||
void onNotificationCountChanged(DiasporaUserProfile diasporaUserProfile, int notificationCount);
|
||||
|
||||
/**
|
||||
* Called when the DiasporaUserProfile unreadMessageCount changed
|
||||
*
|
||||
* @param diasporaUserProfile The profile
|
||||
* @param unreadMessageCount The new unreadMessageCount
|
||||
*/
|
||||
void onUnreadMessageCountChanged(DiasporaUserProfile diasporaUserProfile, int unreadMessageCount);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.github.dfa.diaspora_android.listener;
|
||||
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
|
||||
/**
|
||||
* interface that adds options to control intellihide of toolbars to the Activity
|
||||
* Created by vanitas on 08.10.16.
|
||||
*/
|
||||
|
||||
public interface IntellihideToolbarActivityListener {
|
||||
int toolbarDefaultScrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP;
|
||||
|
||||
void setToolbarIntellihide(boolean enable);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.github.dfa.diaspora_android.listener;
|
||||
|
||||
/**
|
||||
* Listener for different types of click events
|
||||
*/
|
||||
public interface OnSomethingClickListener<T> {
|
||||
/**
|
||||
* Triggered when something was clicked
|
||||
*
|
||||
* @param o Some object, or null
|
||||
* @param i Some index, int value or null
|
||||
* @param s Some String, or null
|
||||
*/
|
||||
void onSomethingClicked(T o, Integer i, String s);
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.listener;
|
||||
|
||||
/**
|
||||
* Created by gsantner (https://gsantner.github.io/) on 26.03.16.
|
||||
* Interface that needs to be implemented by classes that listen for Profile related changes
|
||||
*/
|
||||
public interface WebUserProfileChangedListener {
|
||||
void onUserProfileNameChanged(String name);
|
||||
|
||||
void onUserProfileAvatarChanged(String avatarUrl);
|
||||
|
||||
void onNotificationCountChanged(int notificationCount);
|
||||
|
||||
void onUnreadMessageCountChanged(int unreadMessageCount);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.receiver;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.activity.MainActivity;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemeHelper;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.web.custom_tab.BrowserFallback;
|
||||
import com.github.dfa.diaspora_android.web.custom_tab.CustomTabActivityHelper;
|
||||
|
||||
/**
|
||||
* BroadcastReceiver that opens links in a Chrome CustomTab
|
||||
* Created by vanitas on 11.09.16.
|
||||
*/
|
||||
public class OpenExternalLinkReceiver extends BroadcastReceiver {
|
||||
private final Activity parent;
|
||||
|
||||
public OpenExternalLinkReceiver(Activity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context c, Intent receiveIntent) {
|
||||
AppSettings appSettings = AppSettings.get();
|
||||
ThemeHelper.getInstance(appSettings);
|
||||
|
||||
AppLog.v(this, "OpenExternalLinkReceiver.onReceive(): url");
|
||||
|
||||
Uri url;
|
||||
try {
|
||||
String sUrl = receiveIntent.getStringExtra(MainActivity.EXTRA_URL);
|
||||
url = Uri.parse(sUrl);
|
||||
} catch (Exception _ignored) {
|
||||
AppLog.v(this, "Could not open Chrome Custom Tab (bad URL)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (appSettings.isChromeCustomTabsEnabled()) {
|
||||
// Setup Chrome Custom Tab
|
||||
CustomTabsIntent.Builder customTab = new CustomTabsIntent.Builder();
|
||||
customTab.setToolbarColor(ThemeHelper.getPrimaryColor());
|
||||
customTab.addDefaultShareMenuItem();
|
||||
|
||||
Bitmap backButtonIcon = BitmapFactory.decodeResource(c.getResources(), R.drawable.chrome_custom_tab__back);
|
||||
customTab.setCloseButtonIcon(backButtonIcon);
|
||||
|
||||
// Launch Chrome Custom Tab
|
||||
CustomTabActivityHelper.openCustomTab(parent, customTab.build(), url, new BrowserFallback());
|
||||
} else {
|
||||
// Open in normal browser (via intent)
|
||||
Intent openBrowserIntent = new Intent(Intent.ACTION_VIEW, url);
|
||||
openBrowserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
c.startActivity(openBrowserIntent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.activity.MainActivity;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
|
||||
/**
|
||||
* BroadcastReceiver used to update the title of the MainActivity depending on the url of the ui__webview
|
||||
* Created by vanitas on 11.09.16.
|
||||
*/
|
||||
public class UpdateTitleReceiver extends BroadcastReceiver {
|
||||
private DiasporaUrlHelper urls;
|
||||
private AppSettings appSettings;
|
||||
private App app;
|
||||
private TitleCallback callback;
|
||||
private String lastUrl;
|
||||
|
||||
public UpdateTitleReceiver(App app, DiasporaUrlHelper urls, TitleCallback callback) {
|
||||
this.urls = urls;
|
||||
this.app = app;
|
||||
this.appSettings = app.getSettings();
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
lastUrl = intent.getStringExtra(MainActivity.EXTRA_URL);
|
||||
if (lastUrl != null && lastUrl.startsWith(urls.getPodUrl())) {
|
||||
String subUrl = lastUrl.substring((urls.getPodUrl()).length());
|
||||
AppLog.spam(this, "onReceive()- Set title for subUrl " + subUrl);
|
||||
if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_STREAM)) {
|
||||
setTitle(R.string.nav_stream);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_POSTS)) {
|
||||
setTitle(R.string.app_name);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_NOTIFICATIONS)) {
|
||||
setTitle(R.string.notifications);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_CONVERSATIONS)) {
|
||||
setTitle(R.string.conversations);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_NEW_POST)) {
|
||||
setTitle(R.string.new_post);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_STATISTICS)) {
|
||||
setTitle(R.string.statistics);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_CONTACTS)) {
|
||||
setTitle(R.string.contacts);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_PEOPLE + appSettings.getProfileId())) {
|
||||
setTitle(R.string.nav_profile);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_ACTIVITY)) {
|
||||
setTitle(R.string.nav_activities);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_LIKED)) {
|
||||
setTitle(R.string.nav_liked);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_COMMENTED)) {
|
||||
setTitle(R.string.nav_commented);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_MENTIONS)) {
|
||||
setTitle(R.string.nav_mentions);
|
||||
} else if (subUrl.startsWith(DiasporaUrlHelper.SUBURL_PUBLIC)) {
|
||||
setTitle(R.string.public_);
|
||||
} else if (urls.isAspectUrl(lastUrl)) {
|
||||
setTitle(urls.getAspectNameFromUrl(lastUrl, app));
|
||||
}
|
||||
} else {
|
||||
AppLog.spam(this, "onReceive()- Invalid url: " + lastUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTitle(int rId) {
|
||||
callback.setTitle(lastUrl, rId);
|
||||
}
|
||||
|
||||
private void setTitle(String title) {
|
||||
callback.setTitle(lastUrl, title);
|
||||
}
|
||||
|
||||
public interface TitleCallback {
|
||||
void setTitle(String url, int resId);
|
||||
|
||||
void setTitle(String url, String title);
|
||||
}
|
||||
}
|
|
@ -1,30 +1,30 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
This file is part of the dandelion*.
|
||||
|
||||
Diaspora for Android is free software: you can redistribute it and/or modify
|
||||
dandelion* 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.
|
||||
|
||||
Diaspora for Android is distributed in the hope that it will be useful,
|
||||
dandelion* 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 the Diaspora for Android.
|
||||
along with the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.dfa.diaspora_android.util;
|
||||
package com.github.dfa.diaspora_android.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.github.dfa.diaspora_android.task.ImageDownloadTask;
|
||||
import net.gsantner.opoc.util.DownloadTask;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -54,7 +54,9 @@ public class AvatarImageLoader {
|
|||
|
||||
public void startImageDownload(ImageView imageView, String avatarUrl) {
|
||||
if (!avatarUrl.equals("")) {
|
||||
new ImageDownloadTask(imageView, avatarFile.getAbsolutePath()).execute(avatarUrl);
|
||||
new DownloadTask(new File(avatarFile.getAbsolutePath()), (ok, file) -> {
|
||||
loadToImageView(imageView);
|
||||
}).execute(avatarUrl);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
import com.github.dfa.diaspora_android.data.DiasporaPodList;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
public class FetchPodsService extends Service {
|
||||
public static final String MESSAGE_PODS_RECEIVED = "com.github.dfa.diaspora.podsreceived";
|
||||
public static final String EXTRA_PODLIST = "pods";
|
||||
|
||||
public FetchPodsService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
new GetPodsTask(this).execute();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// TODO: Return the communication channel to the service.
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
class GetPodsTask extends AsyncTask<Void, Void, DiasporaPodList> {
|
||||
private static final String PODDY_PODLIST_URL = "https://raw.githubusercontent.com/gsantner/dandelion/master/app/src/main/res/raw/podlist.json";
|
||||
|
||||
private final Service service;
|
||||
|
||||
GetPodsTask(Service service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DiasporaPodList doInBackground(Void... params) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
HttpsURLConnection con = NetCipher.getHttpsURLConnection(PODDY_PODLIST_URL);
|
||||
if (con.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
||||
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
|
||||
// Parse JSON & return pod list
|
||||
JSONObject json = new JSONObject(sb.toString());
|
||||
return new DiasporaPodList().fromJson(json);
|
||||
} else {
|
||||
AppLog.e(this, "Failed to download list of pods");
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could not fetch list of pods :(
|
||||
return new DiasporaPodList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(DiasporaPodList pods) {
|
||||
if (pods == null) {
|
||||
pods = new DiasporaPodList();
|
||||
}
|
||||
Intent broadcastIntent = new Intent(FetchPodsService.MESSAGE_PODS_RECEIVED);
|
||||
broadcastIntent.putExtra(FetchPodsService.EXTRA_PODLIST, pods);
|
||||
LocalBroadcastManager.getInstance(service.getApplicationContext()).sendBroadcast(broadcastIntent);
|
||||
service.stopSelf();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
This file is inspired from sourabhsoni.com/implementing-hashtags-in-android-application/
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.service;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public class HashtagContentProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public int delete(Uri arg0, String arg1, String[] arg2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri arg0) {
|
||||
return "vnd.android.cursor.item/vnd.cc.tag";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri arg0, ContentValues arg1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
|
||||
String arg4) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,30 +1,31 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
This file is part of the dandelion*.
|
||||
|
||||
Diaspora for Android is free software: you can redistribute it and/or modify
|
||||
dandelion* 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.
|
||||
|
||||
Diaspora for Android is distributed in the hope that it will be useful,
|
||||
dandelion* 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 the Diaspora for Android.
|
||||
along with the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.task;
|
||||
package com.github.dfa.diaspora_android.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.webkit.CookieManager;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.data.PodUserProfile;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaUserProfile;
|
||||
import com.github.dfa.diaspora_android.util.AppLog;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
@ -43,12 +44,14 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
|
|||
// Code for getting the profile async without any UI/WebView
|
||||
// TODO: This is an early version,needs to be converted to Service
|
||||
|
||||
final App app;
|
||||
final Context context;
|
||||
private final App app;
|
||||
private final Context context;
|
||||
private final DiasporaUrlHelper urls;
|
||||
|
||||
public ProfileFetchTask(final App app) {
|
||||
this.context = app.getApplicationContext();
|
||||
this.app = app;
|
||||
this.urls = new DiasporaUrlHelper(app.getSettings());
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,13 +59,13 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
|
|||
protected Void doInBackground(Void... params) {
|
||||
String extractedProfileData = null;
|
||||
final CookieManager cookieManager = app.getCookieManager();
|
||||
String cookies = cookieManager.getCookie("https://" + app.getSettings().getPodDomain());
|
||||
Log.d(App.TAG, cookies);
|
||||
String cookies = cookieManager.getCookie(urls.getPodUrl());
|
||||
AppLog.d(this, cookies);
|
||||
|
||||
HttpsURLConnection connection;
|
||||
InputStream inStream;
|
||||
try {
|
||||
URL url = new URL("https://" + app.getSettings().getPodDomain() + "/stream");
|
||||
URL url = new URL(urls.getStreamUrl());
|
||||
connection = NetCipher.getHttpsURLConnection(url);
|
||||
connection.setReadTimeout(10000);
|
||||
connection.setConnectTimeout(15000);
|
||||
|
@ -83,10 +86,10 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
|
|||
}
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
br.close();
|
||||
inStream.close();
|
||||
} catch (IOException e){/*Nothing*/}
|
||||
} catch (IOException e) {/*Nothing*/}
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
|
@ -96,9 +99,9 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
|
|||
|
||||
|
||||
if (extractedProfileData != null) {
|
||||
PodUserProfile profile = new PodUserProfile(app);
|
||||
DiasporaUserProfile profile = new DiasporaUserProfile(app);
|
||||
profile.parseJson(extractedProfileData);
|
||||
Log.d(App.TAG, "Extracted new_messages (service):" + profile.getUnreadMessagesCount());
|
||||
AppLog.d(this, "Extracted new_messages (service):" + profile.getUnreadMessagesCount());
|
||||
}
|
||||
|
||||
return null;
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.task;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
public class GetPodsService extends Service {
|
||||
public static final String MESSAGE_PODS_RECEIVED = "com.github.dfa.diaspora.podsreceived";
|
||||
private static final String TAG = App.TAG;
|
||||
|
||||
public GetPodsService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
getPods();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
private void getPods() {
|
||||
/*
|
||||
* Most of the code in this AsyncTask is from the file getPodlistTask.java
|
||||
* from the app "Diaspora Webclient".
|
||||
* A few modifications and adaptations were made by me.
|
||||
* Source:
|
||||
* https://github.com/voidcode/Diaspora-Webclient/blob/master/src/com/voidcode/diasporawebclient/getPodlistTask.java
|
||||
* Thanks to Terkel Sørensen ; License : GPLv3
|
||||
*/
|
||||
AsyncTask<Void, Void, String[]> getPodsAsync = new AsyncTask<Void, Void, String[]>() {
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params) {
|
||||
|
||||
// TODO: Update deprecated code
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
//HttpClient client = new DefaultHttpClient();
|
||||
List<String> list = null;
|
||||
HttpsURLConnection connection;
|
||||
InputStream inStream;
|
||||
try {
|
||||
connection = NetCipher.getHttpsURLConnection("https://podupti.me/api.php?key=4r45tg&format=json");
|
||||
int statusCode = connection.getResponseCode();
|
||||
if (statusCode == 200) {
|
||||
inStream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(inStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
try {
|
||||
inStream.close();
|
||||
} catch (IOException e) {/*Nothing to do*/}
|
||||
|
||||
connection.disconnect();
|
||||
} else {
|
||||
Log.e(TAG, "Failed to download list of pods");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//TODO handle json buggy feed
|
||||
e.printStackTrace();
|
||||
}
|
||||
//Parse the JSON Data
|
||||
try {
|
||||
JSONObject jsonObjectAll = new JSONObject(builder.toString());
|
||||
JSONArray jsonArrayAll = jsonObjectAll.getJSONArray("pods");
|
||||
Log.d(TAG, "Number of entries " + jsonArrayAll.length());
|
||||
list = new ArrayList<>();
|
||||
for (int i = 0; i < jsonArrayAll.length(); i++) {
|
||||
JSONObject jo = jsonArrayAll.getJSONObject(i);
|
||||
if (jo.getString("secure").equals("true"))
|
||||
list.add(jo.getString("domain"));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
//TODO Handle Parsing errors here
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (list != null)
|
||||
return list.toArray(new String[list.size()]);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String[] pods) {
|
||||
Intent broadcastIntent = new Intent(MESSAGE_PODS_RECEIVED);
|
||||
broadcastIntent.putExtra("pods", pods != null ? pods : new String[0]);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(broadcastIntent);
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
getPodsAsync.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// TODO: Return the communication channel to the service.
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.task;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
/**
|
||||
* Task that can be used to download images from URLs and store them in storage
|
||||
* Created by gsantner (https://gsantner.github.io/) on 24.03.16.
|
||||
*/
|
||||
public class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
|
||||
ImageView imageView;
|
||||
String savePath;
|
||||
|
||||
/**
|
||||
* Download image from URL
|
||||
*
|
||||
* @param imageView ImageView to set image to (null = don't set)
|
||||
* @param savePath Save image to file (null = don't save)
|
||||
*/
|
||||
public ImageDownloadTask(@Nullable ImageView imageView, @Nullable String savePath) {
|
||||
this.imageView = imageView;
|
||||
this.savePath = savePath;
|
||||
}
|
||||
|
||||
protected Bitmap doInBackground(String... urls) {
|
||||
String url = urls[0];
|
||||
Bitmap bitmap = null;
|
||||
FileOutputStream out = null;
|
||||
InputStream inStream;
|
||||
HttpsURLConnection connection;
|
||||
try {
|
||||
connection = NetCipher.getHttpsURLConnection(url);
|
||||
inStream = connection.getInputStream();
|
||||
bitmap = BitmapFactory.decodeStream(inStream);
|
||||
|
||||
// Save to file if not null
|
||||
if (savePath != null) {
|
||||
out = new FileOutputStream(savePath);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
}
|
||||
|
||||
try {
|
||||
inStream.close();
|
||||
} catch (IOException e) {/*Nothing*/}
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(App.TAG, e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
// Display on imageview if not null
|
||||
if (imageView != null) {
|
||||
imageView.setImageBitmap(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class BadgeDrawable extends Drawable {
|
||||
// Source: http://mobikul.com/adding-badge-count-on-menu-items-like-cart-notification-etc/
|
||||
private static final String BADGE_VALUE_OVERFLOW = "*";
|
||||
|
||||
private Paint _badgeBackground;
|
||||
private Paint _badgeText;
|
||||
private Rect _textRect = new Rect();
|
||||
|
||||
private String _badgeValue = "";
|
||||
private boolean _shouldDraw;
|
||||
|
||||
public BadgeDrawable(Context context) {
|
||||
float textSize = context.getResources().getDimension(R.dimen.textsize_badge_count);
|
||||
|
||||
AppSettings settings = AppSettings.get();
|
||||
_badgeBackground = new Paint();
|
||||
_badgeBackground.setColor(settings.getAccentColor());
|
||||
_badgeBackground.setAntiAlias(true);
|
||||
_badgeBackground.setStyle(Paint.Style.FILL);
|
||||
|
||||
_badgeText = new Paint();
|
||||
_badgeText.setColor(ContextUtils.get().shouldColorOnTopBeLight(settings.getAccentColor()) ? Color.WHITE : Color.BLACK);
|
||||
_badgeText.setTypeface(Typeface.DEFAULT);
|
||||
_badgeText.setTextSize(textSize);
|
||||
_badgeText.setAntiAlias(true);
|
||||
_badgeText.setTextAlign(Paint.Align.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (!_shouldDraw) {
|
||||
return;
|
||||
}
|
||||
Rect bounds = getBounds();
|
||||
float width = bounds.right - bounds.left;
|
||||
float height = bounds.bottom - bounds.top;
|
||||
float oneDp = ContextUtils.get().convertDpToPx(1);
|
||||
|
||||
// Position the badge in the top-right quadrant of the icon.
|
||||
float radius = ((Math.max(width, height) / 2)) / 2;
|
||||
float centerX = (width - radius - 1) + oneDp * 2;
|
||||
float centerY = radius - 2 * oneDp;
|
||||
canvas.drawCircle(centerX, centerY, (int) (radius + oneDp * 5), _badgeBackground);
|
||||
|
||||
// Draw badge count message inside the circle.
|
||||
_badgeText.getTextBounds(_badgeValue, 0, _badgeValue.length(), _textRect);
|
||||
float textHeight = _textRect.bottom - _textRect.top;
|
||||
float textY = centerY + (textHeight / 2f);
|
||||
canvas.drawText(_badgeValue.length() > 2 ? BADGE_VALUE_OVERFLOW : _badgeValue,
|
||||
centerX, textY, _badgeText);
|
||||
}
|
||||
|
||||
// Sets the text to display. Badge displays a '*' if more than 2 characters
|
||||
private void setBadgeText(String text) {
|
||||
_badgeValue = text;
|
||||
|
||||
// Only draw a badge if the value isn't a zero
|
||||
_shouldDraw = !text.equalsIgnoreCase("0");
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
public static void setBadgeCount(Context context, LayerDrawable icon, Integer count) {
|
||||
setBadgeText(context, icon, count.toString());
|
||||
}
|
||||
|
||||
// Max of 2 characters
|
||||
public static void setBadgeText(Context context, LayerDrawable icon, String text) {
|
||||
BadgeDrawable badge;
|
||||
|
||||
// Reuse drawable if possible
|
||||
Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge);
|
||||
if (reuse != null && reuse instanceof BadgeDrawable) {
|
||||
badge = (BadgeDrawable) reuse;
|
||||
} else {
|
||||
badge = new BadgeDrawable(context);
|
||||
}
|
||||
|
||||
badge.setBadgeText(text);
|
||||
icon.mutate();
|
||||
icon.setDrawableByLayerId(R.id.ic_badge, badge);
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ public class BottomBarBehavior extends CoordinatorLayout.Behavior<LinearLayout>
|
|||
if (defaultDependencyTop == -1) {
|
||||
defaultDependencyTop = dependency.getTop();
|
||||
}
|
||||
if(dependency.getTop()<0)
|
||||
if (dependency.getTop() < 0)
|
||||
child.setTranslationY(-dependency.getTop() + defaultDependencyTop);
|
||||
else
|
||||
child.setTranslationY(defaultDependencyTop);
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.activity.MainActivity;
|
||||
import com.github.dfa.diaspora_android.task.ImageDownloadTask;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Subclass of WebView which adds a context menu for long clicks on images or links to share, save
|
||||
* or open with another browser
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ContextMenuWebView extends NestedWebView {
|
||||
|
||||
public static final int ID_SAVE_IMAGE = 10;
|
||||
public static final int ID_IMAGE_EXTERNAL_BROWSER = 11;
|
||||
public static final int ID_COPY_LINK = 12;
|
||||
public static final int ID_SHARE_LINK = 13;
|
||||
public static final int ID_SHARE_IMAGE = 14;
|
||||
|
||||
private Context context;
|
||||
private Activity parentActivity;
|
||||
private String lasLoadUrl = "";
|
||||
|
||||
public ContextMenuWebView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ContextMenuWebView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateContextMenu(ContextMenu menu) {
|
||||
super.onCreateContextMenu(menu);
|
||||
|
||||
HitTestResult result = getHitTestResult();
|
||||
|
||||
MenuItem.OnMenuItemClickListener handler = new MenuItem.OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
HitTestResult result = getHitTestResult();
|
||||
String url = result.getExtra();
|
||||
switch (item.getItemId()) {
|
||||
//Save image to external memory
|
||||
case ID_SAVE_IMAGE: {
|
||||
boolean writeToStoragePermitted = true;
|
||||
if (android.os.Build.VERSION.SDK_INT >= 23) {
|
||||
int hasWRITE_EXTERNAL_STORAGE = parentActivity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (hasWRITE_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) {
|
||||
writeToStoragePermitted = false;
|
||||
if (!parentActivity.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
new AlertDialog.Builder(parentActivity)
|
||||
.setMessage(R.string.permissions_image)
|
||||
.setPositiveButton(context.getText(android.R.string.yes), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 23)
|
||||
parentActivity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
MainActivity.REQUEST_CODE_ASK_PERMISSIONS_SAVE_IMAGE);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(context.getText(android.R.string.no), null)
|
||||
.show();
|
||||
}
|
||||
parentActivity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
MainActivity.REQUEST_CODE_ASK_PERMISSIONS_SAVE_IMAGE);
|
||||
}
|
||||
}
|
||||
if (writeToStoragePermitted) {
|
||||
if (url != null) {
|
||||
Uri source = Uri.parse(url);
|
||||
DownloadManager.Request request = new DownloadManager.Request(source);
|
||||
File destinationFile = new File(Environment.getExternalStorageDirectory() + "/Pictures/Diaspora/"
|
||||
+ System.currentTimeMillis() + ".png");
|
||||
request.setDestinationUri(Uri.fromFile(destinationFile));
|
||||
((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
Toast.makeText(context, context.getText(R.string.share__toast_saved_image_to_location) + " " +
|
||||
destinationFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_SHARE_IMAGE:
|
||||
if (url != null) {
|
||||
final Uri local = Uri.parse(Environment.getExternalStorageDirectory() + "/Pictures/Diaspora/" + System.currentTimeMillis() + ".png");
|
||||
new ImageDownloadTask(null, local.getPath()) {
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
Uri myUri = Uri.fromFile(new File(local.getPath()));
|
||||
Intent sharingIntent = new Intent();
|
||||
sharingIntent.setAction(Intent.ACTION_SEND);
|
||||
sharingIntent.putExtra(Intent.EXTRA_STREAM, myUri);
|
||||
sharingIntent.setType("image/png");
|
||||
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
context.startActivity(Intent.createChooser(sharingIntent, "Share image using"));
|
||||
}
|
||||
}.execute(url);
|
||||
} else {
|
||||
Toast.makeText(context, "Cannot share image: url is null", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_IMAGE_EXTERNAL_BROWSER:
|
||||
if (url != null) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
break;
|
||||
|
||||
//Copy url to clipboard
|
||||
case ID_COPY_LINK:
|
||||
if (url != null) {
|
||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("text", url));
|
||||
Toast.makeText(context, R.string.share__toast_link_address_copied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
|
||||
//Try to share link to other apps
|
||||
case ID_SHARE_LINK:
|
||||
if (url != null) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, url);
|
||||
sendIntent.setType("text/plain");
|
||||
context.startActivity(Intent.createChooser(sendIntent, getResources()
|
||||
.getText(R.string.context_menu_share_link)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//Build context menu
|
||||
if (result.getType() == HitTestResult.IMAGE_TYPE ||
|
||||
result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
|
||||
// Menu options for an image.
|
||||
menu.setHeaderTitle(result.getExtra());
|
||||
menu.add(0, ID_SAVE_IMAGE, 0, context.getString(R.string.context_menu_save_image)).setOnMenuItemClickListener(handler);
|
||||
menu.add(0, ID_IMAGE_EXTERNAL_BROWSER, 0, context.getString(R.string.context_menu_open_external_browser)).setOnMenuItemClickListener(handler);
|
||||
menu.add(0, ID_SHARE_IMAGE, 0, context.getString(R.string.context_menu_share_image)).setOnMenuItemClickListener(handler);
|
||||
} else if (result.getType() == HitTestResult.ANCHOR_TYPE ||
|
||||
result.getType() == HitTestResult.SRC_ANCHOR_TYPE) {
|
||||
// Menu options for a hyperlink.
|
||||
menu.setHeaderTitle(result.getExtra());
|
||||
menu.add(0, ID_COPY_LINK, 0, context.getString(R.string.context_menu_copy_link)).setOnMenuItemClickListener(handler);
|
||||
menu.add(0, ID_SHARE_LINK, 0, context.getString(R.string.context_menu_share_link)).setOnMenuItemClickListener(handler);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUrlNew(String url){
|
||||
stopLoading();
|
||||
loadUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadUrl(String url) {
|
||||
super.loadUrl(url);
|
||||
|
||||
// Don't spam intents ;)
|
||||
if (!lasLoadUrl.equals(url)) {
|
||||
Intent updateActivityTitleIntent = new Intent(MainActivity.ACTION_UPDATE_TITLE_FROM_URL);
|
||||
updateActivityTitleIntent.putExtra(MainActivity.EXTRA_URL, getUrl());
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(updateActivityTitleIntent);
|
||||
}
|
||||
lasLoadUrl = url;
|
||||
}
|
||||
|
||||
public void setParentActivity(Activity activity) {
|
||||
this.parentActivity = activity;
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
This file is part of the Diaspora for Android.
|
||||
|
||||
Diaspora for Android 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.
|
||||
|
||||
Diaspora for Android 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 the Diaspora for Android.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
|
||||
public class CustomWebViewClient extends WebViewClient {
|
||||
private App app;
|
||||
private WebView webView;
|
||||
|
||||
public CustomWebViewClient(App app, WebView webView) {
|
||||
this.app = app;
|
||||
this.webView = webView;
|
||||
}
|
||||
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (!url.contains(app.getSettings().getPodDomain())) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
app.getApplicationContext().startActivity(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
final CookieManager cookieManager = app.getCookieManager();
|
||||
String cookies = cookieManager.getCookie(url);
|
||||
//Log.d(App.TAG, "All the cookies in a string:" + cookies);
|
||||
|
||||
if (cookies != null) {
|
||||
cookieManager.setCookie(url, cookies);
|
||||
cookieManager.setCookie("https://" + app.getSettings().getPodDomain(), cookies);
|
||||
//for (String c : cookies.split(";")) {
|
||||
// Log.d(App.TAG, "Cookie: " + c.split("=")[0] + " Value:" + c.split("=")[1]);
|
||||
//}
|
||||
//new ProfileFetchTask(app).execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Patterns;
|
||||
|
||||
import com.github.dfa.diaspora_android.activity.MainActivity;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* TextView, that renders HTML with highlited and clickable links and hashtags.
|
||||
* Links are opened in a webbrowser.
|
||||
* Hashtags open the MainActivity, load the new-post site of the selected pod and insert the
|
||||
* hashtag into the post editor. See data/HashtagContentProvider.
|
||||
*/
|
||||
public class HtmlTextView extends AppCompatTextView {
|
||||
|
||||
public HtmlTextView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public HtmlTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public HtmlTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Linkify, format markdown and escape the displayed message.
|
||||
*/
|
||||
private void init() {
|
||||
formatHtmlAndCustomTags();
|
||||
}
|
||||
|
||||
public void setTextFormatted(String text) {
|
||||
setText(text);
|
||||
formatHtmlAndCustomTags();
|
||||
}
|
||||
|
||||
private void formatHtmlAndCustomTags() {
|
||||
setText(new SpannableString(Html.fromHtml(getText().toString())));
|
||||
Linkify.TransformFilter filter = new Linkify.TransformFilter() {
|
||||
public final String transformUrl(final Matcher match, String url) {
|
||||
return match.group();
|
||||
}
|
||||
};
|
||||
|
||||
Pattern hashtagPattern = Pattern.compile("[#]+[A-Za-z0-9-_]+\\b");
|
||||
String hashtagScheme = MainActivity.CONTENT_HASHTAG;
|
||||
Linkify.addLinks(this, hashtagPattern, hashtagScheme, null, filter);
|
||||
|
||||
Pattern urlPattern = Patterns.WEB_URL;
|
||||
Linkify.addLinks(this, urlPattern, null, null, filter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaPodList.DiasporaPod;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaPodList.DiasporaPod.DiasporaPodUrl;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemeHelper;
|
||||
import com.github.dfa.diaspora_android.ui.theme.ThemedAppCompatDialogFragment;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.web.ProxyHandler;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.OnItemSelected;
|
||||
|
||||
/**
|
||||
* Dialog that helps the user configure a pod
|
||||
* Created by gsantner on 06.10.16.
|
||||
*/
|
||||
public class PodSelectionDialog extends ThemedAppCompatDialogFragment {
|
||||
public static final String TAG = "com.github.dfa.diaspora_android.ui.PodSelectionDialog";
|
||||
|
||||
public interface PodSelectionDialogResultListener {
|
||||
void onPodSelectionDialogResult(DiasporaPod pod, boolean accepted);
|
||||
}
|
||||
|
||||
public static PodSelectionDialog newInstance(PodSelectionDialogResultListener resultListener) {
|
||||
return newInstance(new DiasporaPod(), resultListener);
|
||||
}
|
||||
|
||||
public static PodSelectionDialog newInstance(DiasporaPod pod, PodSelectionDialogResultListener resultListener) {
|
||||
PodSelectionDialog dialog = new PodSelectionDialog();
|
||||
dialog.setPod(pod);
|
||||
dialog.setResultListener(resultListener);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/*
|
||||
// ██████╗ ██╗ █████╗ ██╗ ██████╗ ██████╗
|
||||
// ██╔══██╗██║██╔══██╗██║ ██╔═══██╗██╔════╝
|
||||
// ██║ ██║██║███████║██║ ██║ ██║██║ ███╗
|
||||
// ██║ ██║██║██╔══██║██║ ██║ ██║██║ ██║
|
||||
// ██████╔╝██║██║ ██║███████╗╚██████╔╝╚██████╔╝
|
||||
// ╚═════╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝
|
||||
*/
|
||||
|
||||
@BindView(R.id.podselection__dialog__edit_podaddress)
|
||||
EditText editPodAddress;
|
||||
|
||||
@BindView(R.id.podselection__dialog__edit_pod_name)
|
||||
EditText editPodName;
|
||||
|
||||
@BindView(R.id.podselection__dialog__radiogroup_protocol)
|
||||
RadioGroup radiogrpProtocol;
|
||||
|
||||
@BindView(R.id.podselection__dialog__text_profile)
|
||||
TextView textProfile;
|
||||
|
||||
@BindView(R.id.podselection__dialog__spinner_profile)
|
||||
Spinner spinnerProfile;
|
||||
|
||||
@BindView(R.id.podselection__dialog__check_torpreset)
|
||||
CheckBox checkboxTorPreset;
|
||||
|
||||
@BindView(R.id.podselection__dialog__text_torpreset)
|
||||
TextView textTorPreset;
|
||||
|
||||
@BindView(R.id.podselection__dialog__text_pod_name)
|
||||
TextView textPodName;
|
||||
|
||||
@BindView(R.id.podselection__dialog__text_pod_address)
|
||||
TextView textPodAddress;
|
||||
|
||||
@BindView(R.id.podselection__dialog__text_protocol)
|
||||
TextView textProtocol;
|
||||
|
||||
@BindView(R.id.podselection__dialog__btn_ok)
|
||||
Button btnOk;
|
||||
|
||||
@BindView(R.id.podselection__dialog__btn_cancel)
|
||||
Button btnCancel;
|
||||
|
||||
private PodSelectionDialogResultListener resultListener;
|
||||
private View root;
|
||||
private DiasporaPod pod = new DiasporaPod();
|
||||
private App app;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@SuppressLint("InflateParams")
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
app = (App) getActivity().getApplication();
|
||||
|
||||
// Bind UI
|
||||
root = inflater.inflate(R.layout.podselection__dialog, null);
|
||||
ButterKnife.bind(this, root);
|
||||
editPodName.setText(pod.getName());
|
||||
List<DiasporaPodUrl> podUrls = pod.getPodUrls();
|
||||
if (podUrls.size() > 0) {
|
||||
uiLoadDiasporaUrl(0);
|
||||
}
|
||||
if (podUrls.size() > 1) {
|
||||
textProfile.setVisibility(View.VISIBLE);
|
||||
spinnerProfile.setVisibility(View.VISIBLE);
|
||||
String[] podUrlss = new String[podUrls.size()];
|
||||
for (int i = 0; i < podUrls.size(); podUrlss[i] = podUrls.get(i++).getBaseUrl()) ;
|
||||
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, podUrlss);
|
||||
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinnerProfile.setAdapter(spinnerAdapter);
|
||||
}
|
||||
applyColorsToViews();
|
||||
builder.setView(root);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
protected void applyColorsToViews() {
|
||||
ThemeHelper.getInstance(app.getSettings());
|
||||
|
||||
textPodAddress.setTextColor(ThemeHelper.getAccentColor());
|
||||
textPodName.setTextColor(ThemeHelper.getAccentColor());
|
||||
textProfile.setTextColor(ThemeHelper.getAccentColor());
|
||||
textProtocol.setTextColor(ThemeHelper.getAccentColor());
|
||||
textTorPreset.setTextColor(ThemeHelper.getAccentColor());
|
||||
btnOk.setTextColor(ThemeHelper.getAccentColor());
|
||||
btnCancel.setTextColor(ThemeHelper.getAccentColor());
|
||||
|
||||
ThemeHelper.updateEditTextColor(editPodAddress);
|
||||
ThemeHelper.updateEditTextColor(editPodName);
|
||||
ThemeHelper.updateCheckBoxColor(checkboxTorPreset);
|
||||
ThemeHelper.updateRadioGroupColor(radiogrpProtocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppSettings getAppSettings() {
|
||||
if (isAdded()) {
|
||||
return ((App) getActivity().getApplication()).getSettings();
|
||||
} else {
|
||||
return AppSettings.get();
|
||||
}
|
||||
}
|
||||
|
||||
@OnItemSelected(R.id.podselection__dialog__spinner_profile)
|
||||
public void spinnerItemSelected(Spinner spinner, int position) {
|
||||
uiLoadDiasporaUrl(position);
|
||||
}
|
||||
|
||||
public void uiLoadDiasporaUrl(int wantedPodUrlPos) {
|
||||
List<DiasporaPodUrl> podUrls = pod.getPodUrls();
|
||||
if (podUrls.size() == 0) {
|
||||
return;
|
||||
}
|
||||
wantedPodUrlPos = wantedPodUrlPos < podUrls.size() ? wantedPodUrlPos : 0;
|
||||
|
||||
DiasporaPodUrl url1 = podUrls.get(wantedPodUrlPos);
|
||||
editPodAddress.setText(url1.getHost());
|
||||
radiogrpProtocol.check(url1.getProtocol().equals("https")
|
||||
? R.id.podselection__dialog__radio_https : R.id.podselection__dialog__radio_http);
|
||||
|
||||
// Tor
|
||||
boolean isOnionUrl = url1.getHost().endsWith(".onion");
|
||||
setUiVisible(textTorPreset, isOnionUrl);
|
||||
setUiVisible(checkboxTorPreset, isOnionUrl);
|
||||
checkboxTorPreset.setChecked(isOnionUrl);
|
||||
}
|
||||
|
||||
public void setUiVisible(View view, boolean visible) {
|
||||
if (view != null) {
|
||||
view.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OnClick({R.id.podselection__dialog__btn_ok, R.id.podselection__dialog__btn_cancel})
|
||||
public void onResultButtonClicked(View view) {
|
||||
boolean POSITIVE_PRESSED = view.getId() == R.id.podselection__dialog__btn_ok;
|
||||
if (POSITIVE_PRESSED) {
|
||||
if (!checkInputs()) {
|
||||
return;
|
||||
}
|
||||
DiasporaPodUrl podUrl = new DiasporaPodUrl();
|
||||
if (radiogrpProtocol.getCheckedRadioButtonId() == R.id.podselection__dialog__radio_https) {
|
||||
podUrl.setHttpsDefaults();
|
||||
} else {
|
||||
podUrl.setHttpDefaults();
|
||||
}
|
||||
podUrl.setHost(editPodAddress.getText().toString());
|
||||
pod.setName(editPodName.getText().toString());
|
||||
pod.getPodUrls().clear();
|
||||
pod.getPodUrls().add(podUrl);
|
||||
|
||||
// Load Tor preset
|
||||
if (pod.getPodUrl().getHost().endsWith(".onion") && checkboxTorPreset.isChecked()) {
|
||||
AppSettings settings = app.getSettings();
|
||||
settings.setProxyHttpEnabled(true);
|
||||
settings.setProxyWasEnabled(false);
|
||||
settings.setProxyHttpPort(8118);
|
||||
settings.setProxyHttpHost("127.0.0.1");
|
||||
ProxyHandler.getInstance().updateProxySettings(getContext());
|
||||
}
|
||||
|
||||
getDialog().dismiss();
|
||||
publishResult(true);
|
||||
} else {
|
||||
getDialog().cancel();
|
||||
publishResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkInputs() {
|
||||
boolean ok = true;
|
||||
String s = editPodAddress.getText().toString();
|
||||
if (TextUtils.isEmpty(s) || s.length() < 3) {
|
||||
editPodAddress.setError(getString(R.string.missing_value));
|
||||
ok = false;
|
||||
}
|
||||
s = editPodName.getText().toString();
|
||||
if (TextUtils.isEmpty(s) || s.length() < 3) {
|
||||
editPodName.setError(getString(R.string.missing_value));
|
||||
ok = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
public void publishResult(boolean accepted) {
|
||||
if (resultListener != null) {
|
||||
resultListener.onPodSelectionDialogResult(pod, accepted);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GETTER & SETTER
|
||||
*/
|
||||
public PodSelectionDialogResultListener getResultListener() {
|
||||
return resultListener;
|
||||
}
|
||||
|
||||
public void setResultListener(PodSelectionDialogResultListener resultListener) {
|
||||
this.resultListener = resultListener;
|
||||
}
|
||||
|
||||
public DiasporaPod getPod() {
|
||||
return pod;
|
||||
}
|
||||
|
||||
public void setPod(DiasporaPod pod) {
|
||||
try {
|
||||
this.pod = new DiasporaPod().fromJson(pod.toJson());
|
||||
} catch (JSONException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.github.dfa.diaspora_android.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.data.DiasporaAspect;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
import net.gsantner.opoc.ui.SearchOrCustomTextDialog;
|
||||
import net.gsantner.opoc.util.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SearchOrCustomTextDialogCreator {
|
||||
public static final String SPECIAL_PREFIX = "\uD83D\uDCA0";
|
||||
|
||||
public static void showDiasporaTagsDialog(final Activity activity, final Callback.a1<String> callback) {
|
||||
SearchOrCustomTextDialog.DialogOptions dopt = new SearchOrCustomTextDialog.DialogOptions();
|
||||
baseConf(activity, dopt);
|
||||
dopt.callback = callback;
|
||||
dopt.isSearchEnabled = true;
|
||||
dopt.searchHintText = R.string.search;
|
||||
dopt.titleText = R.string.tags;
|
||||
|
||||
new Thread(() -> {
|
||||
AppSettings appSettings = AppSettings.get();
|
||||
ArrayList<String> hl = new ArrayList<>();
|
||||
ArrayList<String> data = new ArrayList<>(Arrays.asList(appSettings.getFollowedTags()));
|
||||
if (data.size() > 0) {
|
||||
String highlighted = surroundString(data.remove(0));
|
||||
data.add(0, highlighted);
|
||||
hl.add(highlighted);
|
||||
}
|
||||
|
||||
for (int strid : new int[]{R.string.manage_hashtags}) {
|
||||
String special = surroundString(appSettings.rstr(strid));
|
||||
data.add(0, special);
|
||||
hl.add(special);
|
||||
}
|
||||
dopt.data = data;
|
||||
dopt.highlightData = hl;
|
||||
activity.runOnUiThread(() -> SearchOrCustomTextDialog.showMultiChoiceDialogWithSearchFilterUI(activity, dopt));
|
||||
}).start();
|
||||
}
|
||||
|
||||
private static String surroundString(String text) {
|
||||
return SPECIAL_PREFIX + " " + text + " ";
|
||||
}
|
||||
|
||||
|
||||
public static void showDiasporaAspectsDialog(final Activity activity, final Callback.a1<String> callback) {
|
||||
SearchOrCustomTextDialog.DialogOptions dopt = new SearchOrCustomTextDialog.DialogOptions();
|
||||
baseConf(activity, dopt);
|
||||
dopt.callback = callback;
|
||||
dopt.isSearchEnabled = false;
|
||||
dopt.titleText = R.string.contacts;
|
||||
|
||||
new Thread(() -> {
|
||||
AppSettings appSettings = AppSettings.get();
|
||||
ArrayList<String> hl = new ArrayList<>();
|
||||
ArrayList<String> data = new ArrayList<>();
|
||||
for (DiasporaAspect aspect : AppSettings.get().getAspects()) {
|
||||
data.add(aspect.name);
|
||||
}
|
||||
for (int strid : new int[]{R.string.nav_profile, R.string.manage_your_contact_list}) {
|
||||
String special = surroundString(appSettings.rstr(strid));
|
||||
data.add(0, special);
|
||||
hl.add(special);
|
||||
}
|
||||
dopt.data = data;
|
||||
dopt.highlightData = hl;
|
||||
activity.runOnUiThread(() -> SearchOrCustomTextDialog.showMultiChoiceDialogWithSearchFilterUI(activity, dopt));
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
private static void baseConf(Activity activity, SearchOrCustomTextDialog.DialogOptions dopt) {
|
||||
AppSettings as = new AppSettings(activity);
|
||||
dopt.isDarkDialog = as.isAmoledColorMode();
|
||||
dopt.textColor = ContextCompat.getColor(activity, dopt.isDarkDialog ? R.color.white : R.color.primary_text);
|
||||
dopt.highlightColor = as.getAccentColor();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.graphics.ColorUtils;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
|
||||
/**
|
||||
* Class that handles Colors
|
||||
* Created by dnld on 24/02/16.
|
||||
*/
|
||||
public class ColorPalette {
|
||||
|
||||
public static int[] getAccentColors(Context context) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_red_500),
|
||||
ContextCompat.getColor(context, R.color.md_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_500),
|
||||
ContextCompat.getColor(context, R.color.md_teal_500),
|
||||
ContextCompat.getColor(context, R.color.md_green_500),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_500),
|
||||
ContextCompat.getColor(context, R.color.md_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_brown_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_500),
|
||||
};
|
||||
}
|
||||
|
||||
public static int getObscuredColor(int c) {
|
||||
float[] hsv = new float[3];
|
||||
int color = c;
|
||||
Color.colorToHSV(color, hsv);
|
||||
hsv[2] *= 0.85f; // value component
|
||||
color = Color.HSVToColor(hsv);
|
||||
return color;
|
||||
}
|
||||
|
||||
public static int getTransparentColor(int color, int alpha) {
|
||||
return ColorUtils.setAlphaComponent(color, alpha);
|
||||
}
|
||||
|
||||
public static int[] getTransparencyShadows(int color) {
|
||||
int[] shadows = new int[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
shadows[i] = (ColorPalette.getTransparentColor(color, ((100 - (i * 10)) * 255) / 100));
|
||||
return shadows;
|
||||
}
|
||||
|
||||
public static int[] getBaseColors(Context context) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_red_500),
|
||||
ContextCompat.getColor(context, R.color.md_pink_500),
|
||||
ContextCompat.getColor(context, R.color.md_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_500),
|
||||
ContextCompat.getColor(context, R.color.md_teal_500),
|
||||
ContextCompat.getColor(context, R.color.md_green_500),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_500),
|
||||
ContextCompat.getColor(context, R.color.md_lime_500),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_500),
|
||||
ContextCompat.getColor(context, R.color.md_amber_500),
|
||||
ContextCompat.getColor(context, R.color.md_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_brown_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_500),
|
||||
ContextCompat.getColor(context, R.color.md_grey_500)
|
||||
};
|
||||
}
|
||||
|
||||
public static int[] getColors(Context context, int c) {
|
||||
if (c == ContextCompat.getColor(context, R.color.md_red_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_red_200),
|
||||
ContextCompat.getColor(context, R.color.md_red_300),
|
||||
ContextCompat.getColor(context, R.color.md_red_400),
|
||||
ContextCompat.getColor(context, R.color.md_red_500),
|
||||
ContextCompat.getColor(context, R.color.md_red_600),
|
||||
ContextCompat.getColor(context, R.color.md_red_700),
|
||||
ContextCompat.getColor(context, R.color.md_red_800),
|
||||
ContextCompat.getColor(context, R.color.md_red_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_pink_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_pink_200),
|
||||
ContextCompat.getColor(context, R.color.md_pink_300),
|
||||
ContextCompat.getColor(context, R.color.md_pink_400),
|
||||
ContextCompat.getColor(context, R.color.md_pink_500),
|
||||
ContextCompat.getColor(context, R.color.md_pink_600),
|
||||
ContextCompat.getColor(context, R.color.md_pink_700),
|
||||
ContextCompat.getColor(context, R.color.md_pink_800),
|
||||
ContextCompat.getColor(context, R.color.md_pink_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_purple_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_purple_200),
|
||||
ContextCompat.getColor(context, R.color.md_purple_300),
|
||||
ContextCompat.getColor(context, R.color.md_purple_400),
|
||||
ContextCompat.getColor(context, R.color.md_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_purple_600),
|
||||
ContextCompat.getColor(context, R.color.md_purple_700),
|
||||
ContextCompat.getColor(context, R.color.md_purple_800),
|
||||
ContextCompat.getColor(context, R.color.md_purple_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_deep_purple_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_200),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_300),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_400),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_600),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_700),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_800),
|
||||
ContextCompat.getColor(context, R.color.md_deep_purple_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_indigo_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_indigo_200),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_300),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_400),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_500),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_600),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_700),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_800),
|
||||
ContextCompat.getColor(context, R.color.md_indigo_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_blue_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_blue_200),
|
||||
ContextCompat.getColor(context, R.color.md_blue_300),
|
||||
ContextCompat.getColor(context, R.color.md_blue_400),
|
||||
ContextCompat.getColor(context, R.color.md_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_600),
|
||||
ContextCompat.getColor(context, R.color.md_blue_650),
|
||||
ContextCompat.getColor(context, R.color.md_blue_700),
|
||||
ContextCompat.getColor(context, R.color.md_blue_750),
|
||||
ContextCompat.getColor(context, R.color.md_blue_800),
|
||||
ContextCompat.getColor(context, R.color.md_blue_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_light_blue_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_200),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_300),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_400),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_500),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_600),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_700),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_800),
|
||||
ContextCompat.getColor(context, R.color.md_light_blue_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_cyan_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_cyan_200),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_300),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_400),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_500),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_600),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_700),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_800),
|
||||
ContextCompat.getColor(context, R.color.md_cyan_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_teal_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_teal_200),
|
||||
ContextCompat.getColor(context, R.color.md_teal_300),
|
||||
ContextCompat.getColor(context, R.color.md_teal_400),
|
||||
ContextCompat.getColor(context, R.color.md_teal_500),
|
||||
ContextCompat.getColor(context, R.color.md_teal_600),
|
||||
ContextCompat.getColor(context, R.color.md_teal_700),
|
||||
ContextCompat.getColor(context, R.color.md_teal_800),
|
||||
ContextCompat.getColor(context, R.color.md_teal_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_green_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_green_200),
|
||||
ContextCompat.getColor(context, R.color.md_green_300),
|
||||
ContextCompat.getColor(context, R.color.md_green_400),
|
||||
ContextCompat.getColor(context, R.color.md_green_500),
|
||||
ContextCompat.getColor(context, R.color.md_green_600),
|
||||
ContextCompat.getColor(context, R.color.md_green_700),
|
||||
ContextCompat.getColor(context, R.color.md_green_800),
|
||||
ContextCompat.getColor(context, R.color.md_green_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_light_green_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_light_green_200),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_300),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_400),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_500),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_600),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_700),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_800),
|
||||
ContextCompat.getColor(context, R.color.md_light_green_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_lime_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_lime_200),
|
||||
ContextCompat.getColor(context, R.color.md_lime_300),
|
||||
ContextCompat.getColor(context, R.color.md_lime_400),
|
||||
ContextCompat.getColor(context, R.color.md_lime_500),
|
||||
ContextCompat.getColor(context, R.color.md_lime_600),
|
||||
ContextCompat.getColor(context, R.color.md_lime_700),
|
||||
ContextCompat.getColor(context, R.color.md_lime_800),
|
||||
ContextCompat.getColor(context, R.color.md_lime_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_yellow_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_yellow_400),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_500),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_600),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_700),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_800),
|
||||
ContextCompat.getColor(context, R.color.md_yellow_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_amber_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_amber_200),
|
||||
ContextCompat.getColor(context, R.color.md_amber_300),
|
||||
ContextCompat.getColor(context, R.color.md_amber_400),
|
||||
ContextCompat.getColor(context, R.color.md_amber_500),
|
||||
ContextCompat.getColor(context, R.color.md_amber_600),
|
||||
ContextCompat.getColor(context, R.color.md_amber_700),
|
||||
ContextCompat.getColor(context, R.color.md_amber_800),
|
||||
ContextCompat.getColor(context, R.color.md_amber_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_orange_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_orange_200),
|
||||
ContextCompat.getColor(context, R.color.md_orange_300),
|
||||
ContextCompat.getColor(context, R.color.md_orange_400),
|
||||
ContextCompat.getColor(context, R.color.md_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_orange_600),
|
||||
ContextCompat.getColor(context, R.color.md_orange_700),
|
||||
ContextCompat.getColor(context, R.color.md_orange_800),
|
||||
ContextCompat.getColor(context, R.color.md_orange_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_deep_orange_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_200),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_300),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_400),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_500),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_600),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_650),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_700),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_800),
|
||||
ContextCompat.getColor(context, R.color.md_deep_orange_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_brown_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_brown_200),
|
||||
ContextCompat.getColor(context, R.color.md_brown_300),
|
||||
ContextCompat.getColor(context, R.color.md_brown_400),
|
||||
ContextCompat.getColor(context, R.color.md_brown_500),
|
||||
ContextCompat.getColor(context, R.color.md_brown_600),
|
||||
ContextCompat.getColor(context, R.color.md_brown_700),
|
||||
ContextCompat.getColor(context, R.color.md_brown_800),
|
||||
ContextCompat.getColor(context, R.color.md_brown_900)
|
||||
};
|
||||
} else if (c == ContextCompat.getColor(context, R.color.md_grey_500)) {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_grey_400),
|
||||
ContextCompat.getColor(context, R.color.md_grey_500),
|
||||
ContextCompat.getColor(context, R.color.md_grey_600),
|
||||
ContextCompat.getColor(context, R.color.md_grey_700),
|
||||
ContextCompat.getColor(context, R.color.md_grey_800),
|
||||
ContextCompat.getColor(context, R.color.md_grey_900),
|
||||
Color.parseColor("#000000")
|
||||
};
|
||||
} else {
|
||||
return new int[]{
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_300),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_400),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_500),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_600),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_700),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_800),
|
||||
ContextCompat.getColor(context, R.color.md_blue_grey_900)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
This class is inspired by org.horasapps.LeafPic
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Build;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.CompoundButtonCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.ActionMenuView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* Singleton that can be used to color views
|
||||
* Created by vanitas on 06.10.16.
|
||||
*/
|
||||
|
||||
public class ThemeHelper {
|
||||
private AppSettings appSettings;
|
||||
private static ThemeHelper instance;
|
||||
|
||||
private ThemeHelper(AppSettings appSettings) {
|
||||
this.appSettings = appSettings;
|
||||
}
|
||||
|
||||
public static ThemeHelper getInstance(AppSettings appSettings) {
|
||||
if (instance == null) {
|
||||
instance = new ThemeHelper(appSettings);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static ThemeHelper getInstance() {
|
||||
if (instance == null)
|
||||
throw new IllegalStateException("ThemeHelper must be initialized using getInstance(AppSettingsBase) before it can be used!");
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void updateEditTextColor(EditText editText) {
|
||||
if (editText != null) {
|
||||
editText.setHighlightColor(getInstance().appSettings.getAccentColor());
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
editText.getBackground().mutate().setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateCheckBoxColor(CheckBox checkBox) {
|
||||
if (checkBox != null) {
|
||||
int states[][] = {{android.R.attr.state_checked}, {}};
|
||||
int colors[] = {ThemeHelper.getAccentColor(), getNeutralGreyColor()};
|
||||
CompoundButtonCompat.setButtonTintList(checkBox, new ColorStateList(states, colors));
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateTabLayoutColor(TabLayout tabLayout) {
|
||||
if (tabLayout != null) {
|
||||
tabLayout.setBackgroundColor(getInstance().appSettings.getPrimaryColor());
|
||||
tabLayout.setSelectedTabIndicatorColor(getInstance().appSettings.getAccentColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateTextViewLinkColor(TextView textView) {
|
||||
if (textView != null) {
|
||||
textView.setHighlightColor(getInstance().appSettings.getAccentColor());
|
||||
textView.setLinkTextColor(getInstance().appSettings.getAccentColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateTextViewTextColor(TextView textView) {
|
||||
if (textView != null) {
|
||||
textView.setTextColor(getInstance().appSettings.getAccentColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateToolbarColor(Toolbar toolbar) {
|
||||
if (toolbar != null) {
|
||||
toolbar.setBackgroundColor(getInstance().appSettings.getPrimaryColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateActionMenuViewColor(ActionMenuView actionMenuView) {
|
||||
if (actionMenuView != null) {
|
||||
actionMenuView.setBackgroundColor(getInstance().appSettings.getPrimaryColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static int getPrimaryColor() {
|
||||
return getInstance().appSettings.getPrimaryColor();
|
||||
}
|
||||
|
||||
public static int getAccentColor() {
|
||||
return getInstance().appSettings.getAccentColor();
|
||||
}
|
||||
|
||||
public static void setPrimaryColorAsBackground(View view) {
|
||||
if (view != null) {
|
||||
view.setBackgroundColor(getPrimaryColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static int getPrimaryDarkColor() {
|
||||
return ColorPalette.getObscuredColor(getPrimaryColor());
|
||||
}
|
||||
|
||||
public static void updateProgressBarColor(ProgressBar progressBar) {
|
||||
if (progressBar != null && progressBar.getProgressDrawable() != null) {
|
||||
progressBar.getProgressDrawable().setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateRadioGroupColor(RadioGroup radioGroup) {
|
||||
if (radioGroup != null && Build.VERSION.SDK_INT >= 21) {
|
||||
for (int i = 0; i < radioGroup.getChildCount(); ++i) {
|
||||
RadioButton btn = ((RadioButton) radioGroup.getChildAt(i));
|
||||
btn.setButtonTintList(new ColorStateList(
|
||||
new int[][]{new int[]{-android.R.attr.state_enabled}, new int[]{android.R.attr.state_enabled}},
|
||||
new int[]{Color.BLACK, ThemeHelper.getAccentColor()}));
|
||||
btn.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getNeutralGreyColor() {
|
||||
return ContextCompat.getColor(getInstance().appSettings.getContext(), R.color.md_grey_800);
|
||||
}
|
||||
|
||||
public static void updateAlertDialogColor(AlertDialog alertDialog) {
|
||||
if (alertDialog != null) {
|
||||
for (int i : new int[]{
|
||||
DialogInterface.BUTTON_POSITIVE,
|
||||
DialogInterface.BUTTON_NEUTRAL,
|
||||
DialogInterface.BUTTON_NEGATIVE}) {
|
||||
Button b = alertDialog.getButton(i);
|
||||
if (b != null) {
|
||||
b.setTextColor(getAccentColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateButtonTextColor(Button button) {
|
||||
if (button != null) {
|
||||
button.setTextColor(getAccentColor());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
/**
|
||||
* Interface that allows setting Theme colors
|
||||
* Created by vanitas on 24.10.16.
|
||||
*/
|
||||
|
||||
public interface Themeable {
|
||||
void setColors();
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Build;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
|
||||
/**
|
||||
* Activity that supports color schemes
|
||||
* Created by vanitas on 06.10.16.
|
||||
*/
|
||||
|
||||
public abstract class ThemedActivity extends AppCompatActivity {
|
||||
|
||||
protected AppSettings getAppSettings() {
|
||||
return ((App) getApplication()).getSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
ThemeHelper.getInstance(getAppSettings());
|
||||
updateLanguage();
|
||||
updateStatusBarColor();
|
||||
updateRecentAppColor();
|
||||
applyColorToViews();
|
||||
updateScreenRotation();
|
||||
}
|
||||
|
||||
protected abstract void applyColorToViews();
|
||||
|
||||
/**
|
||||
* Update color of the status bar
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void updateStatusBarColor() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getWindow().setStatusBarColor(ThemeHelper.getPrimaryDarkColor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update primary color in recent apps overview
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void updateRecentAppColor() {
|
||||
|
||||
}
|
||||
|
||||
protected void updateScreenRotation() {
|
||||
String setting = getAppSettings().getScreenRotation();
|
||||
int rotation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; // Default (system settings)
|
||||
|
||||
if (setting.equals(getString(R.string.rotation_val_sensor))) {
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
||||
} else if (setting.equals(getString(R.string.rotation_val_portrait))) {
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
||||
} else if (setting.equals(getString(R.string.rotation_val_landscape))) {
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
||||
}
|
||||
setRequestedOrientation(rotation);
|
||||
}
|
||||
|
||||
public void updateLanguage() {
|
||||
AppSettings appSettings = getAppSettings();
|
||||
ContextUtils.get().setAppLanguage(appSettings.getLanguage());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StyleRes;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* AlertDialog Builder that colors its buttons
|
||||
* Created by vanitas on 06.11.16.
|
||||
*/
|
||||
|
||||
public class ThemedAlertDialogBuilder extends AlertDialog.Builder {
|
||||
protected AppSettings appSettings;
|
||||
|
||||
public ThemedAlertDialogBuilder(@NonNull Context context, AppSettings appSettings) {
|
||||
super(context);
|
||||
this.appSettings = appSettings;
|
||||
}
|
||||
|
||||
public ThemedAlertDialogBuilder(@NonNull Context context, @StyleRes int themeResId, AppSettings appSettings) {
|
||||
super(context, themeResId);
|
||||
this.appSettings = appSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog create() {
|
||||
final AlertDialog dialog = super.create();
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialogInterface) {
|
||||
applyColors(dialog);
|
||||
}
|
||||
});
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void applyColors(AlertDialog alertDialog) {
|
||||
ThemeHelper.getInstance(appSettings);
|
||||
ThemeHelper.updateAlertDialogColor(alertDialog);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatDialogFragment;
|
||||
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* Themed DialogFragment
|
||||
* Created by vanitas on 22.10.16.
|
||||
*/
|
||||
|
||||
public abstract class ThemedAppCompatDialogFragment extends AppCompatDialogFragment {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
ThemeHelper.getInstance(getAppSettings());
|
||||
return dialog;
|
||||
}
|
||||
|
||||
protected abstract void applyColorsToViews();
|
||||
|
||||
protected abstract AppSettings getAppSettings();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* CheckboxPreference that colors its checkbox with accent color
|
||||
* Created by vanitas on 24.10.16.
|
||||
*/
|
||||
|
||||
public class ThemedCheckBoxPreference extends CheckBoxPreference implements Themeable {
|
||||
protected View rootLayout;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedCheckBoxPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedCheckBoxPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(ViewGroup parent) {
|
||||
rootLayout = super.onCreateView(parent);
|
||||
setColors();
|
||||
return rootLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColors() {
|
||||
CheckBox checkBox = rootLayout.findViewById(android.R.id.checkbox);
|
||||
ThemeHelper.getInstance(AppSettings.get());
|
||||
ThemeHelper.updateCheckBoxColor(checkBox);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.Preference;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
import com.github.dfa.diaspora_android.util.ContextUtils;
|
||||
|
||||
/**
|
||||
* Preference that shows selected Color in a circle
|
||||
* Created by vanitas on 25.10.16.
|
||||
*/
|
||||
|
||||
public class ThemedColorPickerPreference extends Preference implements Themeable {
|
||||
protected ImageView colorPreview;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedColorPickerPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedColorPickerPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedColorPickerPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindView(View view) {
|
||||
super.onBindView(view);
|
||||
colorPreview = view.findViewById(android.R.id.icon);
|
||||
setColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColors() {
|
||||
Drawable circle;
|
||||
if (colorPreview != null && (circle = colorPreview.getDrawable()) != null) {
|
||||
Context c = getContext();
|
||||
AppSettings appSettings = AppSettings.get();
|
||||
String key = getKey();
|
||||
|
||||
int color = ContextUtils.get().rcolor(R.color.primary);
|
||||
if ((appSettings.isKeyEqual(key, R.string.pref_key__primary_color_shade))) {
|
||||
color = appSettings.getPrimaryColor();
|
||||
} else if ((appSettings.isKeyEqual(key, R.string.pref_key__accent_color_shade))) {
|
||||
color = appSettings.getAccentColor();
|
||||
} else {
|
||||
color = appSettings.getColor(key, color, getSharedPreferences());
|
||||
}
|
||||
circle.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
This file is part of the dandelion*.
|
||||
|
||||
dandelion* 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.
|
||||
|
||||
dandelion* 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 the dandelion*.
|
||||
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
import net.gsantner.opoc.activity.GsFragmentBase;
|
||||
|
||||
/**
|
||||
* Fragment that supports color schemes
|
||||
* Created by vanitas on 06.10.16.
|
||||
*/
|
||||
|
||||
public abstract class ThemedFragment extends GsFragmentBase {
|
||||
protected AppSettings getAppSettings() {
|
||||
return ((App) getActivity().getApplication()).getSettings();
|
||||
}
|
||||
|
||||
protected abstract void applyColorToViews();
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
ThemeHelper.getInstance(getAppSettings());
|
||||
applyColorToViews();
|
||||
}
|
||||
|
||||
|
||||
public boolean isAllowedIntellihide() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* PreferenceCategory with a colored title
|
||||
* Created by vanitas on 24.10.16.
|
||||
*/
|
||||
|
||||
public class ThemedPreferenceCategory extends PreferenceCategory implements Themeable {
|
||||
protected TextView titleTextView;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedPreferenceCategory(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedPreferenceCategory(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ThemedPreferenceCategory(Context context, AttributeSet attrs,
|
||||
int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(ViewGroup parent) {
|
||||
View rootLayout = super.onCreateView(parent);
|
||||
this.titleTextView = rootLayout.findViewById(android.R.id.title);
|
||||
setColors();
|
||||
return rootLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColors() {
|
||||
if (titleTextView != null) {
|
||||
ThemeHelper.getInstance(AppSettings.get());
|
||||
ThemeHelper.updateTextViewTextColor(titleTextView);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.os.Build;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.view.Window;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* PreferenceFragment with a colored status bar
|
||||
* Created by vanitas on 24.10.16.
|
||||
*/
|
||||
|
||||
public abstract class ThemedPreferenceFragment extends PreferenceFragment {
|
||||
public abstract void updateViewColors();
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateViewColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
|
||||
if (isAdded()) {
|
||||
App app = ((App) getActivity().getApplication());
|
||||
AppSettings appSettings = app.getSettings();
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (preference instanceof PreferenceScreen && ((PreferenceScreen) preference).getDialog() != null) {
|
||||
Window window = ((PreferenceScreen) preference).getDialog().getWindow();
|
||||
if (window != null) {
|
||||
ThemeHelper.getInstance(appSettings);
|
||||
window.setStatusBarColor(ThemeHelper.getPrimaryDarkColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(screen, preference);
|
||||
}
|
||||
|
||||
public abstract String getFragmentTag();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.github.dfa.diaspora_android.ui.theme;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.util.AppSettings;
|
||||
|
||||
/**
|
||||
* ThemedCheckBoxPreference with visibility icons instead of checkbox. TODO: Make more flexible?
|
||||
* Created by vanitas on 25.10.16.
|
||||
*/
|
||||
|
||||
public class ThemedVisibilityPreference extends ThemedCheckBoxPreference {
|
||||
public ThemedVisibilityPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ThemedVisibilityPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ThemedVisibilityPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColors() {
|
||||
CheckBox checkBox = rootLayout.findViewById(android.R.id.checkbox);
|
||||
checkBox.setButtonDrawable(R.drawable.ic_visibility_selector);
|
||||
ThemeHelper.getInstance(AppSettings.get());
|
||||
ThemeHelper.updateCheckBoxColor(checkBox);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.github.dfa.diaspora_android.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.view.View;
|
||||
|
||||
import com.github.dfa.diaspora_android.BuildConfig;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import com.github.dfa.diaspora_android.web.WebHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue"})
|
||||
public class ActivityUtils extends net.gsantner.opoc.util.ActivityUtils {
|
||||
public ActivityUtils(Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
|
||||
public static ActivityUtils get(Activity activity) {
|
||||
return new ActivityUtils(activity);
|
||||
}
|
||||
|
||||
public File createImageFile() throws IOException {
|
||||
// Create an image file name
|
||||
String timeStamp = new SimpleDateFormat("dd-MM-yy_HH-mm", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
AppLog.d(ActivityUtils.class, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
|
||||
File storageDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PICTURES);
|
||||
return new File(
|
||||
imageFileName + /* prefix */
|
||||
".jpg", /* suffix */
|
||||
storageDir.getAbsolutePath() /* directory */
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Information if user is offline, returns true if is not connected to internet
|
||||
*
|
||||
* @param anchor A view anchor
|
||||
*/
|
||||
public boolean showInfoIfUserNotConnectedToInternet(View anchor) {
|
||||
boolean isOnline = WebHelper.isOnline(_context);
|
||||
if (!isOnline) {
|
||||
showSnackBar(R.string.sorry_need_to_be_connected_to_internet, true);
|
||||
}
|
||||
return !isOnline;
|
||||
}
|
||||
|
||||
public void logBundle(Bundle savedInstanceState, String k) {
|
||||
if (savedInstanceState != null) {
|
||||
for (String key : savedInstanceState.keySet()) {
|
||||
AppLog.d("Bundle", key + " is a key in the bundle " + k);
|
||||
Object bun = savedInstanceState.get(key);
|
||||
if (bun != null) {
|
||||
if (bun instanceof Bundle) {
|
||||
logBundle((Bundle) bun, k + "." + key);
|
||||
} else if (bun instanceof byte[]) {
|
||||
AppLog.d("Bundle", "Key: " + k + "." + key + ": " + Arrays.toString((byte[]) bun));
|
||||
} else {
|
||||
AppLog.d("Bundle", "Key: " + k + "." + key + ": " + bun.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates file sharing uri by using FileProvider
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Uri getFileSharingUri(Context context, File file) {
|
||||
return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.github.dfa.diaspora_android.util;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
// From https://stackoverflow.com/a/19494006
|
||||
public class AndroidBug5497Workaround {
|
||||
|
||||
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
||||
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
||||
|
||||
public static void assistActivity(Activity activity) {
|
||||
new AndroidBug5497Workaround(activity);
|
||||
}
|
||||
|
||||
private View mChildOfContent;
|
||||
private int usableHeightPrevious;
|
||||
private FrameLayout.LayoutParams frameLayoutParams;
|
||||
|
||||
private AndroidBug5497Workaround(Activity activity) {
|
||||
FrameLayout content = activity.findViewById(android.R.id.content);
|
||||
mChildOfContent = content.getChildAt(0);
|
||||
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
possiblyResizeChildOfContent();
|
||||
}
|
||||
});
|
||||
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
||||
}
|
||||
|
||||
private void possiblyResizeChildOfContent() {
|
||||
int usableHeightNow = computeUsableHeight();
|
||||
if (usableHeightNow != usableHeightPrevious) {
|
||||
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
|
||||
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
||||
if (heightDifference > (usableHeightSansKeyboard / 4)) {
|
||||
// keyboard probably just became visible
|
||||
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
||||
} else {
|
||||
// keyboard probably just became hidden
|
||||
frameLayoutParams.height = usableHeightSansKeyboard;
|
||||
}
|
||||
mChildOfContent.requestLayout();
|
||||
usableHeightPrevious = usableHeightNow;
|
||||
}
|
||||
}
|
||||
|
||||
private int computeUsableHeight() {
|
||||
Rect r = new Rect();
|
||||
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
||||
return (r.bottom - r.top);
|
||||
}
|
||||
|
||||
}
|