summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle8
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java7
-rw-r--r--app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt201
-rw-r--r--app/src/main/assets/LICENSE_APACHE-2.0.txt (renamed from app/src/main/assets/LICENSE_APACHE_COMMONS.txt)0
-rw-r--r--app/src/main/assets/LICENSE_EVENTBUS.txt202
-rw-r--r--app/src/main/assets/LICENSE_FLATTR4J.txt202
-rw-r--r--app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt201
-rw-r--r--app/src/main/assets/LICENSE_OKIO.txt202
-rw-r--r--app/src/main/assets/LICENSE_RX_ANDROID.txt200
-rw-r--r--app/src/main/assets/LICENSE_STACKBLUR.txt71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java595
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java547
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java199
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java198
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java193
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java85
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java48
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java172
-rw-r--r--app/src/main/res/layout/audio_controls.xml146
-rw-r--r--app/src/main/res/layout/audioplayer_activity.xml266
-rw-r--r--app/src/main/res/layout/choose_speed_dialog.xml45
-rw-r--r--app/src/main/res/layout/cover_fragment.xml63
-rw-r--r--app/src/main/res/menu/mediaplayer.xml27
-rw-r--r--app/src/main/templates/about.html16
-rw-r--r--build.gradle6
-rw-r--r--core/build.gradle1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java47
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java28
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java58
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java90
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java11
-rw-r--r--core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.pngbin0 -> 302 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_skip_white_36dp.pngbin0 -> 304 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.pngbin0 -> 421 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 659 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.pngbin0 -> 431 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.pngbin0 -> 361 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.pngbin0 -> 637 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.pngbin0 -> 637 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.pngbin0 -> 460 bytes
-rw-r--r--core/src/main/res/drawable-hdpi/ic_star_white_24dp.pngbin0 -> 454 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.pngbin0 -> 218 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_skip_white_36dp.pngbin0 -> 216 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.pngbin0 -> 336 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 472 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.pngbin0 -> 323 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.pngbin0 -> 252 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.pngbin0 -> 410 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.pngbin0 -> 410 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.pngbin0 -> 307 bytes
-rw-r--r--core/src/main/res/drawable-mdpi/ic_star_white_24dp.pngbin0 -> 302 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.pngbin0 -> 364 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.pngbin0 -> 368 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.pngbin0 -> 494 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 769 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.pngbin0 -> 486 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.pngbin0 -> 367 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.pngbin0 -> 828 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.pngbin0 -> 821 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.pngbin0 -> 593 bytes
-rw-r--r--core/src/main/res/drawable-xhdpi/ic_star_white_24dp.pngbin0 -> 582 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.pngbin0 -> 533 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.pngbin0 -> 543 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.pngbin0 -> 737 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 1113 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.pngbin0 -> 664 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.pngbin0 -> 509 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.pngbin0 -> 1227 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.pngbin0 -> 1222 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.pngbin0 -> 877 bytes
-rw-r--r--core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.pngbin0 -> 870 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.pngbin0 -> 737 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.pngbin0 -> 749 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.pngbin0 -> 955 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.pngbin0 -> 1514 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.pngbin0 -> 882 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.pngbin0 -> 647 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.pngbin0 -> 1675 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.pngbin0 -> 1684 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.pngbin0 -> 1179 bytes
-rw-r--r--core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.pngbin0 -> 1183 bytes
-rw-r--r--core/src/main/res/values/arrays.xml12
-rw-r--r--core/src/main/res/values/attrs.xml8
-rw-r--r--core/src/main/res/values/dimens.xml4
-rw-r--r--core/src/main/res/values/strings.xml13
-rw-r--r--core/src/main/res/values/styles.xml25
90 files changed, 1589 insertions, 2687 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 2fe94d576..7025d46ad 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,9 +11,10 @@ repositories {
dependencies {
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:gridlayout-v7:$supportVersion"
- compile "com.android.support:cardview-v7:$supportVersion"
compile "com.android.support:design:$supportVersion"
+ compile "com.android.support:gridlayout-v7:$supportVersion"
+ compile "com.android.support:palette-v7:$supportVersion"
+ compile "com.android.support:percent:$supportVersion"
compile "com.android.support:recyclerview-v7:$supportVersion"
compile "org.apache.commons:commons-lang3:$commonslangVersion"
compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
@@ -37,6 +38,9 @@ dependencies {
transitive = true
}
compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
+ compile("com.githang:viewpagerindicator:2.5@aar") {
+ exclude module: "support-v4"
+ }
compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
index fabc399ba..897098c00 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -3,17 +3,10 @@ package de.test.antennapod.ui;
import android.content.Context;
import android.content.res.Resources;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
-import com.robotium.solo.Condition;
import com.robotium.solo.Solo;
import com.robotium.solo.Timeout;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.R;
diff --git a/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt b/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt
deleted file mode 100644
index 8dada3eda..000000000
--- a/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_APACHE_COMMONS.txt b/app/src/main/assets/LICENSE_APACHE-2.0.txt
index d64569567..d64569567 100644
--- a/app/src/main/assets/LICENSE_APACHE_COMMONS.txt
+++ b/app/src/main/assets/LICENSE_APACHE-2.0.txt
diff --git a/app/src/main/assets/LICENSE_EVENTBUS.txt b/app/src/main/assets/LICENSE_EVENTBUS.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_EVENTBUS.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_FLATTR4J.txt b/app/src/main/assets/LICENSE_FLATTR4J.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_FLATTR4J.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt b/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt
deleted file mode 100644
index 5c304d1a4..000000000
--- a/app/src/main/assets/LICENSE_FLEXIBLE_DIVIDER.txt
+++ /dev/null
@@ -1,201 +0,0 @@
-Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_OKIO.txt b/app/src/main/assets/LICENSE_OKIO.txt
deleted file mode 100644
index d64569567..000000000
--- a/app/src/main/assets/LICENSE_OKIO.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_RX_ANDROID.txt b/app/src/main/assets/LICENSE_RX_ANDROID.txt
deleted file mode 100644
index 4fe2d187f..000000000
--- a/app/src/main/assets/LICENSE_RX_ANDROID.txt
+++ /dev/null
@@ -1,200 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/assets/LICENSE_STACKBLUR.txt b/app/src/main/assets/LICENSE_STACKBLUR.txt
deleted file mode 100644
index b66736ccb..000000000
--- a/app/src/main/assets/LICENSE_STACKBLUR.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache License, Version 2.0
-
-Version 2.0, January 2004
-
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
-
-You must give any other recipients of the Work or Derivative Works a copy of this License; and
-You must cause any modified files to carry prominent notices stating that You changed the files; and
-You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
-If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
-
-You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
-5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work
-To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
-
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 442515010..014c65e11 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,54 +1,43 @@
package de.danoeh.antennapod.activity;
+import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Bundle;
+import android.os.Build;
+import android.support.design.widget.AppBarLayout;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.ListFragment;
+import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.ContextMenu;
-import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.ScaleAnimation;
import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ListView;
-import android.widget.PopupWindow;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import com.bumptech.glide.Glide;
+import com.viewpagerindicator.CirclePageIndicator;
-import org.apache.commons.lang3.ArrayUtils;
+import java.util.List;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.ChapterListAdapter;
+import de.danoeh.antennapod.adapter.ChaptersListAdapter;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.feed.SimpleChapter;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
@@ -57,8 +46,14 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.fragment.AddFeedFragment;
+import de.danoeh.antennapod.fragment.ChaptersFragment;
import de.danoeh.antennapod.fragment.CoverFragment;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
+import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
+import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
+import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
import de.danoeh.antennapod.preferences.PreferenceController;
import rx.Observable;
@@ -69,85 +64,38 @@ import rx.schedulers.Schedulers;
/**
* Activity for playing audio files.
*/
-public class AudioplayerActivity extends MediaplayerActivity implements ItemDescriptionFragment.ItemDescriptionFragmentCallback,
- NavDrawerActivity {
+public class AudioplayerActivity extends MediaplayerActivity implements NavDrawerActivity {
private static final int POS_COVER = 0;
private static final int POS_DESCR = 1;
private static final int POS_CHAPTERS = 2;
private static final int NUM_CONTENT_FRAGMENTS = 3;
- private static final int POS_NONE = -1;
final String TAG = "AudioplayerActivity";
private static final String PREFS = "AudioPlayerActivityPreferences";
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
- private static final String PREF_PLAYABLE_ID = "playableId";
+
+ public static final String[] NAV_DRAWER_TAGS = {
+ QueueFragment.TAG,
+ EpisodesFragment.TAG,
+ DownloadsFragment.TAG,
+ PlaybackHistoryFragment.TAG,
+ AddFeedFragment.TAG
+ };
private DrawerLayout drawerLayout;
private NavListAdapter navAdapter;
private ListView navList;
- private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private View navDrawer;
private ActionBarDrawerToggle drawerToggle;
+ private int mPosition = -1;
- private Fragment[] detachedFragments;
-
- private CoverFragment coverFragment;
- private ItemDescriptionFragment descriptionFragment;
- private ListFragment chapterFragment;
-
- private Fragment currentlyShownFragment;
- private int currentlyShownPosition = -1;
- private int lastShownPosition = POS_NONE;
- /**
- * Used if onResume was called without loadMediaInfo.
- */
- private int savedPosition = -1;
-
- private TextView txtvTitle;
- private Button butPlaybackSpeed;
- private ImageButton butNavChaptersShownotes;
- private ImageButton butShowCover;
+ private Playable media;
+ private ViewPager mPager;
+ private AudioplayerPagerAdapter mPagerAdapter;
private Subscription subscription;
- private PopupWindow popupWindow;
-
- private void resetFragmentView() {
- FragmentTransaction fT = getSupportFragmentManager().beginTransaction();
-
- if (coverFragment != null) {
- Log.d(TAG, "Removing cover fragment");
- fT.remove(coverFragment);
- }
- if (descriptionFragment != null) {
- Log.d(TAG, "Removing description fragment");
- fT.remove(descriptionFragment);
- }
- if (chapterFragment != null) {
- Log.d(TAG, "Removing chapter fragment");
- fT.remove(chapterFragment);
- }
- if (currentlyShownFragment != null) {
- Log.d(TAG, "Removing currently shown fragment");
- fT.remove(currentlyShownFragment);
- }
- for (int i = 0; i < detachedFragments.length; i++) {
- Fragment f = detachedFragments[i];
- if (f != null) {
- Log.d(TAG, "Removing detached fragment");
- fT.remove(f);
- }
- }
- fT.commit();
- currentlyShownFragment = null;
- coverFragment = null;
- descriptionFragment = null;
- chapterFragment = null;
- currentlyShownPosition = -1;
- detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
- }
-
@Override
protected void onStop() {
super.onStop();
@@ -156,6 +104,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
subscription.unsubscribe();
}
EventDistributor.getInstance().unregister(contentUpdate);
+ saveCurrentFragment();
}
@Override
@@ -163,29 +112,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
setTheme(UserPreferences.getNoTitleTheme());
}
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
- }
+ private void saveCurrentFragment() {
+ if(mPager == null) {
+ return;
+ }
- private void savePreferences() {
Log.d(TAG, "Saving preferences");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- if (currentlyShownPosition >= 0 && controller != null
- && controller.getMedia() != null) {
- editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION,
- currentlyShownPosition);
- editor.putString(PREF_PLAYABLE_ID, controller.getMedia()
- .getIdentifier().toString());
- } else {
- editor.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
- editor.putString(PREF_PLAYABLE_ID, "");
- }
- editor.commit();
-
- savedPosition = currentlyShownPosition;
+ prefs.edit()
+ .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, mPager.getCurrentItem())
+ .commit();
}
@Override
@@ -194,53 +130,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
drawerToggle.onConfigurationChanged(newConfig);
}
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- // super.onSaveInstanceState(outState); would cause crash
- Log.d(TAG, "onSaveInstanceState");
- }
-
- @Override
- protected void onPause() {
- savePreferences();
- resetFragmentView();
- super.onPause();
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- restoreFromPreferences();
- }
-
- /**
- * Tries to restore the selected fragment position from the Activity's
- * preferences.
- *
- * @return true if restoreFromPrefernces changed the activity's state
- */
- private boolean restoreFromPreferences() {
+ private void loadLastFragment() {
Log.d(TAG, "Restoring instance state");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- int savedPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION,
- -1);
- String playableId = prefs.getString(PREF_PLAYABLE_ID, "");
-
- if (savedPosition != -1
- && controller != null
- && controller.getMedia() != null
- && controller.getMedia().getIdentifier().toString()
- .equals(playableId)) {
- switchToFragment(savedPosition);
- return true;
- } else if (controller == null || controller.getMedia() == null) {
- Log.d(TAG, "Couldn't restore from preferences: controller or media was null");
- } else {
- Log.d(TAG, "Couldn't restore from preferences: savedPosition was -1 or saved identifier and playable identifier didn't match.\nsavedPosition: "
- + savedPosition + ", id: " + playableId);
-
- }
- return false;
+ int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
+ mPager.setCurrentItem(lastPosition);
}
@Override
@@ -260,10 +154,12 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
true);
startService(launchIntent);
}
- if (savedPosition != -1) {
- switchToFragment(savedPosition);
+ if(mPagerAdapter != null && controller != null && controller.getMedia() != media) {
+ media = controller.getMedia();
+ mPagerAdapter.notifyDataSetChanged();
}
+
EventDistributor.getInstance().register(contentUpdate);
loadData();
}
@@ -292,147 +188,25 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
@Override
protected void clearStatusMsg() {
// TODO Hide progress bar here
-
}
- /**
- * Changes the currently displayed fragment.
- *
- * @param pos Must be POS_COVER, POS_DESCR, or POS_CHAPTERS
- */
- private void switchToFragment(int pos) {
- Log.d(TAG, "Switching contentView to position " + pos);
- if (currentlyShownPosition != pos && controller != null) {
- Playable media = controller.getMedia();
- if (media != null) {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
- if (currentlyShownFragment != null) {
- detachedFragments[currentlyShownPosition] = currentlyShownFragment;
- ft.detach(currentlyShownFragment);
- }
- switch (pos) {
- case POS_COVER:
- if (coverFragment == null) {
- Log.i(TAG, "Using new coverfragment");
- coverFragment = CoverFragment.newInstance(media);
- }
- currentlyShownFragment = coverFragment;
- break;
- case POS_DESCR:
- if (descriptionFragment == null) {
- descriptionFragment = ItemDescriptionFragment
- .newInstance(media, true, true);
- }
- currentlyShownFragment = descriptionFragment;
- break;
- case POS_CHAPTERS:
- if (chapterFragment == null) {
- chapterFragment = new ListFragment() {
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- // add padding
- final ListView lv = getListView();
- lv.setClipToPadding(false);
- final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
- lv.setPadding(0, vertPadding, 0, vertPadding);
- }
- };
- chapterFragment.setListAdapter(new ChapterListAdapter(
- AudioplayerActivity.this, 0, media
- .getChapters(), media, position -> {
- Chapter chapter = (Chapter)
- chapterFragment.getListAdapter().getItem(position);
- controller.seekToChapter(chapter);
- }
- ));
- }
- currentlyShownFragment = chapterFragment;
- break;
- }
- if (currentlyShownFragment != null) {
- lastShownPosition = currentlyShownPosition;
- currentlyShownPosition = pos;
- if (detachedFragments[pos] != null) {
- Log.d(TAG, "Reattaching fragment at position " + pos);
- ft.attach(detachedFragments[pos]);
- } else {
- ft.add(R.id.contentView, currentlyShownFragment);
- }
- ft.disallowAddToBackStack();
- ft.commit();
- updateNavButtonDrawable();
- }
- }
- }
- }
-
- /**
- * Switches to the fragment that was displayed before the current one or the description fragment
- * if no fragment was previously displayed.
- */
- public void switchToLastFragment() {
- if (lastShownPosition != POS_NONE) {
- switchToFragment(lastShownPosition);
- } else {
- switchToFragment(POS_DESCR);
- }
- }
-
- private void updateNavButtonDrawable() {
-
- final int[] buttonTexts = new int[]{R.string.show_shownotes_label,
- R.string.show_chapters_label};
-
- final TypedArray drawables = obtainStyledAttributes(new int[]{
- R.attr.navigation_shownotes, R.attr.navigation_chapters});
- final Playable media = controller.getMedia();
- if (butNavChaptersShownotes != null && butShowCover != null && media != null) {
-
- butNavChaptersShownotes.setTag(R.id.imageloader_key, null);
- setNavButtonVisibility();
- switch (currentlyShownPosition) {
- case POS_COVER:
- butShowCover.setVisibility(View.GONE);
- if (lastShownPosition == POS_CHAPTERS) {
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
- } else {
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
- }
- break;
- case POS_DESCR:
- butShowCover.setVisibility(View.VISIBLE);
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1]));
- break;
- case POS_CHAPTERS:
- butShowCover.setVisibility(View.VISIBLE);
- butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0));
- butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0]));
- break;
- }
- }
- drawables.recycle();
- }
@Override
protected void setupGUI() {
super.setupGUI();
- resetFragmentView();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ findViewById(R.id.shadow).setVisibility(View.GONE);
+ AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBar);
+ float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
+ appBarLayout.setElevation(px);
+ }
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.nav_list);
navDrawer = findViewById(R.id.nav_layout);
- butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
- butNavChaptersShownotes = (ImageButton) findViewById(R.id.butNavChaptersShownotes);
- butShowCover = (ImageButton) findViewById(R.id.butCover);
- txtvTitle = (TextView) findViewById(R.id.txtvTitle);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
drawerToggle.setDrawerIndicatorEnabled(false);
@@ -450,6 +224,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
drawerLayout.closeDrawer(navDrawer);
});
+ navList.setOnItemLongClickListener((parent, view, position, id) -> {
+ if (position < navAdapter.getTags().size()) {
+ showDrawerPreferencesDialog();
+ return true;
+ } else {
+ mPosition = position;
+ return false;
+ }
+ });
registerForContextMenu(navList);
drawerToggle.syncState();
@@ -458,128 +241,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
});
- butNavChaptersShownotes.setOnClickListener(v -> {
- if (currentlyShownPosition == POS_CHAPTERS) {
- switchToFragment(POS_DESCR);
- } else if (currentlyShownPosition == POS_DESCR) {
- switchToFragment(POS_CHAPTERS);
- } else if (currentlyShownPosition == POS_COVER) {
- switchToLastFragment();
- }
- });
-
- butShowCover.setOnClickListener(v -> switchToFragment(POS_COVER));
-
- butPlaybackSpeed.setOnClickListener(v -> {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- String[] availableSpeeds = UserPreferences
- .getPlaybackSpeedArray();
- String currentSpeed = UserPreferences.getPlaybackSpeed();
-
- // Provide initial value in case the speed list has changed
- // out from under us
- // and our current speed isn't in the new list
- String newSpeed;
- if (availableSpeeds.length > 0) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = "1.0";
- }
-
- for (int i = 0; i < availableSpeeds.length; i++) {
- if (availableSpeeds[i].equals(currentSpeed)) {
- if (i == availableSpeeds.length - 1) {
- newSpeed = availableSpeeds[0];
- } else {
- newSpeed = availableSpeeds[i + 1];
- }
- break;
- }
- }
- UserPreferences.setPlaybackSpeed(newSpeed);
- controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
- }
- });
-
- butPlaybackSpeed.setOnLongClickListener(v -> {
-
- String[] availableSpeeds = getResources().getStringArray(R.array.playback_speed_values);
- String currentSpeed = UserPreferences.getPlaybackSpeed();
-
- LayoutInflater inflater = getLayoutInflater();
- View popupView = inflater.inflate(R.layout.choose_speed_dialog, null);
- TextView txtvSelectedSpeed = (TextView) popupView.findViewById(R.id.txtvSelectedSpeed);
- SeekBar sbSelectSpeed = (SeekBar) popupView.findViewById(R.id.sbSelectSpeed);
-
- txtvSelectedSpeed.setText(currentSpeed);
- int progress = ArrayUtils.indexOf(availableSpeeds, currentSpeed);
- int max = Math.max(progress, ArrayUtils.indexOf(availableSpeeds, "2.50"));
- sbSelectSpeed.setMax(max);
- sbSelectSpeed.setProgress(progress);
- sbSelectSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- txtvSelectedSpeed.setText(availableSpeeds[progress]);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- String selectedSpeed = availableSpeeds[sbSelectSpeed.getProgress()];
- UserPreferences.setPlaybackSpeed(selectedSpeed);
- controller.setPlaybackSpeed(Float.parseFloat(selectedSpeed));
- if (popupWindow != null && popupWindow.isShowing()) {
- popupWindow.dismiss();
- }
- ScaleAnimation anim = new ScaleAnimation(1.0f, 1.33f, 1.0f, 1.33f,
- butPlaybackSpeed.getWidth()/2, butPlaybackSpeed.getHeight()/2);
- anim.setDuration(150);
- anim.setRepeatMode(ScaleAnimation.REVERSE);
- anim.setRepeatCount(1);
- anim.setInterpolator(new LinearInterpolator());
- butPlaybackSpeed.startAnimation(anim);
- }
- });
- popupWindow = new PopupWindow(popupView,
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- true);
- popupWindow.setBackgroundDrawable(new BitmapDrawable());
- popupWindow.setOutsideTouchable(true);
- popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
- return true;
- });
- }
-
- private void setNavButtonVisibility() {
- if (butNavChaptersShownotes != null) {
- if (controller != null) {
- Playable media = controller.getMedia();
- if (media != null) {
- if (media.getChapters() != null || currentlyShownPosition == POS_COVER) {
- butNavChaptersShownotes.setVisibility(View.VISIBLE);
- return;
- }
- }
- }
- butNavChaptersShownotes.setVisibility(View.GONE);
- }
-
- }
-
- @Override
- protected void onPlaybackSpeedChange() {
- super.onPlaybackSpeedChange();
- updateButPlaybackSpeed();
- }
-
- private void updateButPlaybackSpeed() {
- if (controller != null && controller.canSetPlaybackSpeed()) {
- butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed());
+ mPager = (ViewPager) findViewById(R.id.pager);
+ if(mPager.getAdapter() == null) {
+ mPagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
+ mPager.setAdapter(mPagerAdapter);
+ CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
+ pageIndicator.setViewPager(mPager);
+ loadLastFragment();
}
+ mPager.onSaveInstanceState();
}
@Override
@@ -593,48 +263,17 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
if (!super.loadMediaInfo()) {
return false;
}
- final Playable media = controller.getMedia();
- if (media == null) {
- return false;
+ if(controller.getMedia() != media) {
+ media = controller.getMedia();
+ mPagerAdapter.notifyDataSetChanged();
}
- txtvTitle.setText(media.getEpisodeTitle());
- getSupportActionBar().setTitle("");
- Glide.with(this)
- .load(media.getImageUri())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .dontAnimate()
- .into(butShowCover);
-
- setNavButtonVisibility();
-
- if (currentlyShownPosition == -1) {
- if (!restoreFromPreferences()) {
- switchToFragment(POS_COVER);
- }
- }
- if (currentlyShownFragment instanceof AudioplayerContentFragment) {
- ((AudioplayerContentFragment) currentlyShownFragment)
- .onDataSetChanged(media);
- }
-
- if (controller == null
- || !controller.canSetPlaybackSpeed()) {
- butPlaybackSpeed.setVisibility(View.GONE);
- } else {
- butPlaybackSpeed.setVisibility(View.VISIBLE);
- }
-
- updateButPlaybackSpeed();
return true;
}
public void notifyMediaPositionChanged() {
- if (chapterFragment != null) {
- ArrayAdapter<SimpleChapter> adapter = (ArrayAdapter<SimpleChapter>) chapterFragment
- .getListAdapter();
+ ListFragment chapterFragment = (ListFragment) mPagerAdapter.getItem(POS_CHAPTERS);
+ ChaptersListAdapter adapter = (ChaptersListAdapter) chapterFragment.getListAdapter();
+ if(adapter != null) {
adapter.notifyDataSetChanged();
}
}
@@ -659,7 +298,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
clearStatusMsg();
}
- @Override
public PlaybackController getPlaybackController() {
return controller;
}
@@ -669,10 +307,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
}
- public interface AudioplayerContentFragment {
- void onDataSetChanged(Playable media);
- }
-
@Override
protected int getContentViewResourceId() {
return R.layout.audioplayer_activity;
@@ -704,24 +338,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
menu.setHeaderTitle(feed.getTitle());
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
-
- // we may need to reference this elsewhere...
- lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
- AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
-
- if(menuInfo == null) {
- menuInfo = lastMenuInfo;
- }
-
- if(menuInfo.targetView.getParent() instanceof ListView == false
- || ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) {
+ final int position = mPosition;
+ mPosition = -1; // reset
+ if(position < 0) {
return false;
}
- int position = menuInfo.position;
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
switch(item.getItemId()) {
case R.id.mark_all_seen_item:
@@ -772,11 +397,43 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
public void onBackPressed() {
if(isDrawerOpen()) {
drawerLayout.closeDrawer(navDrawer);
- } else {
+ } else if (mPager.getCurrentItem() == 0) {
+ // If the user is currently looking at the first step, allow the system to handle the
+ // Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
+ } else {
+ // Otherwise, select the previous step.
+ mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
+ public void showDrawerPreferencesDialog() {
+ final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
+ String[] navLabels = new String[NAV_DRAWER_TAGS.length];
+ final boolean[] checked = new boolean[NAV_DRAWER_TAGS.length];
+ for (int i = 0; i < NAV_DRAWER_TAGS.length; i++) {
+ String tag = NAV_DRAWER_TAGS[i];
+ navLabels[i] = navAdapter.getLabel(tag);
+ if (!hiddenDrawerItems.contains(tag)) {
+ checked[i] = true;
+ }
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.drawer_preferences);
+ builder.setMultiChoiceItems(navLabels, checked, (dialog, which, isChecked) -> {
+ if (isChecked) {
+ hiddenDrawerItems.remove(NAV_DRAWER_TAGS[which]);
+ } else {
+ hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]);
+ }
+ });
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setHiddenDrawerItems(hiddenDrawerItems);
+ });
+ builder.setNegativeButton(R.string.cancel_label, null);
+ builder.create().show();
+ }
private DBReader.NavDrawerData navDrawerData;
@@ -847,4 +504,36 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
};
+ public interface AudioplayerContentFragment {
+ void onDataSetChanged(Playable media);
+ }
+
+ private class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
+
+ public AudioplayerPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Log.d(TAG, "getItem(" + position + ")");
+ switch (position) {
+ case POS_COVER:
+ return CoverFragment.newInstance(media);
+ case POS_DESCR:
+ return ItemDescriptionFragment.newInstance(media, true, true);
+ case POS_CHAPTERS:
+ return ChaptersFragment.newInstance(media, controller);
+ default:
+ return null;
+ }
+ }
+
+
+ @Override
+ public int getCount() {
+ return NUM_CONTENT_FRAGMENTS;
+ }
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index bfbf3d86f..75100e717 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -1,34 +1,44 @@
package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.bumptech.glide.Glide;
+import com.joanzapata.iconify.IconDrawable;
+import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
@@ -36,13 +46,17 @@ import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
/**
* Provides general features which are both needed for playing audio and video
* files.
*/
-public abstract class MediaplayerActivity extends ActionBarActivity
- implements OnSeekBarChangeListener {
+public abstract class MediaplayerActivity extends AppCompatActivity implements OnSeekBarChangeListener {
private static final String TAG = "MediaplayerActivity";
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
@@ -52,12 +66,17 @@ public abstract class MediaplayerActivity extends ActionBarActivity
protected TextView txtvPosition;
protected TextView txtvLength;
protected SeekBar sbPosition;
- protected ImageButton butPlay;
+ protected Button butPlaybackSpeed;
protected ImageButton butRev;
- protected boolean showTimeLeft = false;
protected TextView txtvRev;
+ protected ImageButton butPlay;
protected ImageButton butFF;
protected TextView txtvFF;
+ protected ImageButton butSkip;
+
+ protected boolean showTimeLeft = false;
+
+ private boolean isFavorite = false;
private PlaybackController newPlaybackController() {
return new PlaybackController(this, false) {
@@ -157,7 +176,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
protected void onPlaybackSpeedChange() {
-
+ updateButPlaybackSpeed();
}
protected void onServiceQueried() {
@@ -268,7 +287,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- if(controller == null) {
+ if (controller == null) {
return false;
}
Playable media = controller.getMedia();
@@ -294,19 +313,35 @@ public abstract class MediaplayerActivity extends ActionBarActivity
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
- menu.findItem(R.id.skip_episode_item).setVisible(media != null);
+ menu.findItem(R.id.add_to_favorites_item).setVisible(false);
+ menu.findItem(R.id.remove_from_favorites_item).setVisible(false);
+ if(media != null && media instanceof FeedMedia) {
+ menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
+ menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
+ }
boolean sleepTimerSet = controller.sleepTimerActive();
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
+ if (this instanceof AudioplayerActivity) {
+ int[] attrs = {R.attr.action_bar_icon_color};
+ TypedArray ta = obtainStyledAttributes(UserPreferences.getTheme(), attrs);
+ int textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+ menu.findItem(R.id.audio_controls).setIcon(new IconDrawable(this,
+ FontAwesomeIcons.fa_sliders).color(textColor).actionBarSize());
+ } else {
+ menu.findItem(R.id.audio_controls).setVisible(false);
+ }
+
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if(controller == null) {
+ if (controller == null) {
return false;
}
Playable media = controller.getMedia();
@@ -317,84 +352,217 @@ public abstract class MediaplayerActivity extends ActionBarActivity
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
- } else if (media != null) {
- switch (item.getItemId()) {
- case R.id.disable_sleeptimer_item:
- if (controller.serviceAvailable()) {
-
- MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
- stDialog.title(R.string.sleep_timer_label);
- stDialog.content(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) controller
- .getSleepTimerTimeLeft()));
- stDialog.positiveText(R.string.disable_sleeptimer_label);
- stDialog.negativeText(R.string.cancel_label);
- stDialog.callback(new MaterialDialog.ButtonCallback() {
+ } else {
+ if (media != null) {
+ switch (item.getItemId()) {
+ case R.id.add_to_favorites_item:
+ if(media instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia)media).getItem();
+ if(feedItem != null) {
+ DBWriter.addFavoriteItem(feedItem);
+ isFavorite = true;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.added_to_favorites, Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ break;
+ case R.id.remove_from_favorites_item:
+ if(media instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia)media).getItem();
+ if(feedItem != null) {
+ DBWriter.removeFavoriteItem(feedItem);
+ isFavorite = false;
+ invalidateOptionsMenu();
+ Toast.makeText(this, R.string.removed_from_favorites, Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ break;
+ case R.id.disable_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+
+ MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
+ stDialog.title(R.string.sleep_timer_label);
+ stDialog.content(getString(R.string.time_left_label)
+ + Converter.getDurationStringLong((int) controller
+ .getSleepTimerTimeLeft()));
+ stDialog.positiveText(R.string.disable_sleeptimer_label);
+ stDialog.negativeText(R.string.cancel_label);
+ stDialog.callback(new MaterialDialog.ButtonCallback() {
+ @Override
+ public void onPositive(MaterialDialog dialog) {
+ dialog.dismiss();
+ controller.disableSleepTimer();
+ }
+
+ @Override
+ public void onNegative(MaterialDialog dialog) {
+ dialog.dismiss();
+ }
+ });
+ stDialog.build().show();
+ }
+ break;
+ case R.id.set_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+ SleepTimerDialog td = new SleepTimerDialog(this) {
+ @Override
+ public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
+ controller.setSleepTimer(millis, shakeToReset, vibrate);
+ }
+ };
+ td.createNewDialog().show();
+ }
+ break;
+ case R.id.audio_controls:
+ MaterialDialog dialog = new MaterialDialog.Builder(this)
+ .title(R.string.audio_controls)
+ .customView(R.layout.audio_controls, false)
+ .neutralText(R.string.close_label)
+ .onNeutral((dialog1, which) -> {
+ final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
+ final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
+ UserPreferences.setVolume(left.getProgress(), right.getProgress());
+ })
+ .show();
+ final SeekBar barPlaybackSpeed = (SeekBar) dialog.findViewById(R.id.playback_speed);
+
+ final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
+ butDecSpeed.setOnClickListener(v -> {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
+ });
+ final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
+ butIncSpeed.setOnClickListener(v -> {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
+ });
+ final TextView txtvPlaybackSpeed = (TextView) dialog.findViewById(R.id.txtvPlaybackSpeed);
+ float currentSpeed = 1.0f;
+ try {
+ currentSpeed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch (NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
+ }
+
+ txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
+ barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
- public void onPositive(MaterialDialog dialog) {
- dialog.dismiss();
- controller.disableSleepTimer();
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float playbackSpeed = (progress + 10) / 20.0f;
+ controller.setPlaybackSpeed(playbackSpeed);
+ String speed = String.format("%.2f", playbackSpeed);
+ UserPreferences.setPlaybackSpeed(speed);
+ txtvPlaybackSpeed.setText(speed + "x");
}
@Override
- public void onNegative(MaterialDialog dialog) {
- dialog.dismiss();
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
}
});
- stDialog.build().show();
- }
- break;
- case R.id.set_sleeptimer_item:
- if (controller.serviceAvailable()) {
- SleepTimerDialog td = new SleepTimerDialog(this) {
+ barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
+
+ final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
+ barLeftVolume.setProgress(100);
+ final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
+ barRightVolume.setProgress(100);
+ final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
+ stereoToMono.setChecked(UserPreferences.stereoToMono());
+ if (controller != null && !controller.canDownmix()) {
+ stereoToMono.setEnabled(false);
+ String sonicOnly = getString(R.string.sonic_only);
+ stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
+ }
+
+ barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
- public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
- controller.setSleepTimer(millis, shakeToReset, vibrate);
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float leftVolume = 1.0f, rightVolume = 1.0f;
+ if (progress < 100) {
+ leftVolume = progress / 100.0f;
+ }
+ if (barRightVolume.getProgress() < 100) {
+ rightVolume = barRightVolume.getProgress() / 100.0f;
+ }
+ controller.setVolume(leftVolume, rightVolume);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float leftVolume = 1.0f, rightVolume = 1.0f;
+ if (progress < 100) {
+ rightVolume = progress / 100.0f;
+ }
+ if (barLeftVolume.getProgress() < 100) {
+ leftVolume = barLeftVolume.getProgress() / 100.0f;
+ }
+ controller.setVolume(leftVolume, rightVolume);
}
- };
- td.createNewDialog().show();
- }
- break;
- case R.id.visit_website_item:
- Uri uri = Uri.parse(media.getWebsiteLink());
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
- break;
- case R.id.support_item:
- if (media instanceof FeedMedia) {
- DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_link_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_download_url_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
- }
- break;
- case R.id.share_link_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
- }
- break;
- case R.id.share_download_url_with_position_item:
- if (media instanceof FeedMedia) {
- ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
- }
- break;
- case R.id.skip_episode_item:
- sendBroadcast(new Intent(
- PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
- break;
- default:
- return false;
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ stereoToMono.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ UserPreferences.stereoToMono(isChecked);
+ if (controller != null) {
+ controller.setDownmix(isChecked);
+ }
+ });
+ break;
+ case R.id.visit_website_item:
+ Uri uri = Uri.parse(media.getWebsiteLink());
+ startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ break;
+ case R.id.support_item:
+ if (media instanceof FeedMedia) {
+ DBTasks.flattrItemIfLoggedIn(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_link_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_download_url_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem());
+ }
+ break;
+ case R.id.share_link_with_position_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemLink(this, ((FeedMedia) media).getItem(), true);
+ }
+ break;
+ case R.id.share_download_url_with_position_item:
+ if (media instanceof FeedMedia) {
+ ShareUtils.shareFeedItemDownloadLink(this, ((FeedMedia) media).getItem(), true);
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ } else {
+ return false;
}
- return true;
- } else {
- return false;
}
}
@@ -427,11 +595,10 @@ public abstract class MediaplayerActivity extends ActionBarActivity
&& controller.getMedia() != null) {
txtvPosition.setText(Converter
.getDurationStringLong(currentPosition));
- if(showTimeLeft) {
- txtvLength.setText("-"+Converter
+ if (showTimeLeft) {
+ txtvLength.setText("-" + Converter
.getDurationStringLong(duration - currentPosition));
- }
- else {
+ } else {
txtvLength.setText(Converter
.getDurationStringLong(duration));
}
@@ -443,7 +610,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
private void updateProgressbarPosition(int position, int duration) {
- Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration +")");
+ Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
float progress = ((float) position) / duration;
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
@@ -458,22 +625,31 @@ public abstract class MediaplayerActivity extends ActionBarActivity
Log.d(TAG, "loadMediaInfo()");
Playable media = controller.getMedia();
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT,false);
+ showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
if (media != null) {
- txtvPosition.setText(Converter.getDurationStringLong((media
- .getPosition())));
+ txtvPosition.setText(Converter.getDurationStringLong((media.getPosition())));
if (media.getDuration() != 0) {
- txtvLength.setText(Converter.getDurationStringLong(media
- .getDuration()));
- float progress = ((float) media.getPosition())
- / media.getDuration();
+ txtvLength.setText(Converter.getDurationStringLong(media.getDuration()));
+ float progress = ((float) media.getPosition()) / media.getDuration();
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
- if(showTimeLeft) {
- txtvLength.setText("-"+Converter.getDurationStringLong((media
- .getDuration()-media.getPosition())));
+ if (showTimeLeft) {
+ int timeLeft = media.getDuration() - media.getPosition();
+ txtvLength.setText("-" + Converter.getDurationStringLong(timeLeft));
+ }
+ }
+ checkFavorite();
+ if(controller == null) {
+ butPlaybackSpeed.setVisibility(View.GONE);
+ } else {
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
+ if (controller.canSetPlaybackSpeed()) {
+ ViewCompat.setAlpha(butPlaybackSpeed, 1.0f);
+ } else {
+ ViewCompat.setAlpha(butPlaybackSpeed, 0.5f);
}
}
+ updateButPlaybackSpeed();
return true;
} else {
return false;
@@ -486,43 +662,42 @@ public abstract class MediaplayerActivity extends ActionBarActivity
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
- showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT,false);
- Log.d("timeleft",showTimeLeft? "true":"false");
+ showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
+ Log.d("timeleft", showTimeLeft ? "true" : "false");
txtvLength = (TextView) findViewById(R.id.txtvLength);
- txtvLength.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showTimeLeft = !showTimeLeft;
- Playable media = controller.getMedia();
- if (media == null) {
- return;
- }
-
- if (showTimeLeft) {
- txtvLength.setText("-"+Converter.getDurationStringLong((media
- .getDuration()-media.getPosition())));
- } else {
- txtvLength.setText(Converter.getDurationStringLong((media.getDuration())));
- }
+ txtvLength.setOnClickListener(v -> {
+ showTimeLeft = !showTimeLeft;
+ Playable media = controller.getMedia();
+ if (media == null) {
+ return;
+ }
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(PREF_SHOW_TIME_LEFT,showTimeLeft);
- editor.apply();
- Log.d("timeleft on click",showTimeLeft? "true":"false");
+ if (showTimeLeft) {
+ txtvLength.setText("-" + Converter.getDurationStringLong((media
+ .getDuration() - media.getPosition())));
+ } else {
+ txtvLength.setText(Converter.getDurationStringLong((media.getDuration())));
}
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft);
+ editor.apply();
+ Log.d("timeleft on click", showTimeLeft ? "true" : "false");
});
- butPlay = (ImageButton) findViewById(R.id.butPlay);
+ butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
butRev = (ImageButton) findViewById(R.id.butRev);
txtvRev = (TextView) findViewById(R.id.txtvRev);
- if(txtvRev != null) {
+ if (txtvRev != null) {
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
}
+ butPlay = (ImageButton) findViewById(R.id.butPlay);
butFF = (ImageButton) findViewById(R.id.butFF);
txtvFF = (TextView) findViewById(R.id.txtvFF);
- if(txtvFF != null) {
+ if (txtvFF != null) {
txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs()));
}
+ butSkip = (ImageButton) findViewById(R.id.butSkip);
// SEEKBAR SETUP
@@ -530,27 +705,58 @@ public abstract class MediaplayerActivity extends ActionBarActivity
// BUTTON SETUP
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ if(butPlaybackSpeed != null) {
+ butPlaybackSpeed.setOnClickListener(v -> {
+ if (controller != null && controller.canSetPlaybackSpeed()) {
+ String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ String currentSpeed = UserPreferences.getPlaybackSpeed();
+
+ // Provide initial value in case the speed list has changed
+ // out from under us
+ // and our current speed isn't in the new list
+ String newSpeed;
+ if (availableSpeeds.length > 0) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = "1.00";
+ }
- if (butFF != null) {
- butFF.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int curr = controller.getPosition();
- controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ for (int i = 0; i < availableSpeeds.length; i++) {
+ if (availableSpeeds[i].equals(currentSpeed)) {
+ if (i == availableSpeeds.length - 1) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = availableSpeeds[i + 1];
+ }
+ break;
+ }
+ }
+ UserPreferences.setPlaybackSpeed(newSpeed);
+ controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
}
});
- butFF.setOnLongClickListener(new View.OnLongClickListener() {
+ butPlaybackSpeed.setOnLongClickListener(v -> {
+ VariableSpeedDialog.showDialog(this);
+ return true;
+ });
+ }
+
+ if (butRev != null) {
+ butRev.setOnClickListener(v -> {
+ int curr = controller.getPosition();
+ controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ });
+ butRev.setOnLongClickListener(new View.OnLongClickListener() {
int choice;
@Override
public boolean onLongClick(View v) {
int checked = 0;
- int rewindSecs = UserPreferences.getFastFowardSecs();
+ int rewindSecs = UserPreferences.getRewindSecs();
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
final String[] choices = new String[values.length];
- for(int i=0; i < values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
if (rewindSecs == values[i]) {
checked = i;
}
@@ -559,40 +765,40 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
- builder.setTitle(R.string.pref_fast_forward);
+ builder.setTitle(R.string.pref_rewind);
builder.setSingleChoiceItems(choices, checked,
(dialog, which) -> {
choice = values[which];
});
builder.setNegativeButton(R.string.cancel_label, null);
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
- UserPreferences.setPrefFastForwardSecs(choice);
- txtvFF.setText(String.valueOf(choice));
+ UserPreferences.setPrefRewindSecs(choice);
+ txtvRev.setText(String.valueOf(choice));
});
builder.create().show();
return true;
}
});
}
- if (butRev != null) {
- butRev.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int curr = controller.getPosition();
- controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
- }
+
+ butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+
+ if (butFF != null) {
+ butFF.setOnClickListener(v -> {
+ int curr = controller.getPosition();
+ controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
});
- butRev.setOnLongClickListener(new View.OnLongClickListener() {
+ butFF.setOnLongClickListener(new View.OnLongClickListener() {
int choice;
@Override
public boolean onLongClick(View v) {
int checked = 0;
- int rewindSecs = UserPreferences.getRewindSecs();
+ int rewindSecs = UserPreferences.getFastFowardSecs();
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
final String[] choices = new String[values.length];
- for(int i=0; i < values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
if (rewindSecs == values[i]) {
checked = i;
}
@@ -601,21 +807,15 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
- builder.setTitle(R.string.pref_rewind);
+ builder.setTitle(R.string.pref_fast_forward);
builder.setSingleChoiceItems(choices, checked,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- choice = values[which];
- }
+ (dialog, which) -> {
+ choice = values[which];
});
builder.setNegativeButton(R.string.cancel_label, null);
- builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- UserPreferences.setPrefRewindSecs(choice);
- txtvRev.setText(String.valueOf(choice));
- }
+ builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
+ UserPreferences.setPrefFastForwardSecs(choice);
+ txtvFF.setText(String.valueOf(choice));
});
builder.create().show();
return true;
@@ -623,6 +823,11 @@ public abstract class MediaplayerActivity extends ActionBarActivity
});
}
+ if (butSkip != null) {
+ butSkip.setOnClickListener(v -> {
+ sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
+ });
+ }
}
protected abstract int getContentViewResourceId();
@@ -633,12 +838,9 @@ public abstract class MediaplayerActivity extends ActionBarActivity
errorDialog
.setMessage(MediaPlayerError.getErrorString(this, errorCode));
errorDialog.setNeutralButton("OK",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- finish();
- }
+ (dialog, which) -> {
+ dialog.dismiss();
+ finish();
}
);
errorDialog.create().show();
@@ -652,14 +854,20 @@ public abstract class MediaplayerActivity extends ActionBarActivity
if (controller != null) {
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser,
txtvPosition);
- if(showTimeLeft && prog!=0) {
+ if (showTimeLeft && prog != 0) {
int duration = controller.getDuration();
- txtvLength.setText("-"+Converter
+ txtvLength.setText("-" + Converter
.getDurationStringLong(duration - (int) (prog * duration)));
}
}
}
+ private void updateButPlaybackSpeed() {
+ if (controller != null) {
+ butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed() + "x");
+ }
+ }
+
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (controller != null) {
@@ -674,4 +882,23 @@ public abstract class MediaplayerActivity extends ActionBarActivity
}
}
+ private void checkFavorite() {
+ Playable playable = controller.getMedia();
+ if (playable != null && playable instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia) playable).getItem();
+ if (feedItem != null) {
+ Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(item -> {
+ boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
+ if(isFavorite != isFav) {
+ isFavorite = isFav;
+ invalidateOptionsMenu();
+ }
+ });
+ }
+ }
+ }
+
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
deleted file mode 100644
index cf0532cf1..000000000
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.text.Layout;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.Spanned;
-import android.text.style.ClickableSpan;
-import android.text.util.Linkify;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.Chapter;
-import de.danoeh.antennapod.core.util.ChapterUtils;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.playback.Playable;
-
-import java.util.List;
-
-public class ChapterListAdapter extends ArrayAdapter<Chapter> {
-
- private static final String TAG = "ChapterListAdapter";
-
- private List<Chapter> chapters;
- private Playable media;
-
- private int defaultTextColor;
- private final Callback callback;
-
- public ChapterListAdapter(Context context, int textViewResourceId,
- List<Chapter> objects, Playable media, Callback callback) {
- super(context, textViewResourceId, objects);
- this.chapters = objects;
- this.media = media;
- this.callback = callback;
- }
-
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- Holder holder;
-
- Chapter sc = getItem(position);
-
- // Inflate Layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- defaultTextColor = holder.title.getTextColors().getDefaultColor();
- holder.start = (TextView) convertView.findViewById(R.id.txtvStart);
- holder.link = (TextView) convertView.findViewById(R.id.txtvLink);
- holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
-
- }
-
- holder.title.setText(sc.getTitle());
- holder.start.setText(Converter.getDurationStringLong((int) sc
- .getStart()));
- if (sc.getLink() != null) {
- holder.link.setVisibility(View.VISIBLE);
- holder.link.setText(sc.getLink());
- Linkify.addLinks(holder.link, Linkify.WEB_URLS);
- } else {
- holder.link.setVisibility(View.GONE);
- }
- holder.link.setMovementMethod(null);
- holder.link.setOnTouchListener(new OnTouchListener() {
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // from
- // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures
- TextView widget = (TextView) v;
- Object text = widget.getText();
- if (text instanceof Spanned) {
- Spannable buffer = (Spannable) text;
-
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_UP
- || action == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
-
- x -= widget.getTotalPaddingLeft();
- y -= widget.getTotalPaddingTop();
-
- x += widget.getScrollX();
- y += widget.getScrollY();
-
- Layout layout = widget.getLayout();
- int line = layout.getLineForVertical(y);
- int off = layout.getOffsetForHorizontal(line, x);
-
- ClickableSpan[] link = buffer.getSpans(off, off,
- ClickableSpan.class);
-
- if (link.length != 0) {
- if (action == MotionEvent.ACTION_UP) {
- link[0].onClick(widget);
- } else if (action == MotionEvent.ACTION_DOWN) {
- Selection.setSelection(buffer,
- buffer.getSpanStart(link[0]),
- buffer.getSpanEnd(link[0]));
- }
- return true;
- }
- }
-
- }
-
- return false;
-
- }
- });
- holder.butPlayChapter.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (callback != null) {
- callback.onPlayChapterButtonClicked(position);
- }
- }
- });
- Chapter current = ChapterUtils.getCurrentChapter(media);
- if (current != null) {
- if (current == sc) {
- holder.title.setTextColor(convertView.getResources().getColor(
- R.color.holo_blue_light));
- holder.start.setTextColor(convertView.getResources().getColor(
- R.color.holo_blue_light));
- } else {
- holder.title.setTextColor(defaultTextColor);
- holder.start.setTextColor(defaultTextColor);
- }
- } else {
- Log.w(TAG, "Could not find out what the current chapter is.");
- }
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView start;
- TextView link;
- ImageButton butPlayChapter;
- }
-
- @Override
- public int getCount() {
- // ignore invalid chapters
- int counter = 0;
- if (chapters != null) {
- for (Chapter chapter : chapters) {
- if (!ignoreChapter(chapter)) {
- counter++;
- }
- }
- }
- return counter;
- }
-
- private boolean ignoreChapter(Chapter c) {
- return media.getDuration() > 0 && media.getDuration() < c.getStart();
- }
-
- @Override
- public Chapter getItem(int position) {
- int i = 0;
- for (Chapter chapter : chapters) {
- if (!ignoreChapter(chapter)) {
- if (i == position) {
- return chapter;
- } else {
- i++;
- }
- }
- }
- return super.getItem(position);
- }
-
- public static interface Callback {
- public void onPlayChapterButtonClicked(int position);
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
new file mode 100644
index 000000000..1c9439ee6
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java
@@ -0,0 +1,198 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.ClickableSpan;
+import android.text.util.Linkify;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.Chapter;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.ChapterUtils;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+
+public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
+
+ private static final String TAG = "ChapterListAdapter";
+
+ private Playable media;
+
+ private int defaultTextColor;
+ private final Callback callback;
+
+ public ChaptersListAdapter(Context context, int textViewResourceId, Callback callback) {
+ super(context, textViewResourceId);
+ this.callback = callback;
+ }
+
+ public void setMedia(Playable media) {
+ this.media = media;
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ Holder holder;
+
+ Chapter sc = getItem(position);
+
+ // Inflate Layout
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
+ holder.view = convertView;
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ defaultTextColor = holder.title.getTextColors().getDefaultColor();
+ holder.start = (TextView) convertView.findViewById(R.id.txtvStart);
+ holder.link = (TextView) convertView.findViewById(R.id.txtvLink);
+ holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+
+ }
+
+ holder.title.setText(sc.getTitle());
+ holder.start.setText(Converter.getDurationStringLong((int) sc
+ .getStart()));
+ if (sc.getLink() != null) {
+ holder.link.setVisibility(View.VISIBLE);
+ holder.link.setText(sc.getLink());
+ Linkify.addLinks(holder.link, Linkify.WEB_URLS);
+ } else {
+ holder.link.setVisibility(View.GONE);
+ }
+ holder.link.setMovementMethod(null);
+ holder.link.setOnTouchListener((v, event) -> {
+ // from
+ // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures
+ TextView widget = (TextView) v;
+ Object text = widget.getText();
+ if (text instanceof Spanned) {
+ Spannable buffer = (Spannable) text;
+
+ int action = event.getAction();
+
+ if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_DOWN) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+
+ x -= widget.getTotalPaddingLeft();
+ y -= widget.getTotalPaddingTop();
+
+ x += widget.getScrollX();
+ y += widget.getScrollY();
+
+ Layout layout = widget.getLayout();
+ int line = layout.getLineForVertical(y);
+ int off = layout.getOffsetForHorizontal(line, x);
+
+ ClickableSpan[] link = buffer.getSpans(off, off,
+ ClickableSpan.class);
+
+ if (link.length != 0) {
+ if (action == MotionEvent.ACTION_UP) {
+ link[0].onClick(widget);
+ } else if (action == MotionEvent.ACTION_DOWN) {
+ Selection.setSelection(buffer,
+ buffer.getSpanStart(link[0]),
+ buffer.getSpanEnd(link[0]));
+ }
+ return true;
+ }
+ }
+
+ }
+
+ return false;
+
+ });
+ holder.butPlayChapter.setOnClickListener(v -> {
+ if (callback != null) {
+ callback.onPlayChapterButtonClicked(position);
+ }
+ });
+ Chapter current = ChapterUtils.getCurrentChapter(media);
+ if (current != null) {
+ if (current == sc) {
+ int playingBackGroundColor;
+ if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
+ playingBackGroundColor = getContext().getResources().getColor(R.color.highlight_dark);
+ } else {
+ playingBackGroundColor = getContext().getResources().getColor(R.color.highlight_light);
+ }
+ holder.view.setBackgroundColor(playingBackGroundColor);
+ } else {
+ holder.view.setBackgroundColor(getContext().getResources().getColor(android.R.color.transparent));
+ holder.title.setTextColor(defaultTextColor);
+ holder.start.setTextColor(defaultTextColor);
+ }
+ } else {
+ Log.w(TAG, "Could not find out what the current chapter is.");
+ }
+
+ return convertView;
+ }
+
+ static class Holder {
+ View view;
+ TextView title;
+ TextView start;
+ TextView link;
+ ImageButton butPlayChapter;
+ }
+
+ @Override
+ public int getCount() {
+ if(media == null || media.getChapters() == null) {
+ return 0;
+ }
+ // ignore invalid chapters
+ int counter = 0;
+ for (Chapter chapter : media.getChapters()) {
+ if (!ignoreChapter(chapter)) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ private boolean ignoreChapter(Chapter c) {
+ return media.getDuration() > 0 && media.getDuration() < c.getStart();
+ }
+
+ @Override
+ public Chapter getItem(int position) {
+ int i = 0;
+ for (Chapter chapter : media.getChapters()) {
+ if (!ignoreChapter(chapter)) {
+ if (i == position) {
+ return chapter;
+ } else {
+ i++;
+ }
+ }
+ }
+ return super.getItem(position);
+ }
+
+ public interface Callback {
+ void onPlayChapterButtonClicked(int position);
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
index 4b512a48d..f2e8b6f7a 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java
@@ -21,107 +21,96 @@ import de.danoeh.antennapod.core.util.IntentUtils;
public class VariableSpeedDialog {
- private static final String TAG = VariableSpeedDialog.class.getSimpleName();
-
- private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
- Uri.parse("market://details?id=com.falconware.prestissimo"));
-
- private VariableSpeedDialog() {
- }
-
- public static void showDialog(final Context context) {
- if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
- || UserPreferences.useSonic()) {
- showSpeedSelectorDialog(context);
- } else {
- showGetPluginDialog(context);
- }
- }
-
- private static void showGetPluginDialog(final Context context) {
- MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
- builder.title(R.string.no_playback_plugin_title);
- builder.content(R.string.no_playback_plugin_or_sonic_msg);
- builder.positiveText(R.string.download_plugin_label);
- builder.negativeText(R.string.enable_sonic);
- builder.neutralText(R.string.close_label);
- builder.callback(new MaterialDialog.ButtonCallback() {
- @Override
- public void onPositive(MaterialDialog dialog) {
- try {
- context.startActivity(playStoreIntent);
- } catch (ActivityNotFoundException e) {
- // this is usually thrown on an emulator if the Android market is not installed
- Log.e(TAG, Log.getStackTraceString(e));
- }
- }
-
- @Override
- public void onNegative(MaterialDialog dialog) {
- if (Build.VERSION.SDK_INT >= 16) { // just to be safe
- UserPreferences.enableSonic(true);
- showSpeedSelectorDialog(context);
- }
- }
-
- @Override
- public void onNeutral(MaterialDialog dialog) {
- super.onNeutral(dialog);
- }
- });
- builder.forceStacking(true);
- MaterialDialog dialog = builder.show();
- if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) {
- View pos = dialog.getActionButton(DialogAction.POSITIVE);
- pos.setEnabled(false);
- }
- if (Build.VERSION.SDK_INT < 16) {
- View pos = dialog.getActionButton(DialogAction.NEGATIVE);
- pos.setEnabled(false);
- }
- }
-
- private static void showSpeedSelectorDialog(final Context context) {
- final String[] speedValues = context.getResources().getStringArray(
- R.array.playback_speed_values);
- // According to Java spec these get initialized to false on creation
- final boolean[] speedChecked = new boolean[speedValues.length];
-
- // Build the "isChecked" array so that multiChoice dialog is
- // populated correctly
- List<String> selectedSpeedList = Arrays.asList(UserPreferences
- .getPlaybackSpeedArray());
- for (int i = 0; i < speedValues.length; i++) {
- speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.set_playback_speed_label);
- builder.setMultiChoiceItems(R.array.playback_speed_values,
- speedChecked, (dialog, which, isChecked) -> {
- speedChecked[which] = isChecked;
- });
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.setPositiveButton(android.R.string.ok,
- (dialog, which) -> {
- int choiceCount = 0;
- for (int i = 0; i < speedChecked.length; i++) {
- if (speedChecked[i]) {
- choiceCount++;
- }
- }
- String[] newSpeedValues = new String[choiceCount];
- int newSpeedIndex = 0;
- for (int i = 0; i < speedChecked.length; i++) {
- if (speedChecked[i]) {
- newSpeedValues[newSpeedIndex++] = speedValues[i];
- }
- }
-
- UserPreferences.setPlaybackSpeedArray(newSpeedValues);
-
- });
- builder.create().show();
- }
+ private static final String TAG = VariableSpeedDialog.class.getSimpleName();
+
+ private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
+ Uri.parse("market://details?id=com.falconware.prestissimo"));
+
+ private VariableSpeedDialog() {
+ }
+
+ public static void showDialog(final Context context) {
+ if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
+ || UserPreferences.useSonic()) {
+ showSpeedSelectorDialog(context);
+ } else {
+ showGetPluginDialog(context);
+ }
+ }
+
+ private static void showGetPluginDialog(final Context context) {
+ MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
+ builder.title(R.string.no_playback_plugin_title);
+ builder.content(R.string.no_playback_plugin_or_sonic_msg);
+ builder.positiveText(R.string.download_plugin_label);
+ builder.negativeText(R.string.enable_sonic);
+ builder.neutralText(R.string.close_label);
+ builder.onPositive((dialog, which) -> {
+ try {
+ context.startActivity(playStoreIntent);
+ } catch (ActivityNotFoundException e) {
+ // this is usually thrown on an emulator if the Android market is not installed
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ });
+ builder.onNegative((dialog, which) -> {
+ if (Build.VERSION.SDK_INT >= 16) { // just to be safe
+ UserPreferences.enableSonic(true);
+ showSpeedSelectorDialog(context);
+ }
+ });
+ MaterialDialog dialog = builder.show();
+ if(!IntentUtils.isCallable(context.getApplicationContext(), playStoreIntent)) {
+ View pos = dialog.getActionButton(DialogAction.POSITIVE);
+ pos.setEnabled(false);
+ }
+ if (Build.VERSION.SDK_INT < 16) {
+ View pos = dialog.getActionButton(DialogAction.NEGATIVE);
+ pos.setEnabled(false);
+ }
+ }
+
+ private static void showSpeedSelectorDialog(final Context context) {
+ final String[] speedValues = context.getResources().getStringArray(
+ R.array.playback_speed_values);
+ // According to Java spec these get initialized to false on creation
+ final boolean[] speedChecked = new boolean[speedValues.length];
+
+ // Build the "isChecked" array so that multiChoice dialog is
+ // populated correctly
+ List<String> selectedSpeedList = Arrays.asList(UserPreferences
+ .getPlaybackSpeedArray());
+ for (int i = 0; i < speedValues.length; i++) {
+ speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.set_playback_speed_label);
+ builder.setMultiChoiceItems(R.array.playback_speed_values,
+ speedChecked, (dialog, which, isChecked) -> {
+ speedChecked[which] = isChecked;
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setPositiveButton(android.R.string.ok,
+ (dialog, which) -> {
+ int choiceCount = 0;
+ for (int i = 0; i < speedChecked.length; i++) {
+ if (speedChecked[i]) {
+ choiceCount++;
+ }
+ }
+ String[] newSpeedValues = new String[choiceCount];
+ int newSpeedIndex = 0;
+ for (int i = 0; i < speedChecked.length; i++) {
+ if (speedChecked[i]) {
+ newSpeedValues[newSpeedIndex++] = speedValues[i];
+ }
+ }
+
+ UserPreferences.setPlaybackSpeedArray(newSpeedValues);
+
+ });
+ builder.create().show();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
new file mode 100644
index 000000000..abc9f3d22
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java
@@ -0,0 +1,68 @@
+package de.danoeh.antennapod.fragment;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import android.widget.ListView;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.adapter.ChaptersListAdapter;
+import de.danoeh.antennapod.core.feed.Chapter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+
+
+public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
+
+ private Playable media;
+ private PlaybackController controller;
+
+ private ChaptersListAdapter adapter;
+
+ public static ChaptersFragment newInstance(Playable media, PlaybackController controller) {
+ ChaptersFragment f = new ChaptersFragment();
+ f.media = media;
+ f.controller = controller;
+ return f;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ // add padding
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
+
+ adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
+ Chapter chapter = (Chapter) getListAdapter().getItem(pos);
+ controller.seekToChapter(chapter);
+ });
+ setListAdapter(adapter);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ adapter.setMedia(media);
+ adapter.notifyDataSetChanged();
+ if(media == null || media.getChapters() == null) {
+ setEmptyText(getString(R.string.no_chapters_label));
+ } else {
+ setEmptyText(null);
+ }
+ }
+
+ @Override
+ public void onDataSetChanged(Playable media) {
+ adapter.setMedia(media);
+ adapter.notifyDataSetChanged();
+ if(media.getChapters() == null) {
+ setEmptyText(getString(R.string.no_items_label));
+ } else {
+ setEmptyText(null);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index a1667cce0..60a607179 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -1,21 +1,21 @@
package de.danoeh.antennapod.fragment;
-import android.app.Activity;
-import android.content.Context;
+import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v7.graphics.Palette;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.request.animation.GlideAnimation;
+import com.bumptech.glide.request.target.BitmapImageViewTarget;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -30,10 +30,11 @@ public class CoverFragment extends Fragment implements
private Playable media;
+ private View root;
+ private TextView txtvPodcastTitle;
+ private TextView txtvEpisodeTitle;
private ImageView imgvCover;
- private boolean viewCreated = false;
-
public static CoverFragment newInstance(Playable item) {
CoverFragment f = new CoverFragment();
if (item != null) {
@@ -59,38 +60,45 @@ public class CoverFragment extends Fragment implements
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- View root = inflater.inflate(R.layout.cover_fragment, container, false);
+ root = inflater.inflate(R.layout.cover_fragment, container, false);
+ txtvPodcastTitle = (TextView) root.findViewById(R.id.txtvPodcastTitle);
+ txtvEpisodeTitle = (TextView) root.findViewById(R.id.txtvEpisodeTitle);
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
- imgvCover.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Activity activity = getActivity();
- if (activity != null && activity instanceof AudioplayerActivity) {
- ((AudioplayerActivity)activity).switchToLastFragment();
- }
- }
- });
- viewCreated = true;
return root;
}
private void loadMediaInfo() {
+ if(imgvCover == null) {
+ return;
+ }
if (media != null) {
- imgvCover.post(new Runnable() {
-
- @Override
- public void run() {
- Context c = getActivity();
- if (c != null) {
- Glide.with(c)
- .load(media.getImageUri())
- .placeholder(R.color.light_gray)
- .error(R.color.light_gray)
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .dontAnimate()
- .into(imgvCover);
- }
- }
+ Log.d(TAG, "feed title: " + media.getFeedTitle());
+ Log.d(TAG, "episode title: " + media.getEpisodeTitle());
+ txtvPodcastTitle.setText(media.getFeedTitle());
+ txtvEpisodeTitle.setText(media.getEpisodeTitle());
+ imgvCover.post(() -> {
+ Glide.with(this)
+ .load(media.getImageUri())
+ .asBitmap()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .dontAnimate()
+ .into(new BitmapImageViewTarget(imgvCover) {
+ @Override
+ public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
+ super.onResourceReady(bitmap, anim);
+ Palette.Builder builder = new Palette.Builder(bitmap);
+ builder.generate(palette -> {
+ Palette.Swatch swatch = palette.getMutedSwatch();
+ if(swatch != null) {
+ root.setBackgroundColor(swatch.getRgb());
+ txtvPodcastTitle.setTextColor(swatch.getTitleTextColor());
+ txtvEpisodeTitle.setTextColor(swatch.getBodyTextColor());
+ }
+ });
+ }
+ });
});
} else {
Log.w(TAG, "loadMediaInfo was called while media was null");
@@ -99,12 +107,10 @@ public class CoverFragment extends Fragment implements
@Override
public void onStart() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "On Start");
+ Log.d(TAG, "On Start");
super.onStart();
if (media != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading media info");
+ Log.d(TAG, "Loading media info");
loadMediaInfo();
} else {
Log.w(TAG, "Unable to load media info: media was null");
@@ -114,10 +120,7 @@ public class CoverFragment extends Fragment implements
@Override
public void onDataSetChanged(Playable media) {
this.media = media;
- if (viewCreated) {
- loadMediaInfo();
- }
-
+ loadMediaInfo();
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index 888684313..80a9bf0b3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -13,7 +13,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
@@ -80,50 +79,15 @@ public class ExternalPlayerFragment extends Fragment {
return new PlaybackController(getActivity(), true) {
@Override
- public void setupGUI() {
- }
-
- @Override
public void onPositionObserverUpdate() {
ExternalPlayerFragment.this.onPositionObserverUpdate();
}
@Override
- public void onReloadNotification(int code) {
- }
-
- @Override
- public void onBufferStart() {
- }
-
- @Override
- public void onBufferEnd() {
- }
-
- @Override
- public void onBufferUpdate(float progress) {
- }
-
- @Override
- public void onSleepTimerUpdate() {
- }
-
- @Override
- public void handleError(int code) {
- }
-
- @Override
public ImageButton getPlayButton() {
return butPlay;
}
- @Override
- public void postStatusMsg(int msg) {
- }
-
- @Override
- public void clearStatusMsg() {
- }
@Override
public boolean loadMediaInfo() {
@@ -136,14 +100,6 @@ public class ExternalPlayerFragment extends Fragment {
}
@Override
- public void onAwaitingVideoSurface() {
- }
-
- @Override
- public void onServiceQueried() {
- }
-
- @Override
public void onShutdownNotification() {
playbackDone();
}
@@ -152,10 +108,6 @@ public class ExternalPlayerFragment extends Fragment {
public void onPlaybackEnd() {
playbackDone();
}
-
- @Override
- public void onPlaybackSpeedChange() {
- }
};
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index faa4413bb..6c9473176 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -8,7 +8,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -26,6 +25,8 @@ import android.webkit.WebViewClient;
import android.widget.Toast;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity;
+import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -36,11 +37,15 @@ import de.danoeh.antennapod.core.util.ShownotesProvider;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.Timeline;
+import rx.Observable;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
/**
* Displays the description of a Playable object in a Webview.
*/
-public class ItemDescriptionFragment extends Fragment {
+public class ItemDescriptionFragment extends Fragment implements AudioplayerContentFragment {
private static final String TAG = "ItemDescriptionFragment";
@@ -55,12 +60,13 @@ public class ItemDescriptionFragment extends Fragment {
private static final String ARG_HIGHLIGHT_TIMECODES = "arg.highlightTimecodes";
private WebView webvDescription;
+ private String webvData;
private ShownotesProvider shownotesProvider;
private Playable media;
- private AsyncTask<Void, Void, Void> webViewLoader;
+ private Subscription webViewLoader;
/**
* URL that was selected via long-press.
@@ -111,12 +117,10 @@ public class ItemDescriptionFragment extends Fragment {
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
- webvDescription.setBackgroundColor(getResources().getColor(
- R.color.black));
+ webvDescription.setBackgroundColor(getResources().getColor(R.color.black));
}
webvDescription.getSettings().setUseWideViewPort(false);
- webvDescription.getSettings().setLayoutAlgorithm(
- LayoutAlgorithm.NARROW_COLUMNS);
+ webvDescription.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
webvDescription.getSettings().setLoadWithOverviewMode(true);
webvDescription.setOnLongClickListener(webViewLongClickListener);
webvDescription.setWebViewClient(new WebViewClient() {
@@ -142,14 +146,7 @@ public class ItemDescriptionFragment extends Fragment {
super.onPageFinished(view, url);
Log.d(TAG, "Page finished");
// Restoring the scroll position might not always work
- view.postDelayed(new Runnable() {
-
- @Override
- public void run() {
- restoreFromPreference();
- }
-
- }, 50);
+ view.postDelayed(() -> restoreFromPreference(), 50);
}
});
@@ -159,26 +156,11 @@ public class ItemDescriptionFragment extends Fragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- Log.d(TAG, "Fragment attached");
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- Log.d(TAG, "Fragment detached");
- if (webViewLoader != null) {
- webViewLoader.cancel(true);
- }
- }
-
- @Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Fragment destroyed");
if (webViewLoader != null) {
- webViewLoader.cancel(true);
+ webViewLoader.unsubscribe();
}
if (webvDescription != null) {
webvDescription.removeAllViews();
@@ -194,7 +176,6 @@ public class ItemDescriptionFragment extends Fragment {
Bundle args = getArguments();
saveState = args.getBoolean(ARG_SAVE_STATE, false);
highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
-
}
@Override
@@ -204,46 +185,21 @@ public class ItemDescriptionFragment extends Fragment {
if (args.containsKey(ARG_PLAYABLE)) {
media = args.getParcelable(ARG_PLAYABLE);
shownotesProvider = media;
- startLoader();
+ load();
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
- AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() {
-
- @Override
- protected FeedItem doInBackground(Void... voids) {
- return DBReader.getFeedItem(getArguments().getLong(ARG_FEEDITEM_ID));
- }
-
- @Override
- protected void onPostExecute(FeedItem feedItem) {
- super.onPostExecute(feedItem);
- shownotesProvider = feedItem;
- startLoader();
- }
- };
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- itemLoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- itemLoadTask.execute();
- }
+ long id = getArguments().getLong(ARG_FEEDITEM_ID);
+ Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(feedItem -> {
+ shownotesProvider = feedItem;
+ load();
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ });
}
-
-
}
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @SuppressLint("NewApi")
- private void startLoader() {
- webViewLoader = createLoader();
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- webViewLoader.execute();
- }
- }
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@@ -338,49 +294,31 @@ public class ItemDescriptionFragment extends Fragment {
}
}
- private AsyncTask<Void, Void, Void> createLoader() {
- return new AsyncTask<Void, Void, Void>() {
- @Override
- protected void onCancelled() {
- super.onCancelled();
- webViewLoader = null;
- }
-
- String data;
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- // /webvDescription.loadData(url, "text/html", "utf-8");
- webvDescription.loadDataWithBaseURL(null, data, "text/html",
- "utf-8", "about:blank");
- Log.d(TAG, "Webview loaded");
- webViewLoader = null;
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- Log.d(TAG, "Loading Webview");
- try {
- Activity activity = getActivity();
- if (activity != null) {
- Timeline timeline = new Timeline(activity, shownotesProvider);
- data = timeline.processShownotes(highlightTimecodes);
- } else {
- cancel(true);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
+ private void load() {
+ Log.d(TAG, "load()");
+ if(webViewLoader != null) {
+ webViewLoader.unsubscribe();
+ }
+ if(shownotesProvider == null) {
+ return;
+ }
+ webViewLoader = Observable.defer(() -> Observable.just(loadData()))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(data -> {
+ webvData = data;
+ webvDescription.loadDataWithBaseURL(null, data, "text/html",
+ "utf-8", "about:blank");
+ Log.d(TAG, "Webview loaded");
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ });
+ }
- };
+ private String loadData() {
+ Timeline timeline = new Timeline(getActivity(), shownotesProvider);
+ String data = timeline.processShownotes(highlightTimecodes);
+ return data;
}
@Override
@@ -410,7 +348,7 @@ public class ItemDescriptionFragment extends Fragment {
}
private boolean restoreFromPreference() {
- if (saveState) {
+ if (!saveState) {
Log.d(TAG, "Restoring from preferences");
Activity activity = getActivity();
if (activity != null) {
@@ -433,15 +371,19 @@ public class ItemDescriptionFragment extends Fragment {
private void onTimecodeLinkSelected(String link) {
int time = Timeline.getTimecodeLinkTime(link);
- if (getActivity() != null && getActivity() instanceof ItemDescriptionFragmentCallback) {
- PlaybackController pc = ((ItemDescriptionFragmentCallback) getActivity()).getPlaybackController();
+ if (getActivity() != null && getActivity() instanceof AudioplayerActivity) {
+ PlaybackController pc = ((AudioplayerActivity) getActivity()).getPlaybackController();
if (pc != null) {
pc.seekTo(time);
}
}
}
- public interface ItemDescriptionFragmentCallback {
- public PlaybackController getPlaybackController();
+ @Override
+ public void onDataSetChanged(Playable media) {
+ this.media = media;
+ this.shownotesProvider = media;
+ load();
}
+
}
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
new file mode 100644
index 000000000..7532722dd
--- /dev/null
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginLeft="24dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/playback_speed"
+ android:textStyle="bold"/>
+
+ <TextView
+ android:id="@+id/txtvPlaybackSpeed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dp"
+ android:text="1.00x"/>
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp">
+
+ <Button
+ android:id="@+id/butDecSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_alignParentLeft="true"
+ android:gravity="center"
+ android:text="-"
+ android:textStyle="bold"
+ android:textColor="@color/status_progress"
+ android:textSize="24sp"
+ android:background="@drawable/borderless_button_dark"/>
+
+ <Button
+ android:id="@+id/butIncSpeed"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:minWidth="0dp"
+ android:layout_alignParentRight="true"
+ android:gravity="center"
+ android:text="+"
+ android:textStyle="bold"
+ android:textColor="@color/status_progress"
+ android:textSize="24sp"
+ android:background="@drawable/borderless_button_dark"/>
+
+ <SeekBar
+ android:id="@+id/playback_speed"
+ android:layout_width="match_parent"
+ android:layout_height="32dp"
+ android:layout_toRightOf="@id/butDecSpeed"
+ android:layout_toLeftOf="@id/butIncSpeed"
+ android:layout_centerVertical="true"
+ android:max="40"/>
+
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:layout_marginLeft="24dp"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/volume"
+ android:textStyle="bold"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/txtvLeft"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/left_short" />
+
+ <SeekBar
+ android:id="@+id/volume_left"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="100" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/txtvRight"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/right_short" />
+
+ <SeekBar
+ android:id="@+id/volume_right"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="100"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginLeft="24dp"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:text="@string/audio_effects"
+ android:textStyle="bold"/>
+
+ <CheckBox
+ android:id="@+id/stereo_to_mono"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:text="@string/stereo_to_mono" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/audioplayer_activity.xml b/app/src/main/res/layout/audioplayer_activity.xml
index 379028c8e..fb4f995a2 100644
--- a/app/src/main/res/layout/audioplayer_activity.xml
+++ b/app/src/main/res/layout/audioplayer_activity.xml
@@ -1,219 +1,219 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@android:color/holo_red_dark">
- <LinearLayout
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
+
+ <android.support.design.widget.AppBarLayout
+ android:id="@+id/appBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
- tools:background="@android:color/darker_gray">
+ tools:background="@android:color/darker_gray"/>
- <LinearLayout
+ <com.viewpagerindicator.CirclePageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:paddingLeft="8dp"
- android:paddingRight="8dp">
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:ellipsize="end"
- android:gravity="left"
- android:maxLines="2"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- tools:text="Audio title"
- tools:background="@android:color/holo_green_dark" />
-
- <ImageButton
- android:id="@+id/butCover"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="8dp"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/show_cover_label"
- android:gravity="right"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
-
-
- </LinearLayout>
- </android.support.v7.widget.Toolbar>
-
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content"
+ android:layout_marginTop="-12dp"
+ android:layout_marginBottom="4dp"
+ android:background="@android:color/transparent"
+ app:fillColor="?android:attr/textColorSecondary"
+ app:strokeColor="?android:attr/textColorSecondary"
+ app:radius="4dp" />
+
+ </android.support.design.widget.AppBarLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/playtime_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/non_transparent_background"
- android:foreground="?android:windowContentOverlay"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:layout_alignParentBottom="true"
+ android:background="?attr/overlay_drawable"
android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/txtvPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvLength"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"
+ tools:background="@android:color/holo_green_dark" />
+
+ <SeekBar
+ android:id="@+id/sbPosition"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toRightOf="@id/txtvPosition"
+ android:max="500"
+ tools:background="@android:color/holo_green_dark" />
+
+ </RelativeLayout>
+
<RelativeLayout
android:id="@+id/player_control"
android:layout_width="match_parent"
- android:layout_height="@dimen/audioplayer_playercontrols_length"
- android:layout_alignParentBottom="true"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="8dp"
android:background="?attr/overlay_background"
tools:background="@android:color/holo_purple">
<ImageButton
android:id="@+id/butPlay"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
android:layout_centerHorizontal="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/pause_label"
android:src="?attr/av_pause"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_pause_white_36dp"
tools:background="@android:color/holo_green_dark" />
<ImageButton
android:id="@+id/butRev"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toLeftOf="@id/butPlay"
+ android:layout_marginLeft="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/rewind_label"
android:src="?attr/av_rew_big"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_fast_rewind_white_36dp"
tools:background="@android:color/holo_blue_dark" />
<TextView
android:id="@+id/txtvRev"
android:layout_width="wrap_content"
- android:layout_height="32dp"
- android:layout_alignTop="@id/butRev"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butRev"
android:layout_alignLeft="@id/butRev"
android:layout_alignRight="@id/butRev"
+ android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="8dp"
+ android:textSize="10sp"
+ android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
+ <Button
+ android:id="@+id/butPlaybackSpeed"
+ android:layout_width="@dimen/audioplayer_playercontrols_length"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_toLeftOf="@id/butRev"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/set_playback_speed_label"
+ android:src="?attr/av_fast_forward"
+ android:textSize="@dimen/text_size_medium"
+ android:textAllCaps="false"
+ tools:background="@android:color/holo_green_dark" />
+
<ImageButton
android:id="@+id/butFF"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
android:layout_toRightOf="@id/butPlay"
+ android:layout_marginRight="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/fast_forward_label"
android:src="?attr/av_ff_big"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_fast_forward_white_36dp"
tools:background="@android:color/holo_blue_dark" />
<TextView
android:id="@+id/txtvFF"
android:layout_width="wrap_content"
- android:layout_height="32dp"
- android:layout_alignTop="@id/butFF"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/butFF"
android:layout_alignLeft="@id/butFF"
android:layout_alignRight="@id/butFF"
+ android:layout_marginTop="-8dp"
android:gravity="center"
android:text="30"
- android:textSize="8dp"
+ android:textSize="10sp"
+ android:textColor="?android:attr/textColorSecondary"
android:clickable="false"/>
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/set_playback_speed_label"
- android:src="?attr/av_fast_forward"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone"
- tools:background="@android:color/holo_green_dark" />
-
<ImageButton
- android:id="@+id/butNavChaptersShownotes"
+ android:id="@+id/butSkip"
android:layout_width="@dimen/audioplayer_playercontrols_length"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butRev"
+ android:layout_height="@dimen/audioplayer_playercontrols_length"
+ android:layout_toRightOf="@id/butFF"
android:background="?attr/selectableItemBackground"
- android:scaleType="centerInside"
- android:src="@drawable/ic_toc_white_36dp"
- tools:background="@android:color/holo_green_dark" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable">
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark" />
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500"
+ android:scaleType="fitCenter"
+ android:src="?attr/av_skip_big"
+ android:contentDescription="@string/skip_episode_label"
+ tools:src="@drawable/ic_skip_white_36dp"
tools:background="@android:color/holo_green_dark" />
</RelativeLayout>
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_above="@id/playtime_layout"
- android:layout_alignParentTop="true"
- android:foreground="?android:windowContentOverlay"
- tools:background="@android:color/holo_orange_light" />
+ </LinearLayout>
- </RelativeLayout>
+ <android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_above="@id/playtime_layout"
+ android:layout_below="@id/appBar"
+ android:foreground="?android:windowContentOverlay"
+ tools:background="@android:color/holo_orange_light" />
+ <View
+ android:id="@+id/shadow"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:layout_below="@id/appBar"
+ android:background="@drawable/shadow" />
- </LinearLayout>
+ </RelativeLayout>
<include layout="@layout/nav_list" />
diff --git a/app/src/main/res/layout/choose_speed_dialog.xml b/app/src/main/res/layout/choose_speed_dialog.xml
deleted file mode 100644
index 1b461c77e..000000000
--- a/app/src/main/res/layout/choose_speed_dialog.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.v7.widget.CardView
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- android:id="@+id/card_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_margin="16dp"
- card_view:cardElevation="12dp"
- card_view:cardCornerRadius="4dp"
- card_view:cardUseCompatPadding="true"
- card_view:cardBackgroundColor="?attr/overlay_background">
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="center">
-
- <TextView
- android:id="@+id/txtvSelectedSpeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:textSize="22sp"
- android:textStyle="bold"/>
-
- <SeekBar
- android:id="@+id/sbSelectSpeed"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"/>
-
- </LinearLayout>
-
- </android.support.v7.widget.CardView>
-
-</LinearLayout>
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 4bbdeae06..13cfb0add 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -1,19 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<android.support.percent.PercentRelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/cover_fragment_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:background="@color/actionbar_gray">
<ImageView
android:id="@+id/imgvCover"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_centerInParent="true"
android:contentDescription="@string/cover_label"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:adjustViewBounds="true"
android:scaleType="fitCenter"
+ app:layout_aspectRatio="100%"
+ app:layout_widthPercent="82%"
tools:src="@android:drawable/sym_def_app_icon" />
-</RelativeLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_above="@id/imgvCover">
+
+ <TextView
+ android:id="@+id/txtvPodcastTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:text="Podcast" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_below="@id/imgvCover">
+
+ <TextView
+ android:id="@+id/txtvEpisodeTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:text="Episode" />
+
+ </LinearLayout>
+
+</android.support.percent.PercentRelativeLayout>
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 053e68552..c4086bf5e 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -3,22 +3,35 @@
xmlns:custom="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/add_to_favorites_item"
+ android:icon="?attr/ic_fav"
+ android:title="@string/add_to_favorite_label"
+ custom:showAsAction="always">
+ </item>
+ <item
+ android:id="@+id/remove_from_favorites_item"
+ android:icon="?attr/ic_unfav"
+ android:title="@string/remove_from_favorite_label"
+ custom:showAsAction="always">
+ </item>
+
+ <item
android:id="@+id/disable_sleeptimer_item"
- android:icon="?attr/device_access_time"
+ android:icon="?attr/ic_sleep_off"
custom:showAsAction="always"
android:title="@string/sleep_timer_label">
</item>
<item
android:id="@+id/set_sleeptimer_item"
- custom:showAsAction="collapseActionView"
+ android:icon="?attr/ic_sleep"
+ custom:showAsAction="always"
android:title="@string/set_sleeptimer_label">
</item>
<item
- android:id="@+id/skip_episode_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/skip_episode_label"
- android:visible="true">
+ android:id="@+id/audio_controls"
+ android:title="@string/audio_controls"
+ custom:showAsAction="always">
</item>
<item
@@ -30,7 +43,9 @@
</item>
<item
android:id="@+id/share_item"
+ android:icon="?attr/social_share"
android:menuCategory="container"
+ custom:showAsAction="ifRoom"
android:title="@string/share_label">
<menu>
<item
diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html
index 21599bdb8..222429b17 100644
--- a/app/src/main/templates/about.html
+++ b/app/src/main/templates/about.html
@@ -59,13 +59,13 @@
<h1>Used libraries</h1>
<h2>Apache Commons <a href="http://commons.apache.org/">(Link)</a></h2>
-by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE_COMMONS.txt">(View)</a>
+by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>EventBus <a href="https://github.com/greenrobot/EventBus">(Link)</a></h2>
-by greenrobot, licensed under the Apache 2.0 license <a href="LICENSE_EVENTBUS.txt">(View)</a>
+by greenrobot, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>flattr4j <a href="http://www.shredzone.org/projects/flattr4j/wiki">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_FLATTR4J.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>Glide <a href="https://github.com/bumptech/glide/">(Link)</a></h2>
licensed under the Simplified BSD license <a href="LICENSE_GLIDE.txt">(View)</a>
@@ -86,22 +86,22 @@ by Aidan Michael Follestad, licensed under the MIT License <a href="LICENSE_MATE
by Square, licensed under the Apache 2.0 license <a href="LICENSE_OKHTTP.txt">(View)</a>
<h2>Okio <a href="https://github.com/square/okio">(Link)</a></h2>
-by Square, licensed under the Apache 2.0 license <a href="LICENSE_OKIO.txt">(View)</a>
+by Square, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>Presto Client <a href="http://www.aocate.com/presto/">(Link)</a></h2>
licensed under the Apache 2.0 license <a href="LICENSE_PRESTO.txt">(View)</a>
<h2>RecyclerView-FlexibleDivider <a href="https://github.com/yqritc/RecyclerView-FlexibleDivider">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_FLEXIBLE_DIVIDER.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>RxAndroid <a href="https://github.com/ReactiveX/RxAndroid">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_RX_ANDROID.txt">(View)</a>
+licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>StackBlur <a href="https://github.com/kikoso/android-stackblur">(Link)</a></h2>
-by Enrique L&oacute;pez Ma&ntilde;as, licensed under the Apache 2.0 license <a href="LICENSE_STACKBLUR.txt">(View)</a>
+by Enrique L&oacute;pez Ma&ntilde;as, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
<h2>AntennaPod-AudioPlayer <a href="https://github.com/AntennaPod/AntennaPod-AudioPlayer/">(Link)</a></h2>
-by the AntennaPod team, licensed under the Apache 2.0 license <a href="LICENSE_ANTENNAPOD_AUDIOPLAYER.txt">(View)</a>
+by the AntennaPod team, licensed under the Apache 2.0 license <a href="LICENSE_APACHE-2.0.txt">(View)</a>
</body>
</html>
diff --git a/build.gradle b/build.gradle
index 79cf2e3c5..0d2cf9dfb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -50,14 +50,14 @@ project.ext {
jsoupVersion = "1.7.3"
iconifyFontawesomeVersion = "2.1.1"
materialDialogsVersion = "0.8.5.3@aar"
+ okhttpVersion = "2.7.2"
+ okioVersion = "1.6.0"
recyclerviewFlexibledividerVersion = "1.2.6"
rxAndroidVersion = "1.1.0"
rxJavaVersion = "1.1.0"
rxJavaRulesVersion = "1.1.0.0"
- okhttpVersion = "2.7.2"
- okioVersion = "1.6.0"
- audioPlayerVersion = "v1.0.8"
+ audioPlayerVersion = "v1.0.9"
}
task wrapper(type: Wrapper) {
diff --git a/core/build.gradle b/core/build.gradle
index d8e6b6287..09d13a476 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -40,7 +40,6 @@ repositories {
dependencies {
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:design:$supportVersion"
compile "org.apache.commons:commons-lang3:$commonslangVersion"
compile ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
exclude group: "org.json", module: "json"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index d6ac8496b..6c0aff15e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -95,9 +94,12 @@ public class UserPreferences {
public static final String PREF_QUEUE_LOCKED = "prefQueueLocked";
public static final String IMAGE_CACHE_DEFAULT_VALUE = "100";
public static final int IMAGE_CACHE_SIZE_MINIMUM = 20;
+ public static final String PREF_LEFT_VOLUME = "prefLeftVolume";
+ public static final String PREF_RIGHT_VOLUME = "prefRightVolume";
// Experimental
public static final String PREF_SONIC = "prefSonic";
+ public static final String PREF_STEREO_TO_MONO = "PrefStereoToMono";
public static final String PREF_NORMALIZER = "prefNormalizer";
public static final int EPISODE_CLEANUP_QUEUE = -1;
public static final int EPISODE_CLEANUP_NULL = -2;
@@ -249,17 +251,37 @@ public class UserPreferences {
}
public static String getPlaybackSpeed() {
- return prefs.getString(PREF_PLAYBACK_SPEED, "1.0");
+ return prefs.getString(PREF_PLAYBACK_SPEED, "1.00");
}
public static String[] getPlaybackSpeedArray() {
return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null));
}
+ public static float getLeftVolume() {
+ int volume = prefs.getInt(PREF_LEFT_VOLUME, 100);
+ if(volume == 100) {
+ return 1.0f;
+ } else {
+ return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
+ }
+ }
+
+ public static float getRightVolume() {
+ int volume = prefs.getInt(PREF_RIGHT_VOLUME, 100);
+ if(volume == 100) {
+ return 1.0f;
+ } else {
+ return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
+ }
+ }
+
public static boolean shouldPauseForFocusLoss() {
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
}
+
+
public static long getUpdateInterval() {
String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0");
if(false == updateInterval.contains(":")) {
@@ -385,6 +407,15 @@ public class UserPreferences {
.apply();
}
+ public static void setVolume(int leftVolume, int rightVolume) {
+ assert(0 <= leftVolume && leftVolume <= 100);
+ assert(0 <= rightVolume && rightVolume <= 100);
+ prefs.edit()
+ .putInt(PREF_LEFT_VOLUME, leftVolume)
+ .putInt(PREF_RIGHT_VOLUME, rightVolume)
+ .apply();
+ }
+
public static void setAutodownloadSelectedNetworks(String[] value) {
prefs.edit()
.putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
@@ -472,7 +503,7 @@ public class UserPreferences {
// If this preference hasn't been set yet, return the default options
if (valueFromPrefs == null) {
String[] allSpeeds = context.getResources().getStringArray(R.array.playback_speed_values);
- List<String> speedList = new LinkedList<String>();
+ List<String> speedList = new ArrayList<>();
for (String speedStr : allSpeeds) {
float speed = Float.parseFloat(speedStr);
if (speed < 2.0001 && speed * 10 % 1 == 0) {
@@ -505,6 +536,16 @@ public class UserPreferences {
.apply();
}
+ public static boolean stereoToMono() {
+ return prefs.getBoolean(PREF_STEREO_TO_MONO, false);
+ }
+
+ public static void stereoToMono(boolean enable) {
+ prefs.edit()
+ .putBoolean(PREF_STEREO_TO_MONO, enable)
+ .apply();
+ }
+
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
int cleanupValue = Integer.valueOf(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 129055f92..2be075a92 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -398,19 +398,25 @@ public class PlaybackService extends Service {
@Override
public void onSleepTimerAlmostExpired() {
- mediaPlayer.setVolume(0.1f);
+ float leftVolume = 0.1f * UserPreferences.getLeftVolume();
+ float rightVolume = 0.1f * UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
@Override
public void onSleepTimerExpired() {
mediaPlayer.pause(true, true);
- mediaPlayer.setVolume(1.0f);
+ float leftVolume = UserPreferences.getLeftVolume();
+ float rightVolume = UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
}
@Override
public void onSleepTimerReset() {
- mediaPlayer.setVolume(1.0f);
+ float leftVolume = UserPreferences.getLeftVolume();
+ float rightVolume = UserPreferences.getRightVolume();
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
@Override
@@ -1165,18 +1171,30 @@ public class PlaybackService extends Service {
public Playable getPlayable() { return mediaPlayer.getPlayable(); }
+ public boolean canSetSpeed() {
+ return mediaPlayer.canSetSpeed();
+ }
+
public void setSpeed(float speed) {
mediaPlayer.setSpeed(speed);
}
- public boolean canSetSpeed() {
- return mediaPlayer.canSetSpeed();
+ public void setVolume(float leftVolume, float rightVolume) {
+ mediaPlayer.setVolume(leftVolume, rightVolume);
}
public float getCurrentPlaybackSpeed() {
return mediaPlayer.getPlaybackSpeed();
}
+ public boolean canDownmix() {
+ return mediaPlayer.canDownmix();
+ }
+
+ public void setDownmix(boolean enable) {
+ mediaPlayer.setDownmix(enable);
+ }
+
public boolean isStartWhenPrepared() {
return mediaPlayer.isStartWhenPrepared();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index e26ee32cb..aa73b17a7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -24,6 +24,7 @@ import android.view.SurfaceHolder;
import android.view.WindowManager;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.Target;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
@@ -293,6 +294,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
+
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
try {
@@ -322,13 +324,10 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* This method is executed on an internal executor service.
*/
public void resume() {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- playerLock.lock();
- resumeSync();
- playerLock.unlock();
- }
+ executor.submit(() -> {
+ playerLock.lock();
+ resumeSync();
+ playerLock.unlock();
});
}
@@ -339,7 +338,15 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
AudioManager.AUDIOFOCUS_GAIN);
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
acquireWifiLockIfNecessary();
- setSpeed(Float.parseFloat(UserPreferences.getPlaybackSpeed()));
+ float speed = 1.0f;
+ try {
+ speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch(NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(speed));
+ }
+ setSpeed(speed);
+ setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume());
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
@@ -690,24 +697,39 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* Sets the playback speed.
* This method is executed on an internal executor service.
*/
- public void setVolume(final float volume) {
- executor.submit(new Runnable() {
- @Override
- public void run() {
- setVolumeSync(volume);
- }
- });
+ public void setVolume(final float volumeLeft, float volumeRight) {
+ executor.submit(() -> setVolumeSync(volumeLeft, volumeRight));
}
/**
* Sets the playback speed.
* This method is executed on the caller's thread.
*/
- private void setVolumeSync(float volume) {
+ private void setVolumeSync(float volumeLeft, float volumeRight) {
+ playerLock.lock();
+ if (media != null && media.getMediaType() == MediaType.AUDIO) {
+ mediaPlayer.setVolume(volumeLeft, volumeRight);
+ Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight);
+ }
+ playerLock.unlock();
+ }
+
+ /**
+ * Returns true if the mediaplayer can mix stereo down to mono
+ */
+ public boolean canDownmix() {
+ boolean retVal = false;
+ if (mediaPlayer != null && media != null && media.getMediaType() == MediaType.AUDIO) {
+ retVal = mediaPlayer.canDownmix();
+ }
+ return retVal;
+ }
+
+ public void setDownmix(boolean enable) {
playerLock.lock();
if (media != null && media.getMediaType() == MediaType.AUDIO) {
- mediaPlayer.setVolume(volume, volume);
- Log.d(TAG, "Media player volume was set to " + volume);
+ mediaPlayer.setDownmix(enable);
+ Log.d(TAG, "Media player downmix was set to " + enable);
}
playerLock.unlock();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
index b6beb5bf1..f0850e6df 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
@@ -37,4 +37,9 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
protected boolean useSonic() {
return UserPreferences.useSonic();
}
+
+ @Override
+ protected boolean downmix() {
+ return UserPreferences.stereoToMono();
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
index 147c7848d..d67153a4e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/IPlayer.java
@@ -10,6 +10,8 @@ public interface IPlayer {
boolean canSetSpeed();
+ boolean canDownmix();
+
float getCurrentPitchStepsAdjustment();
int getCurrentPosition();
@@ -57,6 +59,8 @@ public interface IPlayer {
void setPlaybackSpeed(float f);
+ void setDownmix(boolean enable);
+
void setVolume(float left, float right);
void start();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index a519fb555..1952c068f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -27,7 +27,6 @@ import android.widget.TextView;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -48,6 +47,7 @@ import de.danoeh.antennapod.core.util.playback.Playable.PlayableUtils;
* control playback instead of communicating with the PlaybackService directly.
*/
public abstract class PlaybackController {
+
private static final String TAG = "PlaybackController";
public static final int INVALID_TIME = -1;
@@ -78,23 +78,18 @@ public abstract class PlaybackController {
this.activity = activity;
this.reinitOnPause = reinitOnPause;
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE,
- new ThreadFactory() {
-
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- }, new RejectedExecutionHandler() {
-
- @Override
- public void rejectedExecution(Runnable r,
- ThreadPoolExecutor executor) {
- Log.w(TAG,
+ r -> {
+ Thread t = new Thread(r);
+ t.setPriority(Thread.MIN_PRIORITY);
+ return t;
+ }, new RejectedExecutionHandler() {
+ @Override
+ public void rejectedExecution(Runnable r,
+ ThreadPoolExecutor executor) {
+ Log.w(TAG,
"Rejected execution of runnable in schedExecutor");
+ }
}
- }
);
}
@@ -104,10 +99,10 @@ public abstract class PlaybackController {
*/
public void init() {
activity.registerReceiver(statusUpdate, new IntentFilter(
- PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
+ PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
activity.registerReceiver(notificationReceiver, new IntentFilter(
- PlaybackService.ACTION_PLAYER_NOTIFICATION));
+ PlaybackService.ACTION_PLAYER_NOTIFICATION));
activity.registerReceiver(shutdownReceiver, new IntentFilter(
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
@@ -239,7 +234,7 @@ public abstract class PlaybackController {
return null;
}
- public abstract void setupGUI();
+
private void setupPositionObserver() {
if ((positionObserverFuture != null && positionObserverFuture
@@ -263,8 +258,6 @@ public abstract class PlaybackController {
}
}
- public abstract void onPositionObserverUpdate();
-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
playbackService = ((PlaybackService.LocalBinder) service)
@@ -367,26 +360,31 @@ public abstract class PlaybackController {
}
};
- public abstract void onPlaybackSpeedChange();
+ public void setupGUI() {};
+
+ public void onPositionObserverUpdate() {};
+
- public abstract void onShutdownNotification();
+ public void onPlaybackSpeedChange() {};
+
+ public void onShutdownNotification() {};
/**
* Called when the currently displayed information should be refreshed.
*/
- public abstract void onReloadNotification(int code);
+ public void onReloadNotification(int code) {};
- public abstract void onBufferStart();
+ public void onBufferStart() {};
- public abstract void onBufferEnd();
+ public void onBufferEnd() {};
- public abstract void onBufferUpdate(float progress);
+ public void onBufferUpdate(float progress) {};
- public abstract void onSleepTimerUpdate();
+ public void onSleepTimerUpdate() {};
- public abstract void handleError(int code);
+ public void handleError(int code) {};
- public abstract void onPlaybackEnd();
+ public void onPlaybackEnd() {};
public void repeatHandleStatus() {
if (status != null && playbackService != null) {
@@ -484,15 +482,19 @@ public abstract class PlaybackController {
}
}
- public abstract ImageButton getPlayButton();
+ public ImageButton getPlayButton() {
+ return null;
+ };
- public abstract void postStatusMsg(int msg);
+ public void postStatusMsg(int msg) {};
- public abstract void clearStatusMsg();
+ public void clearStatusMsg() {};
- public abstract boolean loadMediaInfo();
+ public boolean loadMediaInfo() {
+ return false;
+ };
- public abstract void onAwaitingVideoSurface();
+ public void onAwaitingVideoSurface() {};
/**
* Called when connection to playback service has been established or
@@ -526,7 +528,7 @@ public abstract class PlaybackController {
}
}
- public abstract void onServiceQueried();
+ public void onServiceQueried() {};
/**
* Should be used by classes which implement the OnSeekBarChanged interface.
@@ -691,6 +693,12 @@ public abstract class PlaybackController {
}
}
+ public void setVolume(float leftVolume, float rightVolume) {
+ if (playbackService != null) {
+ playbackService.setVolume(leftVolume, rightVolume);
+ }
+ }
+
public float getCurrentPlaybackSpeedMultiplier() {
if (canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
@@ -699,6 +707,16 @@ public abstract class PlaybackController {
}
}
+ public boolean canDownmix() {
+ return playbackService != null && playbackService.canDownmix();
+ }
+
+ public void setDownmix(boolean enable) {
+ if(playbackService != null) {
+ playbackService.setDownmix(enable);
+ }
+ }
+
public boolean isPlayingVideo() {
if (playbackService != null) {
return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 00f2e6f57..2eee1ac87 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -88,7 +88,7 @@ public class Timeline {
}
// replace ASCII line breaks with HTML ones if shownotes don't contain HTML line breaks already
- if(!LINE_BREAK_REGEX.matcher(shownotes).find()) {
+ if(!LINE_BREAK_REGEX.matcher(shownotes).find() && !shownotes.contains("<p>")) {
shownotes = shownotes.replace("\n", "<br />");
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
index dc5270d8f..368379509 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/VideoPlayer.java
@@ -17,6 +17,11 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
}
@Override
+ public boolean canDownmix() {
+ return false;
+ }
+
+ @Override
public float getCurrentPitchStepsAdjustment() {
return 1;
}
@@ -60,6 +65,12 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
throw new UnsupportedOperationException("Setting playback speed unsupported in video player");
}
+ @Override
+ public void setDownmix(boolean b) {
+ Log.e(TAG, "Setting downmix unsupported in video player");
+ throw new UnsupportedOperationException("Setting downmix unsupported in video player");
+ }
+
@Override
public void setVideoScalingMode(int mode) {
super.setVideoScalingMode(mode);
diff --git a/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..edbc95b05
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..cbfb262d8
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..809066499
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..4496a320d
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..79684ab65
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..f0df6032c
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..006410bc3
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..27831192f
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..93f70a024
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..e8619b780
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..be0fcc765
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..893cf2c64
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..ea511bf2a
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..7f631ad86
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..795e318e3
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..4304a6bca
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..dd9d11ba0
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..104fb3c9d
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..af84b71f2
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..0ccebc7c8
--- /dev/null
+++ b/core/src/main/res/drawable-mdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..2e291dd19
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..fa85f1899
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..ae0787a26
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..026224c5e
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..ef39d7279
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..07e156172
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..5160319b5
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..33f9727d3
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..7a09ebc33
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..288799f93
--- /dev/null
+++ b/core/src/main/res/drawable-xhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..00a55a0f8
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..ac38e6d42
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..f4bd9e94d
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..6c42d6051
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..b8e06f9b3
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..e2249c357
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..6348e1997
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..aab4831ff
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..ef0294931
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..de4b7b29d
--- /dev/null
+++ b/core/src/main/res/drawable-xxhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png
new file mode 100644
index 000000000..94836e0c8
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png
new file mode 100644
index 000000000..a84f34228
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png
new file mode 100644
index 000000000..9c0116c60
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png
new file mode 100644
index 000000000..e8141d0df
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png
new file mode 100644
index 000000000..ca41ad5e6
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_off_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png
new file mode 100644
index 000000000..29782e155
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_sleep_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png
new file mode 100644
index 000000000..1109e95c8
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_border_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png
new file mode 100644
index 000000000..086cb677c
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_border_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png
new file mode 100644
index 000000000..dda3262ed
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_grey600_24dp.png
Binary files differ
diff --git a/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png b/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png
new file mode 100644
index 000000000..ba29292b0
--- /dev/null
+++ b/core/src/main/res/drawable-xxxhdpi/ic_star_white_24dp.png
Binary files differ
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 341a7e520..80e3d57f5 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -75,15 +75,15 @@
</string-array>
<string-array name="playback_speed_values">
- <item>0.5</item>
- <item>0.6</item>
- <item>0.7</item>
+ <item>0.50</item>
+ <item>0.60</item>
+ <item>0.70</item>
<item>0.75</item>
- <item>0.8</item>
+ <item>0.80</item>
<item>0.85</item>
- <item>0.9</item>
+ <item>0.90</item>
<item>0.95</item>
- <item>1.0</item>
+ <item>1.00</item>
<item>1.05</item>
<item>1.10</item>
<item>1.15</item>
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index 4e444c990..7adf8295b 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -13,7 +13,6 @@
<attr name="content_discard" format="reference"/>
<attr name="content_new" format="reference"/>
<attr name="feed" format="reference"/>
- <attr name="device_access_time" format="reference"/>
<attr name="location_web_site" format="reference"/>
<attr name="navigation_accept" format="reference"/>
<attr name="navigation_cancel" format="reference"/>
@@ -37,15 +36,20 @@
<attr name="av_pause_big" format="reference"/>
<attr name="av_ff_big" format="reference"/>
<attr name="av_rew_big" format="reference"/>
+ <attr name="av_skip_big" format="reference"/>
<attr name="ic_settings" format="reference"/>
<attr name="ic_lock_open" format="reference"/>
<attr name="ic_lock_closed" format="reference"/>
<attr name="ic_filter" format="reference"/>
<attr name="progressBarTheme" format="reference"/>
+ <attr name="ic_fav" format="reference"/>
+ <attr name="ic_unfav" format="reference"/>
+ <attr name="ic_sleep" format="reference"/>
+ <attr name="ic_sleep_off" format="reference"/>
<!-- Used in itemdescription -->
<attr name="non_transparent_background" format="reference"/>
<attr name="overlay_background" format="color"/>
<attr name="nav_drawer_background" format="color"/>
-</resources> \ No newline at end of file
+</resources>
diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml
index aa57e3051..9aafd14e3 100644
--- a/core/src/main/res/values/dimens.xml
+++ b/core/src/main/res/values/dimens.xml
@@ -33,6 +33,6 @@
<dimen name="listitem_icon_leftpadding">16dp</dimen>
<dimen name="listitem_icon_rightpadding">16dp</dimen>
- <dimen name="audioplayer_playercontrols_length">64dp</dimen>
+ <dimen name="audioplayer_playercontrols_length">48dp</dimen>
-</resources> \ No newline at end of file
+</resources>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 443a1a8a8..fa54ad22e 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -148,7 +148,9 @@
<string name="added_to_queue_label">Added to Queue</string>
<string name="remove_from_queue_label">Remove from Queue</string>
<string name="add_to_favorite_label">Add to Favorites</string>
+ <string name="added_to_favorites">Added to Favorites</string>
<string name="remove_from_favorite_label">Remove from Favorites</string>
+ <string name="removed_from_favorites">Removed from Favorites</string>
<string name="visit_website_label">Visit Website</string>
<string name="support_label">Flattr this</string>
<string name="enqueue_all_new">Enqueue all</string>
@@ -268,6 +270,7 @@
<!-- Empty list labels -->
<string name="no_items_label">There are no items in this list.</string>
<string name="no_feeds_label">You haven\'t subscribed to any feeds yet.</string>
+ <string name="no_chapters_label">This episode has no chapters.</string>
<!-- Preferences -->
<string name="other_pref">Other</string>
@@ -555,4 +558,14 @@
<string name="rating_later_label">Remind me later</string>
<string name="rating_now_label">Sure, let\'s do this!</string>
+ <!-- Audio controls -->
+ <string name="audio_controls">Audio controls</string>
+ <string name="playback_speed">Playback Speed</string>
+ <string name="volume">Volume</string>
+ <string name="left_short">L</string>
+ <string name="right_short">R</string>
+ <string name="audio_effects">Audio Effects</string>
+ <string name="stereo_to_mono">Downmix: Stereo to mono</string>
+ <string name="sonic_only">Sonic only</string>
+
</resources>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index 1f73fbba2..45e1206b7 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -18,7 +18,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_grey600_24dp</item>
<item name="attr/content_new">@drawable/ic_add_grey600_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_grey600_24dp</item>
<item name="attr/feed">@drawable/ic_feed_grey600_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_grey600_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_grey600_24dp</item>
@@ -45,10 +44,16 @@
<item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_grey600_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_grey600_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_grey600_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_grey600_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_grey600_24dp</item>
+
</style>
<style name="Theme.AntennaPod.Dark" parent="Theme.AppCompat">
@@ -67,7 +72,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_white_24dp</item>
<item name="attr/content_new">@drawable/ic_add_white_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_white_24dp</item>
<item name="attr/feed">@drawable/ic_feed_white_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_white_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_white_24dp</item>
@@ -94,10 +98,15 @@
<item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_white_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_white_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_white_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_white_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_white_24dp</item>
</style>
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.AppCompat.Light.NoActionBar">
@@ -118,7 +127,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_grey600_24dp</item>
<item name="attr/content_new">@drawable/ic_add_grey600_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_grey600_24dp</item>
<item name="attr/feed">@drawable/ic_feed_grey600_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_grey600_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_grey600_24dp</item>
@@ -145,10 +153,15 @@
<item name="attr/av_pause_big">@drawable/ic_pause_grey600_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_grey600_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_grey600_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_grey600_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_grey600_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_grey600_24dp</item>
</style>
<style name="Theme.AntennaPod.Dark.NoTitle" parent="Theme.AppCompat.NoActionBar">
@@ -168,7 +181,6 @@
<item name="attr/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
<item name="attr/content_discard">@drawable/ic_delete_white_24dp</item>
<item name="attr/content_new">@drawable/ic_add_white_24dp</item>
- <item name="attr/device_access_time">@drawable/ic_timer_white_24dp</item>
<item name="attr/feed">@drawable/ic_feed_white_24dp</item>
<item name="attr/location_web_site">@drawable/ic_web_white_24dp</item>
<item name="attr/navigation_accept">@drawable/ic_done_white_24dp</item>
@@ -195,10 +207,15 @@
<item name="attr/av_pause_big">@drawable/ic_pause_white_36dp</item>
<item name="attr/av_ff_big">@drawable/ic_fast_forward_white_36dp</item>
<item name="attr/av_rew_big">@drawable/ic_fast_rewind_white_36dp</item>
+ <item name="attr/av_skip_big">@drawable/ic_skip_white_36dp</item>
+ <item name="attr/ic_fav">@drawable/ic_star_border_white_24dp</item>
+ <item name="attr/ic_unfav">@drawable/ic_star_white_24dp</item>
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
+ <item name="attr/ic_sleep">@drawable/ic_sleep_white_24dp</item>
+ <item name="attr/ic_sleep_off">@drawable/ic_sleep_off_white_24dp</item>
</style>
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">