Audio player redesign
Sleep timer and audio effects (e.g. balance) accessible from actionbar, fragment pager
|
@ -11,9 +11,10 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "com.android.support:support-v4:$supportVersion"
|
compile "com.android.support:support-v4:$supportVersion"
|
||||||
compile "com.android.support:appcompat-v7:$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: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 "com.android.support:recyclerview-v7:$supportVersion"
|
||||||
compile "org.apache.commons:commons-lang3:$commonslangVersion"
|
compile "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||||
compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
||||||
|
@ -37,6 +38,9 @@ dependencies {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
|
compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
|
||||||
|
compile("com.githang:viewpagerindicator:2.5@aar") {
|
||||||
|
exclude module: "support-v4"
|
||||||
|
}
|
||||||
|
|
||||||
compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
|
compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,10 @@ package de.test.antennapod.ui;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
import android.test.ActivityInstrumentationTestCase2;
|
||||||
import android.test.FlakyTest;
|
|
||||||
|
|
||||||
import com.robotium.solo.Condition;
|
|
||||||
import com.robotium.solo.Solo;
|
import com.robotium.solo.Solo;
|
||||||
import com.robotium.solo.Timeout;
|
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 java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -1,54 +1,43 @@
|
||||||
package de.danoeh.antennapod.activity;
|
package de.danoeh.antennapod.activity;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.TypedArray;
|
import android.os.Build;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.support.design.widget.AppBarLayout;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v4.app.Fragment;
|
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.app.ListFragment;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
import android.support.v4.widget.DrawerLayout;
|
import android.support.v4.widget.DrawerLayout;
|
||||||
import android.support.v7.app.ActionBarDrawerToggle;
|
import android.support.v7.app.ActionBarDrawerToggle;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
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.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ListView;
|
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.R;
|
||||||
import de.danoeh.antennapod.adapter.ChapterListAdapter;
|
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
|
||||||
import de.danoeh.antennapod.adapter.NavListAdapter;
|
import de.danoeh.antennapod.adapter.NavListAdapter;
|
||||||
import de.danoeh.antennapod.core.asynctask.FeedRemover;
|
import de.danoeh.antennapod.core.asynctask.FeedRemover;
|
||||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
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.EventDistributor;
|
||||||
import de.danoeh.antennapod.core.feed.Feed;
|
import de.danoeh.antennapod.core.feed.Feed;
|
||||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.core.feed.MediaType;
|
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.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
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.ExternalMedia;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
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.CoverFragment;
|
||||||
|
import de.danoeh.antennapod.fragment.DownloadsFragment;
|
||||||
|
import de.danoeh.antennapod.fragment.EpisodesFragment;
|
||||||
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
|
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.menuhandler.NavDrawerActivity;
|
||||||
import de.danoeh.antennapod.preferences.PreferenceController;
|
import de.danoeh.antennapod.preferences.PreferenceController;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
@ -69,85 +64,38 @@ import rx.schedulers.Schedulers;
|
||||||
/**
|
/**
|
||||||
* Activity for playing audio files.
|
* Activity for playing audio files.
|
||||||
*/
|
*/
|
||||||
public class AudioplayerActivity extends MediaplayerActivity implements ItemDescriptionFragment.ItemDescriptionFragmentCallback,
|
public class AudioplayerActivity extends MediaplayerActivity implements NavDrawerActivity {
|
||||||
NavDrawerActivity {
|
|
||||||
|
|
||||||
private static final int POS_COVER = 0;
|
private static final int POS_COVER = 0;
|
||||||
private static final int POS_DESCR = 1;
|
private static final int POS_DESCR = 1;
|
||||||
private static final int POS_CHAPTERS = 2;
|
private static final int POS_CHAPTERS = 2;
|
||||||
private static final int NUM_CONTENT_FRAGMENTS = 3;
|
private static final int NUM_CONTENT_FRAGMENTS = 3;
|
||||||
private static final int POS_NONE = -1;
|
|
||||||
|
|
||||||
final String TAG = "AudioplayerActivity";
|
final String TAG = "AudioplayerActivity";
|
||||||
private static final String PREFS = "AudioPlayerActivityPreferences";
|
private static final String PREFS = "AudioPlayerActivityPreferences";
|
||||||
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
|
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 DrawerLayout drawerLayout;
|
||||||
private NavListAdapter navAdapter;
|
private NavListAdapter navAdapter;
|
||||||
private ListView navList;
|
private ListView navList;
|
||||||
private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
|
|
||||||
private View navDrawer;
|
private View navDrawer;
|
||||||
private ActionBarDrawerToggle drawerToggle;
|
private ActionBarDrawerToggle drawerToggle;
|
||||||
|
private int mPosition = -1;
|
||||||
|
|
||||||
private Fragment[] detachedFragments;
|
private Playable media;
|
||||||
|
private ViewPager mPager;
|
||||||
private CoverFragment coverFragment;
|
private AudioplayerPagerAdapter mPagerAdapter;
|
||||||
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 Subscription subscription;
|
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
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
@ -156,6 +104,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
EventDistributor.getInstance().unregister(contentUpdate);
|
EventDistributor.getInstance().unregister(contentUpdate);
|
||||||
|
saveCurrentFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,29 +112,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
setTheme(UserPreferences.getNoTitleTheme());
|
setTheme(UserPreferences.getNoTitleTheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void saveCurrentFragment() {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
if(mPager == null) {
|
||||||
super.onCreate(savedInstanceState);
|
return;
|
||||||
detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void savePreferences() {
|
|
||||||
Log.d(TAG, "Saving preferences");
|
Log.d(TAG, "Saving preferences");
|
||||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
prefs.edit()
|
||||||
if (currentlyShownPosition >= 0 && controller != null
|
.putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, mPager.getCurrentItem())
|
||||||
&& controller.getMedia() != null) {
|
.commit();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -194,53 +130,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
drawerToggle.onConfigurationChanged(newConfig);
|
drawerToggle.onConfigurationChanged(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void loadLastFragment() {
|
||||||
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() {
|
|
||||||
Log.d(TAG, "Restoring instance state");
|
Log.d(TAG, "Restoring instance state");
|
||||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||||
int savedPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION,
|
int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
|
||||||
-1);
|
mPager.setCurrentItem(lastPosition);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -260,10 +154,12 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
true);
|
true);
|
||||||
startService(launchIntent);
|
startService(launchIntent);
|
||||||
}
|
}
|
||||||
if (savedPosition != -1) {
|
if(mPagerAdapter != null && controller != null && controller.getMedia() != media) {
|
||||||
switchToFragment(savedPosition);
|
media = controller.getMedia();
|
||||||
|
mPagerAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EventDistributor.getInstance().register(contentUpdate);
|
EventDistributor.getInstance().register(contentUpdate);
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
@ -292,147 +188,25 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
@Override
|
@Override
|
||||||
protected void clearStatusMsg() {
|
protected void clearStatusMsg() {
|
||||||
// TODO Hide progress bar here
|
// 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
|
@Override
|
||||||
protected void setupGUI() {
|
protected void setupGUI() {
|
||||||
super.setupGUI();
|
super.setupGUI();
|
||||||
resetFragmentView();
|
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
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);
|
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||||
navList = (ListView) findViewById(R.id.nav_list);
|
navList = (ListView) findViewById(R.id.nav_list);
|
||||||
navDrawer = findViewById(R.id.nav_layout);
|
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 = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
|
||||||
drawerToggle.setDrawerIndicatorEnabled(false);
|
drawerToggle.setDrawerIndicatorEnabled(false);
|
||||||
|
@ -450,6 +224,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
}
|
}
|
||||||
drawerLayout.closeDrawer(navDrawer);
|
drawerLayout.closeDrawer(navDrawer);
|
||||||
});
|
});
|
||||||
|
navList.setOnItemLongClickListener((parent, view, position, id) -> {
|
||||||
|
if (position < navAdapter.getTags().size()) {
|
||||||
|
showDrawerPreferencesDialog();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
mPosition = position;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
registerForContextMenu(navList);
|
registerForContextMenu(navList);
|
||||||
drawerToggle.syncState();
|
drawerToggle.syncState();
|
||||||
|
|
||||||
|
@ -458,128 +241,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
|
startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
|
||||||
});
|
});
|
||||||
|
|
||||||
butNavChaptersShownotes.setOnClickListener(v -> {
|
mPager = (ViewPager) findViewById(R.id.pager);
|
||||||
if (currentlyShownPosition == POS_CHAPTERS) {
|
if(mPager.getAdapter() == null) {
|
||||||
switchToFragment(POS_DESCR);
|
mPagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
|
||||||
} else if (currentlyShownPosition == POS_DESCR) {
|
mPager.setAdapter(mPagerAdapter);
|
||||||
switchToFragment(POS_CHAPTERS);
|
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
|
||||||
} else if (currentlyShownPosition == POS_COVER) {
|
pageIndicator.setViewPager(mPager);
|
||||||
switchToLastFragment();
|
loadLastFragment();
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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.onSaveInstanceState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -593,48 +263,17 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
if (!super.loadMediaInfo()) {
|
if (!super.loadMediaInfo()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Playable media = controller.getMedia();
|
if(controller.getMedia() != media) {
|
||||||
if (media == null) {
|
media = controller.getMedia();
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyMediaPositionChanged() {
|
public void notifyMediaPositionChanged() {
|
||||||
if (chapterFragment != null) {
|
ListFragment chapterFragment = (ListFragment) mPagerAdapter.getItem(POS_CHAPTERS);
|
||||||
ArrayAdapter<SimpleChapter> adapter = (ArrayAdapter<SimpleChapter>) chapterFragment
|
ChaptersListAdapter adapter = (ChaptersListAdapter) chapterFragment.getListAdapter();
|
||||||
.getListAdapter();
|
if(adapter != null) {
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,7 +298,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
clearStatusMsg();
|
clearStatusMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PlaybackController getPlaybackController() {
|
public PlaybackController getPlaybackController() {
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
@ -669,10 +307,6 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
|
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface AudioplayerContentFragment {
|
|
||||||
void onDataSetChanged(Playable media);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getContentViewResourceId() {
|
protected int getContentViewResourceId() {
|
||||||
return R.layout.audioplayer_activity;
|
return R.layout.audioplayer_activity;
|
||||||
|
@ -704,24 +338,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
||||||
menu.setHeaderTitle(feed.getTitle());
|
menu.setHeaderTitle(feed.getTitle());
|
||||||
// episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
|
// 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
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
final int position = mPosition;
|
||||||
|
mPosition = -1; // reset
|
||||||
if(menuInfo == null) {
|
if(position < 0) {
|
||||||
menuInfo = lastMenuInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(menuInfo.targetView.getParent() instanceof ListView == false
|
|
||||||
|| ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int position = menuInfo.position;
|
|
||||||
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
|
||||||
switch(item.getItemId()) {
|
switch(item.getItemId()) {
|
||||||
case R.id.mark_all_seen_item:
|
case R.id.mark_all_seen_item:
|
||||||
|
@ -772,11 +397,43 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if(isDrawerOpen()) {
|
if(isDrawerOpen()) {
|
||||||
drawerLayout.closeDrawer(navDrawer);
|
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();
|
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;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,44 @@
|
||||||
package de.danoeh.antennapod.activity;
|
package de.danoeh.antennapod.activity;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
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.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
import com.bumptech.glide.Glide;
|
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.R;
|
||||||
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
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.DBTasks;
|
||||||
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
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.Playable;
|
||||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||||
import de.danoeh.antennapod.dialog.SleepTimerDialog;
|
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
|
* Provides general features which are both needed for playing audio and video
|
||||||
* files.
|
* files.
|
||||||
*/
|
*/
|
||||||
public abstract class MediaplayerActivity extends ActionBarActivity
|
public abstract class MediaplayerActivity extends AppCompatActivity implements OnSeekBarChangeListener {
|
||||||
implements OnSeekBarChangeListener {
|
|
||||||
private static final String TAG = "MediaplayerActivity";
|
private static final String TAG = "MediaplayerActivity";
|
||||||
private static final String PREFS = "MediaPlayerActivityPreferences";
|
private static final String PREFS = "MediaPlayerActivityPreferences";
|
||||||
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
|
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
|
||||||
|
@ -52,12 +66,17 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
protected TextView txtvPosition;
|
protected TextView txtvPosition;
|
||||||
protected TextView txtvLength;
|
protected TextView txtvLength;
|
||||||
protected SeekBar sbPosition;
|
protected SeekBar sbPosition;
|
||||||
protected ImageButton butPlay;
|
protected Button butPlaybackSpeed;
|
||||||
protected ImageButton butRev;
|
protected ImageButton butRev;
|
||||||
protected boolean showTimeLeft = false;
|
|
||||||
protected TextView txtvRev;
|
protected TextView txtvRev;
|
||||||
|
protected ImageButton butPlay;
|
||||||
protected ImageButton butFF;
|
protected ImageButton butFF;
|
||||||
protected TextView txtvFF;
|
protected TextView txtvFF;
|
||||||
|
protected ImageButton butSkip;
|
||||||
|
|
||||||
|
protected boolean showTimeLeft = false;
|
||||||
|
|
||||||
|
private boolean isFavorite = false;
|
||||||
|
|
||||||
private PlaybackController newPlaybackController() {
|
private PlaybackController newPlaybackController() {
|
||||||
return new PlaybackController(this, false) {
|
return new PlaybackController(this, false) {
|
||||||
|
@ -157,7 +176,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onPlaybackSpeedChange() {
|
protected void onPlaybackSpeedChange() {
|
||||||
|
updateButPlaybackSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onServiceQueried() {
|
protected void onServiceQueried() {
|
||||||
|
@ -268,7 +287,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
super.onPrepareOptionsMenu(menu);
|
super.onPrepareOptionsMenu(menu);
|
||||||
if(controller == null) {
|
if (controller == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Playable media = controller.getMedia();
|
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.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 sleepTimerSet = controller.sleepTimerActive();
|
||||||
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
|
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
|
||||||
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
|
menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
|
||||||
menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if(controller == null) {
|
if (controller == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Playable media = controller.getMedia();
|
Playable media = controller.getMedia();
|
||||||
|
@ -317,84 +352,217 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
} else if (media != null) {
|
} else {
|
||||||
switch (item.getItemId()) {
|
if (media != null) {
|
||||||
case R.id.disable_sleeptimer_item:
|
switch (item.getItemId()) {
|
||||||
if (controller.serviceAvailable()) {
|
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);
|
MaterialDialog.Builder stDialog = new MaterialDialog.Builder(this);
|
||||||
stDialog.title(R.string.sleep_timer_label);
|
stDialog.title(R.string.sleep_timer_label);
|
||||||
stDialog.content(getString(R.string.time_left_label)
|
stDialog.content(getString(R.string.time_left_label)
|
||||||
+ Converter.getDurationStringLong((int) controller
|
+ Converter.getDurationStringLong((int) controller
|
||||||
.getSleepTimerTimeLeft()));
|
.getSleepTimerTimeLeft()));
|
||||||
stDialog.positiveText(R.string.disable_sleeptimer_label);
|
stDialog.positiveText(R.string.disable_sleeptimer_label);
|
||||||
stDialog.negativeText(R.string.cancel_label);
|
stDialog.negativeText(R.string.cancel_label);
|
||||||
stDialog.callback(new MaterialDialog.ButtonCallback() {
|
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
|
@Override
|
||||||
public void onPositive(MaterialDialog dialog) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
dialog.dismiss();
|
float playbackSpeed = (progress + 10) / 20.0f;
|
||||||
controller.disableSleepTimer();
|
controller.setPlaybackSpeed(playbackSpeed);
|
||||||
|
String speed = String.format("%.2f", playbackSpeed);
|
||||||
|
UserPreferences.setPlaybackSpeed(speed);
|
||||||
|
txtvPlaybackSpeed.setText(speed + "x");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNegative(MaterialDialog dialog) {
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
dialog.dismiss();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
stDialog.build().show();
|
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
|
||||||
}
|
|
||||||
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.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;
|
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
&& controller.getMedia() != null) {
|
||||||
txtvPosition.setText(Converter
|
txtvPosition.setText(Converter
|
||||||
.getDurationStringLong(currentPosition));
|
.getDurationStringLong(currentPosition));
|
||||||
if(showTimeLeft) {
|
if (showTimeLeft) {
|
||||||
txtvLength.setText("-"+Converter
|
txtvLength.setText("-" + Converter
|
||||||
.getDurationStringLong(duration - currentPosition));
|
.getDurationStringLong(duration - currentPosition));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
txtvLength.setText(Converter
|
txtvLength.setText(Converter
|
||||||
.getDurationStringLong(duration));
|
.getDurationStringLong(duration));
|
||||||
}
|
}
|
||||||
|
@ -443,7 +610,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgressbarPosition(int position, int duration) {
|
private void updateProgressbarPosition(int position, int duration) {
|
||||||
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration +")");
|
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
|
||||||
float progress = ((float) position) / duration;
|
float progress = ((float) position) / duration;
|
||||||
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
||||||
}
|
}
|
||||||
|
@ -458,22 +625,31 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
Log.d(TAG, "loadMediaInfo()");
|
Log.d(TAG, "loadMediaInfo()");
|
||||||
Playable media = controller.getMedia();
|
Playable media = controller.getMedia();
|
||||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
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) {
|
if (media != null) {
|
||||||
txtvPosition.setText(Converter.getDurationStringLong((media
|
txtvPosition.setText(Converter.getDurationStringLong((media.getPosition())));
|
||||||
.getPosition())));
|
|
||||||
|
|
||||||
if (media.getDuration() != 0) {
|
if (media.getDuration() != 0) {
|
||||||
txtvLength.setText(Converter.getDurationStringLong(media
|
txtvLength.setText(Converter.getDurationStringLong(media.getDuration()));
|
||||||
.getDuration()));
|
float progress = ((float) media.getPosition()) / media.getDuration();
|
||||||
float progress = ((float) media.getPosition())
|
|
||||||
/ media.getDuration();
|
|
||||||
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
||||||
if(showTimeLeft) {
|
if (showTimeLeft) {
|
||||||
txtvLength.setText("-"+Converter.getDurationStringLong((media
|
int timeLeft = media.getDuration() - media.getPosition();
|
||||||
.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;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -486,43 +662,42 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
|
txtvPosition = (TextView) findViewById(R.id.txtvPosition);
|
||||||
|
|
||||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||||
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT,false);
|
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
|
||||||
Log.d("timeleft",showTimeLeft? "true":"false");
|
Log.d("timeleft", showTimeLeft ? "true" : "false");
|
||||||
txtvLength = (TextView) findViewById(R.id.txtvLength);
|
txtvLength = (TextView) findViewById(R.id.txtvLength);
|
||||||
txtvLength.setOnClickListener(new View.OnClickListener() {
|
txtvLength.setOnClickListener(v -> {
|
||||||
@Override
|
showTimeLeft = !showTimeLeft;
|
||||||
public void onClick(View v) {
|
Playable media = controller.getMedia();
|
||||||
showTimeLeft = !showTimeLeft;
|
if (media == null) {
|
||||||
Playable media = controller.getMedia();
|
return;
|
||||||
if (media == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
butRev = (ImageButton) findViewById(R.id.butRev);
|
||||||
txtvRev = (TextView) findViewById(R.id.txtvRev);
|
txtvRev = (TextView) findViewById(R.id.txtvRev);
|
||||||
if(txtvRev != null) {
|
if (txtvRev != null) {
|
||||||
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
|
txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
|
||||||
}
|
}
|
||||||
|
butPlay = (ImageButton) findViewById(R.id.butPlay);
|
||||||
butFF = (ImageButton) findViewById(R.id.butFF);
|
butFF = (ImageButton) findViewById(R.id.butFF);
|
||||||
txtvFF = (TextView) findViewById(R.id.txtvFF);
|
txtvFF = (TextView) findViewById(R.id.txtvFF);
|
||||||
if(txtvFF != null) {
|
if (txtvFF != null) {
|
||||||
txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs()));
|
txtvFF.setText(String.valueOf(UserPreferences.getFastFowardSecs()));
|
||||||
}
|
}
|
||||||
|
butSkip = (ImageButton) findViewById(R.id.butSkip);
|
||||||
|
|
||||||
// SEEKBAR SETUP
|
// SEEKBAR SETUP
|
||||||
|
|
||||||
|
@ -530,15 +705,88 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
|
|
||||||
// BUTTON SETUP
|
// BUTTON SETUP
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
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 -> {
|
||||||
|
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.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++) {
|
||||||
|
if (rewindSecs == values[i]) {
|
||||||
|
checked = i;
|
||||||
|
}
|
||||||
|
choices[i] = String.valueOf(values[i]) + " "
|
||||||
|
+ getString(R.string.time_seconds);
|
||||||
|
}
|
||||||
|
choice = values[checked];
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
|
||||||
|
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.setPrefRewindSecs(choice);
|
||||||
|
txtvRev.setText(String.valueOf(choice));
|
||||||
|
});
|
||||||
|
builder.create().show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
||||||
|
|
||||||
if (butFF != null) {
|
if (butFF != null) {
|
||||||
butFF.setOnClickListener(new View.OnClickListener() {
|
butFF.setOnClickListener(v -> {
|
||||||
@Override
|
int curr = controller.getPosition();
|
||||||
public void onClick(View v) {
|
controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
|
||||||
int curr = controller.getPosition();
|
|
||||||
controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
butFF.setOnLongClickListener(new View.OnLongClickListener() {
|
butFF.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
|
||||||
|
@ -550,7 +798,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
int rewindSecs = UserPreferences.getFastFowardSecs();
|
int rewindSecs = UserPreferences.getFastFowardSecs();
|
||||||
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
|
final int[] values = getResources().getIntArray(R.array.seek_delta_values);
|
||||||
final String[] choices = new String[values.length];
|
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]) {
|
if (rewindSecs == values[i]) {
|
||||||
checked = i;
|
checked = i;
|
||||||
}
|
}
|
||||||
|
@ -574,55 +822,12 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (butRev != null) {
|
|
||||||
butRev.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
int curr = controller.getPosition();
|
|
||||||
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
butRev.setOnLongClickListener(new View.OnLongClickListener() {
|
|
||||||
|
|
||||||
int choice;
|
if (butSkip != null) {
|
||||||
|
butSkip.setOnClickListener(v -> {
|
||||||
@Override
|
sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
|
||||||
public boolean onLongClick(View v) {
|
|
||||||
int checked = 0;
|
|
||||||
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++) {
|
|
||||||
if (rewindSecs == values[i]) {
|
|
||||||
checked = i;
|
|
||||||
}
|
|
||||||
choices[i] = String.valueOf(values[i]) + " "
|
|
||||||
+ getString(R.string.time_seconds);
|
|
||||||
}
|
|
||||||
choice = values[checked];
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
|
|
||||||
builder.setTitle(R.string.pref_rewind);
|
|
||||||
builder.setSingleChoiceItems(choices, checked,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int 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.create().show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int getContentViewResourceId();
|
protected abstract int getContentViewResourceId();
|
||||||
|
@ -633,12 +838,9 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
errorDialog
|
errorDialog
|
||||||
.setMessage(MediaPlayerError.getErrorString(this, errorCode));
|
.setMessage(MediaPlayerError.getErrorString(this, errorCode));
|
||||||
errorDialog.setNeutralButton("OK",
|
errorDialog.setNeutralButton("OK",
|
||||||
new DialogInterface.OnClickListener() {
|
(dialog, which) -> {
|
||||||
@Override
|
dialog.dismiss();
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
finish();
|
||||||
dialog.dismiss();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
errorDialog.create().show();
|
errorDialog.create().show();
|
||||||
|
@ -652,14 +854,20 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser,
|
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser,
|
||||||
txtvPosition);
|
txtvPosition);
|
||||||
if(showTimeLeft && prog!=0) {
|
if (showTimeLeft && prog != 0) {
|
||||||
int duration = controller.getDuration();
|
int duration = controller.getDuration();
|
||||||
txtvLength.setText("-"+Converter
|
txtvLength.setText("-" + Converter
|
||||||
.getDurationStringLong(duration - (int) (prog * duration)));
|
.getDurationStringLong(duration - (int) (prog * duration)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateButPlaybackSpeed() {
|
||||||
|
if (controller != null) {
|
||||||
|
butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed() + "x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
if (controller != null) {
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,107 +21,96 @@ import de.danoeh.antennapod.core.util.IntentUtils;
|
||||||
|
|
||||||
public class VariableSpeedDialog {
|
public class VariableSpeedDialog {
|
||||||
|
|
||||||
private static final String TAG = VariableSpeedDialog.class.getSimpleName();
|
private static final String TAG = VariableSpeedDialog.class.getSimpleName();
|
||||||
|
|
||||||
private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
|
private static final Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
|
||||||
Uri.parse("market://details?id=com.falconware.prestissimo"));
|
Uri.parse("market://details?id=com.falconware.prestissimo"));
|
||||||
|
|
||||||
private VariableSpeedDialog() {
|
private VariableSpeedDialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showDialog(final Context context) {
|
public static void showDialog(final Context context) {
|
||||||
if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
|
if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)
|
||||||
|| UserPreferences.useSonic()) {
|
|| UserPreferences.useSonic()) {
|
||||||
showSpeedSelectorDialog(context);
|
showSpeedSelectorDialog(context);
|
||||||
} else {
|
} else {
|
||||||
showGetPluginDialog(context);
|
showGetPluginDialog(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void showGetPluginDialog(final Context context) {
|
private static void showGetPluginDialog(final Context context) {
|
||||||
MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
|
MaterialDialog.Builder builder = new MaterialDialog.Builder(context);
|
||||||
builder.title(R.string.no_playback_plugin_title);
|
builder.title(R.string.no_playback_plugin_title);
|
||||||
builder.content(R.string.no_playback_plugin_or_sonic_msg);
|
builder.content(R.string.no_playback_plugin_or_sonic_msg);
|
||||||
builder.positiveText(R.string.download_plugin_label);
|
builder.positiveText(R.string.download_plugin_label);
|
||||||
builder.negativeText(R.string.enable_sonic);
|
builder.negativeText(R.string.enable_sonic);
|
||||||
builder.neutralText(R.string.close_label);
|
builder.neutralText(R.string.close_label);
|
||||||
builder.callback(new MaterialDialog.ButtonCallback() {
|
builder.onPositive((dialog, which) -> {
|
||||||
@Override
|
try {
|
||||||
public void onPositive(MaterialDialog dialog) {
|
context.startActivity(playStoreIntent);
|
||||||
try {
|
} catch (ActivityNotFoundException e) {
|
||||||
context.startActivity(playStoreIntent);
|
// this is usually thrown on an emulator if the Android market is not installed
|
||||||
} catch (ActivityNotFoundException e) {
|
Log.e(TAG, Log.getStackTraceString(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private static void showSpeedSelectorDialog(final Context context) {
|
||||||
public void onNegative(MaterialDialog dialog) {
|
final String[] speedValues = context.getResources().getStringArray(
|
||||||
if (Build.VERSION.SDK_INT >= 16) { // just to be safe
|
R.array.playback_speed_values);
|
||||||
UserPreferences.enableSonic(true);
|
// According to Java spec these get initialized to false on creation
|
||||||
showSpeedSelectorDialog(context);
|
final boolean[] speedChecked = new boolean[speedValues.length];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// Build the "isChecked" array so that multiChoice dialog is
|
||||||
public void onNeutral(MaterialDialog dialog) {
|
// populated correctly
|
||||||
super.onNeutral(dialog);
|
List<String> selectedSpeedList = Arrays.asList(UserPreferences
|
||||||
}
|
.getPlaybackSpeedArray());
|
||||||
});
|
for (int i = 0; i < speedValues.length; i++) {
|
||||||
builder.forceStacking(true);
|
speedChecked[i] = selectedSpeedList.contains(speedValues[i]);
|
||||||
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) {
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
final String[] speedValues = context.getResources().getStringArray(
|
builder.setTitle(R.string.set_playback_speed_label);
|
||||||
R.array.playback_speed_values);
|
builder.setMultiChoiceItems(R.array.playback_speed_values,
|
||||||
// According to Java spec these get initialized to false on creation
|
speedChecked, (dialog, which, isChecked) -> {
|
||||||
final boolean[] speedChecked = new boolean[speedValues.length];
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build the "isChecked" array so that multiChoice dialog is
|
UserPreferences.setPlaybackSpeedArray(newSpeedValues);
|
||||||
// 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.create().show();
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,21 @@
|
||||||
package de.danoeh.antennapod.fragment;
|
package de.danoeh.antennapod.fragment;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.graphics.Bitmap;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.graphics.Palette;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
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.R;
|
||||||
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
|
||||||
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
|
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
|
||||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
@ -30,10 +30,11 @@ public class CoverFragment extends Fragment implements
|
||||||
|
|
||||||
private Playable media;
|
private Playable media;
|
||||||
|
|
||||||
|
private View root;
|
||||||
|
private TextView txtvPodcastTitle;
|
||||||
|
private TextView txtvEpisodeTitle;
|
||||||
private ImageView imgvCover;
|
private ImageView imgvCover;
|
||||||
|
|
||||||
private boolean viewCreated = false;
|
|
||||||
|
|
||||||
public static CoverFragment newInstance(Playable item) {
|
public static CoverFragment newInstance(Playable item) {
|
||||||
CoverFragment f = new CoverFragment();
|
CoverFragment f = new CoverFragment();
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
@ -59,38 +60,45 @@ public class CoverFragment extends Fragment implements
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
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 = (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;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMediaInfo() {
|
private void loadMediaInfo() {
|
||||||
|
if(imgvCover == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
imgvCover.post(new Runnable() {
|
Log.d(TAG, "feed title: " + media.getFeedTitle());
|
||||||
|
Log.d(TAG, "episode title: " + media.getEpisodeTitle());
|
||||||
@Override
|
txtvPodcastTitle.setText(media.getFeedTitle());
|
||||||
public void run() {
|
txtvEpisodeTitle.setText(media.getEpisodeTitle());
|
||||||
Context c = getActivity();
|
imgvCover.post(() -> {
|
||||||
if (c != null) {
|
Glide.with(this)
|
||||||
Glide.with(c)
|
.load(media.getImageUri())
|
||||||
.load(media.getImageUri())
|
.asBitmap()
|
||||||
.placeholder(R.color.light_gray)
|
.placeholder(R.color.light_gray)
|
||||||
.error(R.color.light_gray)
|
.error(R.color.light_gray)
|
||||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
.into(imgvCover);
|
.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 {
|
} else {
|
||||||
Log.w(TAG, "loadMediaInfo was called while media was null");
|
Log.w(TAG, "loadMediaInfo was called while media was null");
|
||||||
|
@ -99,12 +107,10 @@ public class CoverFragment extends Fragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (BuildConfig.DEBUG)
|
Log.d(TAG, "On Start");
|
||||||
Log.d(TAG, "On Start");
|
|
||||||
super.onStart();
|
super.onStart();
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
if (BuildConfig.DEBUG)
|
Log.d(TAG, "Loading media info");
|
||||||
Log.d(TAG, "Loading media info");
|
|
||||||
loadMediaInfo();
|
loadMediaInfo();
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Unable to load media info: media was null");
|
Log.w(TAG, "Unable to load media info: media was null");
|
||||||
|
@ -114,10 +120,7 @@ public class CoverFragment extends Fragment implements
|
||||||
@Override
|
@Override
|
||||||
public void onDataSetChanged(Playable media) {
|
public void onDataSetChanged(Playable media) {
|
||||||
this.media = media;
|
this.media = media;
|
||||||
if (viewCreated) {
|
loadMediaInfo();
|
||||||
loadMediaInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||||
|
@ -79,51 +78,16 @@ public class ExternalPlayerFragment extends Fragment {
|
||||||
private PlaybackController setupPlaybackController() {
|
private PlaybackController setupPlaybackController() {
|
||||||
return new PlaybackController(getActivity(), true) {
|
return new PlaybackController(getActivity(), true) {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setupGUI() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionObserverUpdate() {
|
public void onPositionObserverUpdate() {
|
||||||
ExternalPlayerFragment.this.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
|
@Override
|
||||||
public ImageButton getPlayButton() {
|
public ImageButton getPlayButton() {
|
||||||
return butPlay;
|
return butPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postStatusMsg(int msg) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearStatusMsg() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean loadMediaInfo() {
|
public boolean loadMediaInfo() {
|
||||||
|
@ -135,14 +99,6 @@ public class ExternalPlayerFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAwaitingVideoSurface() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceQueried() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onShutdownNotification() {
|
public void onShutdownNotification() {
|
||||||
playbackDone();
|
playbackDone();
|
||||||
|
@ -152,10 +108,6 @@ public class ExternalPlayerFragment extends Fragment {
|
||||||
public void onPlaybackEnd() {
|
public void onPlaybackEnd() {
|
||||||
playbackDone();
|
playbackDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlaybackSpeedChange() {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
@ -26,6 +25,8 @@ import android.webkit.WebViewClient;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
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.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.storage.DBReader;
|
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.Playable;
|
||||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||||
import de.danoeh.antennapod.core.util.playback.Timeline;
|
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.
|
* 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";
|
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 static final String ARG_HIGHLIGHT_TIMECODES = "arg.highlightTimecodes";
|
||||||
|
|
||||||
private WebView webvDescription;
|
private WebView webvDescription;
|
||||||
|
private String webvData;
|
||||||
|
|
||||||
private ShownotesProvider shownotesProvider;
|
private ShownotesProvider shownotesProvider;
|
||||||
private Playable media;
|
private Playable media;
|
||||||
|
|
||||||
|
|
||||||
private AsyncTask<Void, Void, Void> webViewLoader;
|
private Subscription webViewLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL that was selected via long-press.
|
* 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) {
|
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||||
}
|
}
|
||||||
webvDescription.setBackgroundColor(getResources().getColor(
|
webvDescription.setBackgroundColor(getResources().getColor(R.color.black));
|
||||||
R.color.black));
|
|
||||||
}
|
}
|
||||||
webvDescription.getSettings().setUseWideViewPort(false);
|
webvDescription.getSettings().setUseWideViewPort(false);
|
||||||
webvDescription.getSettings().setLayoutAlgorithm(
|
webvDescription.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
|
||||||
LayoutAlgorithm.NARROW_COLUMNS);
|
|
||||||
webvDescription.getSettings().setLoadWithOverviewMode(true);
|
webvDescription.getSettings().setLoadWithOverviewMode(true);
|
||||||
webvDescription.setOnLongClickListener(webViewLongClickListener);
|
webvDescription.setOnLongClickListener(webViewLongClickListener);
|
||||||
webvDescription.setWebViewClient(new WebViewClient() {
|
webvDescription.setWebViewClient(new WebViewClient() {
|
||||||
|
@ -142,14 +146,7 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
super.onPageFinished(view, url);
|
super.onPageFinished(view, url);
|
||||||
Log.d(TAG, "Page finished");
|
Log.d(TAG, "Page finished");
|
||||||
// Restoring the scroll position might not always work
|
// Restoring the scroll position might not always work
|
||||||
view.postDelayed(new Runnable() {
|
view.postDelayed(() -> restoreFromPreference(), 50);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
restoreFromPreference();
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -158,27 +155,12 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
return webvDescription;
|
return webvDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
Log.d(TAG, "Fragment destroyed");
|
Log.d(TAG, "Fragment destroyed");
|
||||||
if (webViewLoader != null) {
|
if (webViewLoader != null) {
|
||||||
webViewLoader.cancel(true);
|
webViewLoader.unsubscribe();
|
||||||
}
|
}
|
||||||
if (webvDescription != null) {
|
if (webvDescription != null) {
|
||||||
webvDescription.removeAllViews();
|
webvDescription.removeAllViews();
|
||||||
|
@ -194,7 +176,6 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
saveState = args.getBoolean(ARG_SAVE_STATE, false);
|
saveState = args.getBoolean(ARG_SAVE_STATE, false);
|
||||||
highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
|
highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -204,47 +185,22 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
if (args.containsKey(ARG_PLAYABLE)) {
|
if (args.containsKey(ARG_PLAYABLE)) {
|
||||||
media = args.getParcelable(ARG_PLAYABLE);
|
media = args.getParcelable(ARG_PLAYABLE);
|
||||||
shownotesProvider = media;
|
shownotesProvider = media;
|
||||||
startLoader();
|
load();
|
||||||
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
|
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
|
||||||
AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() {
|
long id = getArguments().getLong(ARG_FEEDITEM_ID);
|
||||||
|
Observable.defer(() -> Observable.just(DBReader.getFeedItem(id)))
|
||||||
@Override
|
.subscribeOn(Schedulers.newThread())
|
||||||
protected FeedItem doInBackground(Void... voids) {
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
return DBReader.getFeedItem(getArguments().getLong(ARG_FEEDITEM_ID));
|
.subscribe(feedItem -> {
|
||||||
}
|
shownotesProvider = feedItem;
|
||||||
|
load();
|
||||||
@Override
|
}, error -> {
|
||||||
protected void onPostExecute(FeedItem feedItem) {
|
Log.e(TAG, Log.getStackTraceString(error));
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@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() {
|
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -338,49 +294,31 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AsyncTask<Void, Void, Void> createLoader() {
|
private void load() {
|
||||||
return new AsyncTask<Void, Void, Void>() {
|
Log.d(TAG, "load()");
|
||||||
@Override
|
if(webViewLoader != null) {
|
||||||
protected void onCancelled() {
|
webViewLoader.unsubscribe();
|
||||||
super.onCancelled();
|
}
|
||||||
webViewLoader = null;
|
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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
String data;
|
private String loadData() {
|
||||||
|
Timeline timeline = new Timeline(getActivity(), shownotesProvider);
|
||||||
@Override
|
String data = timeline.processShownotes(highlightTimecodes);
|
||||||
protected void onPostExecute(Void result) {
|
return data;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -410,7 +348,7 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean restoreFromPreference() {
|
private boolean restoreFromPreference() {
|
||||||
if (saveState) {
|
if (!saveState) {
|
||||||
Log.d(TAG, "Restoring from preferences");
|
Log.d(TAG, "Restoring from preferences");
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
|
@ -433,15 +371,19 @@ public class ItemDescriptionFragment extends Fragment {
|
||||||
|
|
||||||
private void onTimecodeLinkSelected(String link) {
|
private void onTimecodeLinkSelected(String link) {
|
||||||
int time = Timeline.getTimecodeLinkTime(link);
|
int time = Timeline.getTimecodeLinkTime(link);
|
||||||
if (getActivity() != null && getActivity() instanceof ItemDescriptionFragmentCallback) {
|
if (getActivity() != null && getActivity() instanceof AudioplayerActivity) {
|
||||||
PlaybackController pc = ((ItemDescriptionFragmentCallback) getActivity()).getPlaybackController();
|
PlaybackController pc = ((AudioplayerActivity) getActivity()).getPlaybackController();
|
||||||
if (pc != null) {
|
if (pc != null) {
|
||||||
pc.seekTo(time);
|
pc.seekTo(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ItemDescriptionFragmentCallback {
|
@Override
|
||||||
public PlaybackController getPlaybackController();
|
public void onDataSetChanged(Playable media) {
|
||||||
|
this.media = media;
|
||||||
|
this.shownotesProvider = media;
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -1,219 +1,219 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/drawer_layout"
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:background="@android:color/holo_red_dark">
|
tools:background="@android:color/holo_red_dark">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical">
|
|
||||||
|
<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.support.v7.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
android:minHeight="?attr/actionBarSize"
|
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_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_marginTop="-12dp"
|
||||||
android:orientation="horizontal"
|
android:layout_marginBottom="4dp"
|
||||||
android:paddingLeft="8dp"
|
android:background="@android:color/transparent"
|
||||||
android:paddingRight="8dp">
|
app:fillColor="?android:attr/textColorSecondary"
|
||||||
|
app:strokeColor="?android:attr/textColorSecondary"
|
||||||
|
app:radius="4dp" />
|
||||||
|
|
||||||
<TextView
|
</android.support.design.widget.AppBarLayout>
|
||||||
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
|
<LinearLayout
|
||||||
android:id="@+id/butCover"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="32dp"
|
android:id="@+id/playtime_layout"
|
||||||
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_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/non_transparent_background"
|
android:paddingTop="8dp"
|
||||||
android:foreground="?android:windowContentOverlay"
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="?attr/overlay_drawable"
|
||||||
android:orientation="vertical">
|
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
|
<RelativeLayout
|
||||||
android:id="@+id/player_control"
|
android:id="@+id/player_control"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/audioplayer_playercontrols_length"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentBottom="true"
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
android:background="?attr/overlay_background"
|
android:background="?attr/overlay_background"
|
||||||
tools:background="@android:color/holo_purple">
|
tools:background="@android:color/holo_purple">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/butPlay"
|
android:id="@+id/butPlay"
|
||||||
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
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:layout_centerHorizontal="true"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:contentDescription="@string/pause_label"
|
android:contentDescription="@string/pause_label"
|
||||||
android:src="?attr/av_pause"
|
android:src="?attr/av_pause"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
tools:src="@drawable/ic_pause_white_36dp"
|
tools:src="@drawable/ic_pause_white_36dp"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/butRev"
|
android:id="@+id/butRev"
|
||||||
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
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_toLeftOf="@id/butPlay"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:contentDescription="@string/rewind_label"
|
android:contentDescription="@string/rewind_label"
|
||||||
android:src="?attr/av_rew_big"
|
android:src="?attr/av_rew_big"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
tools:src="@drawable/ic_fast_rewind_white_36dp"
|
tools:src="@drawable/ic_fast_rewind_white_36dp"
|
||||||
tools:background="@android:color/holo_blue_dark" />
|
tools:background="@android:color/holo_blue_dark" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/txtvRev"
|
android:id="@+id/txtvRev"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="32dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignTop="@id/butRev"
|
android:layout_below="@id/butRev"
|
||||||
android:layout_alignLeft="@id/butRev"
|
android:layout_alignLeft="@id/butRev"
|
||||||
android:layout_alignRight="@id/butRev"
|
android:layout_alignRight="@id/butRev"
|
||||||
|
android:layout_marginTop="-8dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="30"
|
android:text="30"
|
||||||
android:textSize="8dp"
|
android:textSize="10sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:clickable="false"/>
|
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
|
<ImageButton
|
||||||
android:id="@+id/butFF"
|
android:id="@+id/butFF"
|
||||||
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
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_toRightOf="@id/butPlay"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:contentDescription="@string/fast_forward_label"
|
android:contentDescription="@string/fast_forward_label"
|
||||||
android:src="?attr/av_ff_big"
|
android:src="?attr/av_ff_big"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
tools:src="@drawable/ic_fast_forward_white_36dp"
|
tools:src="@drawable/ic_fast_forward_white_36dp"
|
||||||
tools:background="@android:color/holo_blue_dark" />
|
tools:background="@android:color/holo_blue_dark" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/txtvFF"
|
android:id="@+id/txtvFF"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="32dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignTop="@id/butFF"
|
android:layout_below="@id/butFF"
|
||||||
android:layout_alignLeft="@id/butFF"
|
android:layout_alignLeft="@id/butFF"
|
||||||
android:layout_alignRight="@id/butFF"
|
android:layout_alignRight="@id/butFF"
|
||||||
|
android:layout_marginTop="-8dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="30"
|
android:text="30"
|
||||||
android:textSize="8dp"
|
android:textSize="10sp"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:clickable="false"/>
|
android:clickable="false"/>
|
||||||
|
|
||||||
<Button
|
<ImageButton
|
||||||
android:id="@+id/butPlaybackSpeed"
|
android:id="@+id/butSkip"
|
||||||
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="@dimen/audioplayer_playercontrols_length"
|
||||||
android:layout_toRightOf="@id/butFF"
|
android:layout_toRightOf="@id/butFF"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:contentDescription="@string/set_playback_speed_label"
|
android:scaleType="fitCenter"
|
||||||
android:src="?attr/av_fast_forward"
|
android:src="?attr/av_skip_big"
|
||||||
android:textSize="@dimen/text_size_medium"
|
android:contentDescription="@string/skip_episode_label"
|
||||||
android:visibility="gone"
|
tools:src="@drawable/ic_skip_white_36dp"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/butNavChaptersShownotes"
|
|
||||||
android:layout_width="@dimen/audioplayer_playercontrols_length"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_toLeftOf="@id/butRev"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:src="@drawable/ic_toc_white_36dp"
|
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
</LinearLayout>
|
||||||
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.support.v4.view.ViewPager
|
||||||
android:id="@+id/txtvPosition"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/pager"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_height="0dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_above="@id/playtime_layout"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_below="@id/appBar"
|
||||||
android:layout_marginTop="16dp"
|
android:foreground="?android:windowContentOverlay"
|
||||||
android:text="@string/position_default_label"
|
tools:background="@android:color/holo_orange_light" />
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:textSize="@dimen/text_size_micro"
|
|
||||||
tools:background="@android:color/holo_green_dark" />
|
|
||||||
|
|
||||||
<TextView
|
<View
|
||||||
android:id="@+id/txtvLength"
|
android:id="@+id/shadow"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="4dp"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_below="@id/appBar"
|
||||||
android:layout_alignParentTop="true"
|
android:background="@drawable/shadow" />
|
||||||
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
|
</RelativeLayout>
|
||||||
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"
|
|
||||||
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" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<include layout="@layout/nav_list" />
|
<include layout="@layout/nav_list" />
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
|
@ -1,19 +1,66 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/cover_fragment_root"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical" >
|
android:background="@color/actionbar_gray">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imgvCover"
|
android:id="@+id/imgvCover"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
android:contentDescription="@string/cover_label"
|
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"
|
android:scaleType="fitCenter"
|
||||||
|
app:layout_aspectRatio="100%"
|
||||||
|
app:layout_widthPercent="82%"
|
||||||
tools:src="@android:drawable/sym_def_app_icon" />
|
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>
|
||||||
|
|
|
@ -2,23 +2,36 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
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
|
<item
|
||||||
android:id="@+id/disable_sleeptimer_item"
|
android:id="@+id/disable_sleeptimer_item"
|
||||||
android:icon="?attr/device_access_time"
|
android:icon="?attr/ic_sleep_off"
|
||||||
custom:showAsAction="always"
|
custom:showAsAction="always"
|
||||||
android:title="@string/sleep_timer_label">
|
android:title="@string/sleep_timer_label">
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/set_sleeptimer_item"
|
android:id="@+id/set_sleeptimer_item"
|
||||||
custom:showAsAction="collapseActionView"
|
android:icon="?attr/ic_sleep"
|
||||||
|
custom:showAsAction="always"
|
||||||
android:title="@string/set_sleeptimer_label">
|
android:title="@string/set_sleeptimer_label">
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/skip_episode_item"
|
android:id="@+id/audio_controls"
|
||||||
custom:showAsAction="collapseActionView"
|
android:title="@string/audio_controls"
|
||||||
android:title="@string/skip_episode_label"
|
custom:showAsAction="always">
|
||||||
android:visible="true">
|
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
|
@ -30,7 +43,9 @@
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/share_item"
|
android:id="@+id/share_item"
|
||||||
|
android:icon="?attr/social_share"
|
||||||
android:menuCategory="container"
|
android:menuCategory="container"
|
||||||
|
custom:showAsAction="ifRoom"
|
||||||
android:title="@string/share_label">
|
android:title="@string/share_label">
|
||||||
<menu>
|
<menu>
|
||||||
<item
|
<item
|
||||||
|
|
|
@ -59,13 +59,13 @@
|
||||||
<h1>Used libraries</h1>
|
<h1>Used libraries</h1>
|
||||||
|
|
||||||
<h2>Apache Commons <a href="http://commons.apache.org/">(Link)</a></h2>
|
<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>
|
<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>
|
<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>
|
<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>
|
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>
|
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>
|
<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>
|
<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>
|
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>
|
<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>
|
<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>
|
<h2>StackBlur <a href="https://github.com/kikoso/android-stackblur">(Link)</a></h2>
|
||||||
by Enrique López Mañas, licensed under the Apache 2.0 license <a href="LICENSE_STACKBLUR.txt">(View)</a>
|
by Enrique López Mañ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>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -50,14 +50,14 @@ project.ext {
|
||||||
jsoupVersion = "1.7.3"
|
jsoupVersion = "1.7.3"
|
||||||
iconifyFontawesomeVersion = "2.1.1"
|
iconifyFontawesomeVersion = "2.1.1"
|
||||||
materialDialogsVersion = "0.8.5.3@aar"
|
materialDialogsVersion = "0.8.5.3@aar"
|
||||||
|
okhttpVersion = "2.7.2"
|
||||||
|
okioVersion = "1.6.0"
|
||||||
recyclerviewFlexibledividerVersion = "1.2.6"
|
recyclerviewFlexibledividerVersion = "1.2.6"
|
||||||
rxAndroidVersion = "1.1.0"
|
rxAndroidVersion = "1.1.0"
|
||||||
rxJavaVersion = "1.1.0"
|
rxJavaVersion = "1.1.0"
|
||||||
rxJavaRulesVersion = "1.1.0.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) {
|
task wrapper(type: Wrapper) {
|
||||||
|
|
|
@ -40,7 +40,6 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "com.android.support:support-v4:$supportVersion"
|
compile "com.android.support:support-v4:$supportVersion"
|
||||||
compile "com.android.support:appcompat-v7:$supportVersion"
|
compile "com.android.support:appcompat-v7:$supportVersion"
|
||||||
compile "com.android.support:design:$supportVersion"
|
|
||||||
compile "org.apache.commons:commons-lang3:$commonslangVersion"
|
compile "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||||
compile ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
compile ("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
|
||||||
exclude group: "org.json", module: "json"
|
exclude group: "org.json", module: "json"
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -95,9 +94,12 @@ public class UserPreferences {
|
||||||
public static final String PREF_QUEUE_LOCKED = "prefQueueLocked";
|
public static final String PREF_QUEUE_LOCKED = "prefQueueLocked";
|
||||||
public static final String IMAGE_CACHE_DEFAULT_VALUE = "100";
|
public static final String IMAGE_CACHE_DEFAULT_VALUE = "100";
|
||||||
public static final int IMAGE_CACHE_SIZE_MINIMUM = 20;
|
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
|
// Experimental
|
||||||
public static final String PREF_SONIC = "prefSonic";
|
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 String PREF_NORMALIZER = "prefNormalizer";
|
||||||
public static final int EPISODE_CLEANUP_QUEUE = -1;
|
public static final int EPISODE_CLEANUP_QUEUE = -1;
|
||||||
public static final int EPISODE_CLEANUP_NULL = -2;
|
public static final int EPISODE_CLEANUP_NULL = -2;
|
||||||
|
@ -249,17 +251,37 @@ public class UserPreferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getPlaybackSpeed() {
|
public static String getPlaybackSpeed() {
|
||||||
return prefs.getString(PREF_PLAYBACK_SPEED, "1.0");
|
return prefs.getString(PREF_PLAYBACK_SPEED, "1.00");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] getPlaybackSpeedArray() {
|
public static String[] getPlaybackSpeedArray() {
|
||||||
return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null));
|
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() {
|
public static boolean shouldPauseForFocusLoss() {
|
||||||
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
|
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static long getUpdateInterval() {
|
public static long getUpdateInterval() {
|
||||||
String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0");
|
String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0");
|
||||||
if(false == updateInterval.contains(":")) {
|
if(false == updateInterval.contains(":")) {
|
||||||
|
@ -385,6 +407,15 @@ public class UserPreferences {
|
||||||
.apply();
|
.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) {
|
public static void setAutodownloadSelectedNetworks(String[] value) {
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
|
.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 this preference hasn't been set yet, return the default options
|
||||||
if (valueFromPrefs == null) {
|
if (valueFromPrefs == null) {
|
||||||
String[] allSpeeds = context.getResources().getStringArray(R.array.playback_speed_values);
|
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) {
|
for (String speedStr : allSpeeds) {
|
||||||
float speed = Float.parseFloat(speedStr);
|
float speed = Float.parseFloat(speedStr);
|
||||||
if (speed < 2.0001 && speed * 10 % 1 == 0) {
|
if (speed < 2.0001 && speed * 10 % 1 == 0) {
|
||||||
|
@ -505,6 +536,16 @@ public class UserPreferences {
|
||||||
.apply();
|
.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() {
|
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
|
||||||
int cleanupValue = Integer.valueOf(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
|
int cleanupValue = Integer.valueOf(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
|
||||||
|
|
|
@ -398,19 +398,25 @@ public class PlaybackService extends Service {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSleepTimerAlmostExpired() {
|
public void onSleepTimerAlmostExpired() {
|
||||||
mediaPlayer.setVolume(0.1f);
|
float leftVolume = 0.1f * UserPreferences.getLeftVolume();
|
||||||
|
float rightVolume = 0.1f * UserPreferences.getRightVolume();
|
||||||
|
mediaPlayer.setVolume(leftVolume, rightVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSleepTimerExpired() {
|
public void onSleepTimerExpired() {
|
||||||
mediaPlayer.pause(true, true);
|
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);
|
sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSleepTimerReset() {
|
public void onSleepTimerReset() {
|
||||||
mediaPlayer.setVolume(1.0f);
|
float leftVolume = UserPreferences.getLeftVolume();
|
||||||
|
float rightVolume = UserPreferences.getRightVolume();
|
||||||
|
mediaPlayer.setVolume(leftVolume, rightVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1165,18 +1171,30 @@ public class PlaybackService extends Service {
|
||||||
|
|
||||||
public Playable getPlayable() { return mediaPlayer.getPlayable(); }
|
public Playable getPlayable() { return mediaPlayer.getPlayable(); }
|
||||||
|
|
||||||
public void setSpeed(float speed) {
|
|
||||||
mediaPlayer.setSpeed(speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canSetSpeed() {
|
public boolean canSetSpeed() {
|
||||||
return mediaPlayer.canSetSpeed();
|
return mediaPlayer.canSetSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSpeed(float speed) {
|
||||||
|
mediaPlayer.setSpeed(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolume(float leftVolume, float rightVolume) {
|
||||||
|
mediaPlayer.setVolume(leftVolume, rightVolume);
|
||||||
|
}
|
||||||
|
|
||||||
public float getCurrentPlaybackSpeed() {
|
public float getCurrentPlaybackSpeed() {
|
||||||
return mediaPlayer.getPlaybackSpeed();
|
return mediaPlayer.getPlaybackSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canDownmix() {
|
||||||
|
return mediaPlayer.canDownmix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDownmix(boolean enable) {
|
||||||
|
mediaPlayer.setDownmix(enable);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStartWhenPrepared() {
|
public boolean isStartWhenPrepared() {
|
||||||
return mediaPlayer.isStartWhenPrepared();
|
return mediaPlayer.isStartWhenPrepared();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.view.SurfaceHolder;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.request.target.Target;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
@ -293,6 +294,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
||||||
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
|
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
|
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
|
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
|
||||||
|
|
||||||
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
|
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
|
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
|
||||||
try {
|
try {
|
||||||
|
@ -322,13 +324,10 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
||||||
* This method is executed on an internal executor service.
|
* This method is executed on an internal executor service.
|
||||||
*/
|
*/
|
||||||
public void resume() {
|
public void resume() {
|
||||||
executor.submit(new Runnable() {
|
executor.submit(() -> {
|
||||||
@Override
|
playerLock.lock();
|
||||||
public void run() {
|
resumeSync();
|
||||||
playerLock.lock();
|
playerLock.unlock();
|
||||||
resumeSync();
|
|
||||||
playerLock.unlock();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +338,15 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
||||||
AudioManager.AUDIOFOCUS_GAIN);
|
AudioManager.AUDIOFOCUS_GAIN);
|
||||||
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
acquireWifiLockIfNecessary();
|
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) {
|
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
|
||||||
int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
|
int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
|
||||||
|
@ -690,24 +697,39 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
||||||
* Sets the playback speed.
|
* Sets the playback speed.
|
||||||
* This method is executed on an internal executor service.
|
* This method is executed on an internal executor service.
|
||||||
*/
|
*/
|
||||||
public void setVolume(final float volume) {
|
public void setVolume(final float volumeLeft, float volumeRight) {
|
||||||
executor.submit(new Runnable() {
|
executor.submit(() -> setVolumeSync(volumeLeft, volumeRight));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
setVolumeSync(volume);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the playback speed.
|
* Sets the playback speed.
|
||||||
* This method is executed on the caller's thread.
|
* This method is executed on the caller's thread.
|
||||||
*/
|
*/
|
||||||
private void setVolumeSync(float volume) {
|
private void setVolumeSync(float volumeLeft, float volumeRight) {
|
||||||
playerLock.lock();
|
playerLock.lock();
|
||||||
if (media != null && media.getMediaType() == MediaType.AUDIO) {
|
if (media != null && media.getMediaType() == MediaType.AUDIO) {
|
||||||
mediaPlayer.setVolume(volume, volume);
|
mediaPlayer.setVolume(volumeLeft, volumeRight);
|
||||||
Log.d(TAG, "Media player volume was set to " + volume);
|
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.setDownmix(enable);
|
||||||
|
Log.d(TAG, "Media player downmix was set to " + enable);
|
||||||
}
|
}
|
||||||
playerLock.unlock();
|
playerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,4 +37,9 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
|
||||||
protected boolean useSonic() {
|
protected boolean useSonic() {
|
||||||
return UserPreferences.useSonic();
|
return UserPreferences.useSonic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean downmix() {
|
||||||
|
return UserPreferences.stereoToMono();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ public interface IPlayer {
|
||||||
|
|
||||||
boolean canSetSpeed();
|
boolean canSetSpeed();
|
||||||
|
|
||||||
|
boolean canDownmix();
|
||||||
|
|
||||||
float getCurrentPitchStepsAdjustment();
|
float getCurrentPitchStepsAdjustment();
|
||||||
|
|
||||||
int getCurrentPosition();
|
int getCurrentPosition();
|
||||||
|
@ -57,6 +59,8 @@ public interface IPlayer {
|
||||||
|
|
||||||
void setPlaybackSpeed(float f);
|
void setPlaybackSpeed(float f);
|
||||||
|
|
||||||
|
void setDownmix(boolean enable);
|
||||||
|
|
||||||
void setVolume(float left, float right);
|
void setVolume(float left, float right);
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
|
@ -27,7 +27,6 @@ import android.widget.TextView;
|
||||||
import java.util.concurrent.RejectedExecutionHandler;
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.
|
* control playback instead of communicating with the PlaybackService directly.
|
||||||
*/
|
*/
|
||||||
public abstract class PlaybackController {
|
public abstract class PlaybackController {
|
||||||
|
|
||||||
private static final String TAG = "PlaybackController";
|
private static final String TAG = "PlaybackController";
|
||||||
|
|
||||||
public static final int INVALID_TIME = -1;
|
public static final int INVALID_TIME = -1;
|
||||||
|
@ -78,23 +78,18 @@ public abstract class PlaybackController {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
this.reinitOnPause = reinitOnPause;
|
this.reinitOnPause = reinitOnPause;
|
||||||
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE,
|
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOLSIZE,
|
||||||
new ThreadFactory() {
|
r -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
@Override
|
t.setPriority(Thread.MIN_PRIORITY);
|
||||||
public Thread newThread(Runnable r) {
|
return t;
|
||||||
Thread t = new Thread(r);
|
}, new RejectedExecutionHandler() {
|
||||||
t.setPriority(Thread.MIN_PRIORITY);
|
@Override
|
||||||
return t;
|
public void rejectedExecution(Runnable r,
|
||||||
}
|
ThreadPoolExecutor executor) {
|
||||||
}, new RejectedExecutionHandler() {
|
Log.w(TAG,
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rejectedExecution(Runnable r,
|
|
||||||
ThreadPoolExecutor executor) {
|
|
||||||
Log.w(TAG,
|
|
||||||
"Rejected execution of runnable in schedExecutor");
|
"Rejected execution of runnable in schedExecutor");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,10 +99,10 @@ public abstract class PlaybackController {
|
||||||
*/
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
activity.registerReceiver(statusUpdate, new IntentFilter(
|
activity.registerReceiver(statusUpdate, new IntentFilter(
|
||||||
PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
PlaybackService.ACTION_PLAYER_STATUS_CHANGED));
|
||||||
|
|
||||||
activity.registerReceiver(notificationReceiver, new IntentFilter(
|
activity.registerReceiver(notificationReceiver, new IntentFilter(
|
||||||
PlaybackService.ACTION_PLAYER_NOTIFICATION));
|
PlaybackService.ACTION_PLAYER_NOTIFICATION));
|
||||||
|
|
||||||
activity.registerReceiver(shutdownReceiver, new IntentFilter(
|
activity.registerReceiver(shutdownReceiver, new IntentFilter(
|
||||||
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||||
|
@ -239,7 +234,7 @@ public abstract class PlaybackController {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void setupGUI();
|
|
||||||
|
|
||||||
private void setupPositionObserver() {
|
private void setupPositionObserver() {
|
||||||
if ((positionObserverFuture != null && positionObserverFuture
|
if ((positionObserverFuture != null && positionObserverFuture
|
||||||
|
@ -263,8 +258,6 @@ public abstract class PlaybackController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void onPositionObserverUpdate();
|
|
||||||
|
|
||||||
private ServiceConnection mConnection = new ServiceConnection() {
|
private ServiceConnection mConnection = new ServiceConnection() {
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
playbackService = ((PlaybackService.LocalBinder) service)
|
playbackService = ((PlaybackService.LocalBinder) service)
|
||||||
|
@ -367,26 +360,31 @@ public abstract class PlaybackController {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public abstract void onPlaybackSpeedChange();
|
public void setupGUI() {};
|
||||||
|
|
||||||
public abstract void onShutdownNotification();
|
public void onPositionObserverUpdate() {};
|
||||||
|
|
||||||
|
|
||||||
|
public void onPlaybackSpeedChange() {};
|
||||||
|
|
||||||
|
public void onShutdownNotification() {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the currently displayed information should be refreshed.
|
* 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() {
|
public void repeatHandleStatus() {
|
||||||
if (status != null && playbackService != null) {
|
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
|
* 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.
|
* 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() {
|
public float getCurrentPlaybackSpeedMultiplier() {
|
||||||
if (canSetPlaybackSpeed()) {
|
if (canSetPlaybackSpeed()) {
|
||||||
return playbackService.getCurrentPlaybackSpeed();
|
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() {
|
public boolean isPlayingVideo() {
|
||||||
if (playbackService != null) {
|
if (playbackService != null) {
|
||||||
return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
|
return PlaybackService.getCurrentMediaType() == MediaType.VIDEO;
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class Timeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace ASCII line breaks with HTML ones if shownotes don't contain HTML line breaks already
|
// 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 />");
|
shownotes = shownotes.replace("\n", "<br />");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDownmix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getCurrentPitchStepsAdjustment() {
|
public float getCurrentPitchStepsAdjustment() {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -60,6 +65,12 @@ public class VideoPlayer extends MediaPlayer implements IPlayer {
|
||||||
throw new UnsupportedOperationException("Setting playback speed unsupported in video player");
|
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
|
@Override
|
||||||
public void setVideoScalingMode(int mode) {
|
public void setVideoScalingMode(int mode) {
|
||||||
super.setVideoScalingMode(mode);
|
super.setVideoScalingMode(mode);
|
||||||
|
|
After Width: | Height: | Size: 302 B |
After Width: | Height: | Size: 304 B |
After Width: | Height: | Size: 421 B |
After Width: | Height: | Size: 659 B |
After Width: | Height: | Size: 431 B |
After Width: | Height: | Size: 361 B |
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 460 B |
After Width: | Height: | Size: 454 B |
After Width: | Height: | Size: 218 B |
After Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 336 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 307 B |
After Width: | Height: | Size: 302 B |
After Width: | Height: | Size: 364 B |
After Width: | Height: | Size: 368 B |
After Width: | Height: | Size: 494 B |
After Width: | Height: | Size: 769 B |
After Width: | Height: | Size: 486 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 828 B |
After Width: | Height: | Size: 821 B |
After Width: | Height: | Size: 593 B |
After Width: | Height: | Size: 582 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 543 B |
After Width: | Height: | Size: 737 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 664 B |
After Width: | Height: | Size: 509 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 877 B |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 737 B |
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 955 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 882 B |
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
|
@ -75,15 +75,15 @@
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="playback_speed_values">
|
<string-array name="playback_speed_values">
|
||||||
<item>0.5</item>
|
<item>0.50</item>
|
||||||
<item>0.6</item>
|
<item>0.60</item>
|
||||||
<item>0.7</item>
|
<item>0.70</item>
|
||||||
<item>0.75</item>
|
<item>0.75</item>
|
||||||
<item>0.8</item>
|
<item>0.80</item>
|
||||||
<item>0.85</item>
|
<item>0.85</item>
|
||||||
<item>0.9</item>
|
<item>0.90</item>
|
||||||
<item>0.95</item>
|
<item>0.95</item>
|
||||||
<item>1.0</item>
|
<item>1.00</item>
|
||||||
<item>1.05</item>
|
<item>1.05</item>
|
||||||
<item>1.10</item>
|
<item>1.10</item>
|
||||||
<item>1.15</item>
|
<item>1.15</item>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
<attr name="content_discard" format="reference"/>
|
<attr name="content_discard" format="reference"/>
|
||||||
<attr name="content_new" format="reference"/>
|
<attr name="content_new" format="reference"/>
|
||||||
<attr name="feed" format="reference"/>
|
<attr name="feed" format="reference"/>
|
||||||
<attr name="device_access_time" format="reference"/>
|
|
||||||
<attr name="location_web_site" format="reference"/>
|
<attr name="location_web_site" format="reference"/>
|
||||||
<attr name="navigation_accept" format="reference"/>
|
<attr name="navigation_accept" format="reference"/>
|
||||||
<attr name="navigation_cancel" format="reference"/>
|
<attr name="navigation_cancel" format="reference"/>
|
||||||
|
@ -37,11 +36,16 @@
|
||||||
<attr name="av_pause_big" format="reference"/>
|
<attr name="av_pause_big" format="reference"/>
|
||||||
<attr name="av_ff_big" format="reference"/>
|
<attr name="av_ff_big" format="reference"/>
|
||||||
<attr name="av_rew_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_settings" format="reference"/>
|
||||||
<attr name="ic_lock_open" format="reference"/>
|
<attr name="ic_lock_open" format="reference"/>
|
||||||
<attr name="ic_lock_closed" format="reference"/>
|
<attr name="ic_lock_closed" format="reference"/>
|
||||||
<attr name="ic_filter" format="reference"/>
|
<attr name="ic_filter" format="reference"/>
|
||||||
<attr name="progressBarTheme" 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 -->
|
<!-- Used in itemdescription -->
|
||||||
<attr name="non_transparent_background" format="reference"/>
|
<attr name="non_transparent_background" format="reference"/>
|
||||||
|
|
|
@ -33,6 +33,6 @@
|
||||||
<dimen name="listitem_icon_leftpadding">16dp</dimen>
|
<dimen name="listitem_icon_leftpadding">16dp</dimen>
|
||||||
<dimen name="listitem_icon_rightpadding">16dp</dimen>
|
<dimen name="listitem_icon_rightpadding">16dp</dimen>
|
||||||
|
|
||||||
<dimen name="audioplayer_playercontrols_length">64dp</dimen>
|
<dimen name="audioplayer_playercontrols_length">48dp</dimen>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -148,7 +148,9 @@
|
||||||
<string name="added_to_queue_label">Added to Queue</string>
|
<string name="added_to_queue_label">Added to Queue</string>
|
||||||
<string name="remove_from_queue_label">Remove from Queue</string>
|
<string name="remove_from_queue_label">Remove from Queue</string>
|
||||||
<string name="add_to_favorite_label">Add to Favorites</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="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="visit_website_label">Visit Website</string>
|
||||||
<string name="support_label">Flattr this</string>
|
<string name="support_label">Flattr this</string>
|
||||||
<string name="enqueue_all_new">Enqueue all</string>
|
<string name="enqueue_all_new">Enqueue all</string>
|
||||||
|
@ -268,6 +270,7 @@
|
||||||
<!-- Empty list labels -->
|
<!-- Empty list labels -->
|
||||||
<string name="no_items_label">There are no items in this list.</string>
|
<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_feeds_label">You haven\'t subscribed to any feeds yet.</string>
|
||||||
|
<string name="no_chapters_label">This episode has no chapters.</string>
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="other_pref">Other</string>
|
<string name="other_pref">Other</string>
|
||||||
|
@ -555,4 +558,14 @@
|
||||||
<string name="rating_later_label">Remind me later</string>
|
<string name="rating_later_label">Remind me later</string>
|
||||||
<string name="rating_now_label">Sure, let\'s do this!</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>
|
</resources>
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
<item name="attr/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
|
<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_discard">@drawable/ic_delete_grey600_24dp</item>
|
||||||
<item name="attr/content_new">@drawable/ic_add_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/feed">@drawable/ic_feed_grey600_24dp</item>
|
||||||
<item name="attr/location_web_site">@drawable/ic_web_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>
|
<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_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_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_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_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_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_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
|
||||||
<item name="attr/ic_filter">@drawable/ic_filter_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>
|
||||||
|
|
||||||
<style name="Theme.AntennaPod.Dark" parent="Theme.AppCompat">
|
<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/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
|
||||||
<item name="attr/content_discard">@drawable/ic_delete_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/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/feed">@drawable/ic_feed_white_24dp</item>
|
||||||
<item name="attr/location_web_site">@drawable/ic_web_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>
|
<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_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_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_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_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_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_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
|
||||||
<item name="attr/ic_filter">@drawable/ic_filter_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>
|
||||||
|
|
||||||
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.AppCompat.Light.NoActionBar">
|
<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/av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item>
|
||||||
<item name="attr/content_discard">@drawable/ic_delete_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/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/feed">@drawable/ic_feed_grey600_24dp</item>
|
||||||
<item name="attr/location_web_site">@drawable/ic_web_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>
|
<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_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_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_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_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_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_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
|
||||||
<item name="attr/ic_filter">@drawable/ic_filter_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>
|
||||||
|
|
||||||
<style name="Theme.AntennaPod.Dark.NoTitle" parent="Theme.AppCompat.NoActionBar">
|
<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/av_rewind">@drawable/ic_fast_rewind_white_24dp</item>
|
||||||
<item name="attr/content_discard">@drawable/ic_delete_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/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/feed">@drawable/ic_feed_white_24dp</item>
|
||||||
<item name="attr/location_web_site">@drawable/ic_web_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>
|
<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_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_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_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_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_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_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
|
||||||
<item name="attr/ic_filter">@drawable/ic_filter_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>
|
||||||
|
|
||||||
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">
|
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">
|
||||||
|
|