- Run Checkstyle with gradle to make it easier for users
  - No longer needs different configuration for new code
  - Exclude current violations
  - Fix some violations that somehow couldn't be specified in the exclusion file
- Print SpotBugs/Lint/Checkstly violations in GitHub format
  - Then the CI run gets annotated on the web UI
This commit is contained in:
ByteHamster 2024-04-07 23:28:14 +02:00 committed by GitHub
parent fc40da28a7
commit e578f4ca93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 503 additions and 627 deletions

View File

@ -9,6 +9,7 @@
--> -->
- [ ] I have read the contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request - [ ] I have read the contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request
- [ ] I have performed a self-review of my code - [ ] I have performed a self-review of my code
- [ ] I have run the automated code checks using `./gradlew checkstyle spotbugsPlayDebug spotbugsDebug :app:lintPlayDebug`
- [ ] My code follows the style guidelines of the AntennaPod project: https://github.com/AntennaPod/AntennaPod/wiki/Code-style - [ ] My code follows the style guidelines of the AntennaPod project: https://github.com/AntennaPod/AntennaPod/wiki/Code-style
- [ ] I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) - [ ] I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
- [ ] If it is a core feature, I have added automated tests - [ ] If it is a core feature, I have added automated tests

View File

@ -7,36 +7,8 @@ on:
branches: [ master, develop ] branches: [ master, develop ]
jobs: jobs:
code-style:
name: "Code Style"
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkstyle
run: |
curl -s -L https://github.com/checkstyle/checkstyle/releases/download/checkstyle-10.3.1/checkstyle-10.3.1-all.jar > checkstyle.jar
find . -name "*\.java" | xargs java -Dconfig_loc=config/checkstyle -jar checkstyle.jar -c config/checkstyle/checkstyle.xml
- name: Find PR Base Commit
id: vars
run: |
git fetch origin develop
echo "branchBaseCommit=$(git merge-base origin/develop HEAD)" >> $GITHUB_OUTPUT
- name: Diff-Checkstyle
run: |
curl -s -L https://github.com/yangziwen/diff-check/releases/download/0.0.7/diff-checkstyle.jar > diff-checkstyle.jar
java -Dconfig_loc=config/checkstyle -jar diff-checkstyle.jar -c config/checkstyle/checkstyle-new-code.xml --git-dir . --base-rev ${{ steps.vars.outputs.branchBaseCommit }}
- name: XML of changed files
run: |
curl -s -L https://github.com/ByteHamster/android-xml-formatter/releases/download/1.1.0/android-xml-formatter.jar > android-xml-formatter.jar
git diff --name-only ${{ steps.vars.outputs.branchBaseCommit }} --diff-filter=AM | { grep "res/layout/" || true; } | xargs java -jar android-xml-formatter.jar
test $(git diff | wc -l) -eq 0 || (echo -e "\n\n===== Found XML code style violations! See output below how to fix them. =====\n\n" && git --no-pager diff --color=always && false)
wrapper-validation: wrapper-validation:
name: "Gradle Wrapper Validation" name: "Gradle Wrapper Validation"
needs: code-style
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45 timeout-minutes: 45
steps: steps:
@ -45,11 +17,12 @@ jobs:
static-analysis: static-analysis:
name: "Static Code Analysis" name: "Static Code Analysis"
needs: code-style
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45 timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -62,14 +35,24 @@ jobs:
~/.gradle/caches ~/.gradle/caches
~/.gradle/wrapper ~/.gradle/wrapper
key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
- name: Lint :app module recursively - name: Configure parallel build
run: ./gradlew :app:lintPlayRelease run: echo "org.gradle.parallel=true" >> local.properties
- name: SpotBugs - name: XML code style
run: ./gradlew spotbugsPlayDebug spotbugsDebug run: |
curl -s -L https://github.com/ByteHamster/android-xml-formatter/releases/download/1.1.0/android-xml-formatter.jar > android-xml-formatter.jar
find . -wholename "*/res/layout/*.xml" | xargs java -jar android-xml-formatter.jar
test $(git diff | wc -l) -eq 0 || (echo -e "\n\n===== Found XML code style violations! See output below how to fix them. =====\n\n" && git --no-pager diff --color=always && false)
- name: Checkstyle, Lint, SpotBugs
run: ./gradlew checkstyle :app:lintPlayDebug spotbugsPlayDebug spotbugsDebug
- name: Generate readable error messages for GitHub
if: failure()
run: |
git diff --name-only | xargs -I '{}' echo "::error file={},line=1,endLine=1,title=XML Format::Run android-xml-formatter.jar on this file or view CI output to see how it should be formatted."
python .github/workflows/errorPrinter.py
unit-test: unit-test:
name: "Unit Test: ${{ matrix.variant }}" name: "Unit Test: ${{ matrix.variant }}"
needs: code-style needs: static-analysis
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45 timeout-minutes: 45
strategy: strategy:
@ -101,6 +84,8 @@ jobs:
~/.gradle/caches ~/.gradle/caches
~/.gradle/wrapper ~/.gradle/wrapper
key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
- name: Configure parallel build
run: echo "org.gradle.parallel=true" >> local.properties
- name: Create temporary release keystore - name: Create temporary release keystore
run: keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US" run: keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US"
- name: Build - name: Build
@ -116,7 +101,7 @@ jobs:
emulator-test: emulator-test:
name: "Emulator Test" name: "Emulator Test"
needs: code-style needs: static-analysis
runs-on: macOS-latest runs-on: macOS-latest
timeout-minutes: 45 timeout-minutes: 45
env: env:
@ -135,6 +120,8 @@ jobs:
~/.gradle/caches ~/.gradle/caches
~/.gradle/wrapper ~/.gradle/wrapper
key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} key: gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
- name: Configure parallel build
run: echo "org.gradle.parallel=true" >> local.properties
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew assemblePlayDebugAndroidTest run: ./gradlew assemblePlayDebugAndroidTest
- name: Android Emulator test - name: Android Emulator test

48
.github/workflows/errorPrinter.py vendored Normal file
View File

@ -0,0 +1,48 @@
#!/bin/python
from xml.dom import minidom
import os.path
import glob
from pathlib import Path
if os.path.isfile('app/build/reports/lint-results-playDebug.xml'):
dom = minidom.parse('app/build/reports/lint-results-playDebug.xml')
issues = dom.getElementsByTagName('issue')
for issue in issues:
locations = issue.getElementsByTagName('location')
for location in locations:
print(location.attributes['file'].value + ":" + location.attributes['line'].value + " " + issue.attributes['summary'].value)
print("::error file=" + location.attributes['file'].value
+ ",line=" + location.attributes['line'].value
+ ",endLine=" + location.attributes['line'].value
+ ",title=Lint::" + issue.attributes['summary'].value + ". " + issue.attributes['explanation'].value.replace('\n', ' '))
print()
if os.path.isfile('build/reports/checkstyle/checkstyle.xml'):
dom = minidom.parse('build/reports/checkstyle/checkstyle.xml')
files = dom.getElementsByTagName('file')
for f in files:
errors = f.getElementsByTagName('error')
for error in errors:
print(f.attributes['name'].value + ":" + error.attributes['line'].value + " " + error.attributes['message'].value)
print("::error file=" + f.attributes['name'].value
+ ",line=" + error.attributes['line'].value
+ ",endLine=" + error.attributes['line'].value
+ ",title=Checkstyle::" + error.attributes['message'].value)
print()
for filename in glob.iglob('**/build/reports/spotbugs/*.xml', recursive=True):
filenamePath = Path(filename)
dom = minidom.parse(filename)
instance = dom.getElementsByTagName('BugInstance')
for inst in instance:
lines = inst.getElementsByTagName('SourceLine')
longMessage = inst.getElementsByTagName('LongMessage')[0].firstChild.nodeValue
for line in lines:
if "primary" in line.attributes:
print(line.attributes['sourcepath'].value + ": " + longMessage)
print("::error file=" + str(filenamePath.parent.parent.parent.parent.absolute()) + "/src/main/java/" + line.attributes['sourcepath'].value
+ ",line=" + line.attributes['start'].value
+ ",endLine=" + line.attributes['end'].value
+ ",title=SpotBugs::" + longMessage.replace('\n', ' '))
print()

View File

@ -41,7 +41,8 @@ Submit a pull request
- Get coding :) - Get coding :)
- If possible, add unit tests for your pull request and make sure that they pass. - If possible, add unit tests for your pull request and make sure that they pass.
- Please do not upgrade dependencies or build tools unless you have a good reason for it. Doing so can easily introduce bugs that are hard to track down. - Please do not upgrade dependencies or build tools unless you have a good reason for it. Doing so can easily introduce bugs that are hard to track down.
- Please follow our code style. You can use Checkstyle within Android Studio using our [configuration file](https://github.com/AntennaPod/AntennaPod/blob/develop/config/checkstyle/checkstyle-new-code.xml). - Please follow our code style. You can use Checkstyle within Android Studio using our [configuration file](https://github.com/AntennaPod/AntennaPod/blob/develop/config/checkstyle/checkstyle.xml).
- To check the code style locally, run `./gradlew checkstyle spotbugsPlayDebug spotbugsDebug :app:lintPlayDebug`
- Please only change the English string resources. Translations are handled on [Transifex](https://www.transifex.com/antennapod/antennapod/). - Please only change the English string resources. Translations are handled on [Transifex](https://www.transifex.com/antennapod/antennapod/).
- Open the PR - Open the PR
- Mention the corresponding issue in the pull request text, so that it can be closed once your pull request has been merged. If you use [special keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue), GitHub will close the issue(s) automatically. - Mention the corresponding issue in the pull request text, so that it can be closed once your pull request has been merged. If you use [special keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue), GitHub will close the issue(s) automatically.

View File

@ -47,13 +47,11 @@ android {
} }
lint { lint {
disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams', disable 'CheckResult', 'MissingMediaBrowserServiceIntentFilter', 'UnusedAttribute', 'InflateParams',
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat', 'RestrictedApi', 'ExportedReceiver', 'NotifyDataSetChanged', 'UseCompoundDrawables', 'NestedWeights',
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields', 'Overdraw', 'UselessParent', 'TextFields', 'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility',
'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility', 'ContentDescription',
'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap', 'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap',
'RtlCompat', 'RtlHardcoded', 'MissingMediaBrowserServiceIntentFilter', 'VectorPath', 'RtlHardcoded', 'RtlEnabled', 'ContentDescription'
'InvalidPeriodicWorkRequestInterval', 'NotifyDataSetChanged', 'RtlEnabled'
} }
androidResources { androidResources {

View File

@ -7,9 +7,7 @@ import java.io.IOException;
/** /**
* Utility methods for FeedGenerator * Utility methods for FeedGenerator
*/ */
class GeneratorUtil { abstract class GeneratorUtil {
private GeneratorUtil(){}
public static void addPaymentLink(XmlSerializer xml, String paymentLink, boolean withNamespace) throws IOException { public static void addPaymentLink(XmlSerializer xml, String paymentLink, boolean withNamespace) throws IOException {
String ns = (withNamespace) ? "http://www.w3.org/2005/Atom" : null; String ns = (withNamespace) ? "http://www.w3.org/2005/Atom" : null;
xml.startTag(ns, "link"); xml.startTag(ns, "link");

View File

@ -173,10 +173,12 @@ public class ProxyDialog {
private final TextWatcher requireTestOnChange = new TextWatcher() { private final TextWatcher requireTestOnChange = new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) {} public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {

View File

@ -13,7 +13,8 @@ import com.google.android.material.bottomsheet.ViewPagerBottomSheetBehavior;
public class LockableBottomSheetBehavior<V extends View> extends ViewPagerBottomSheetBehavior<V> { public class LockableBottomSheetBehavior<V extends View> extends ViewPagerBottomSheetBehavior<V> {
private boolean isLocked = false; private boolean isLocked = false;
public LockableBottomSheetBehavior() {} public LockableBottomSheetBehavior() {
}
public LockableBottomSheetBehavior(Context context, AttributeSet attrs) { public LockableBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);

View File

@ -2,7 +2,7 @@
<CheckedTextView <CheckedTextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1" android:id="@android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingVertical="8dp" /> android:paddingVertical="8dp"
style="?android:attr/spinnerDropDownItemStyle" />

View File

@ -2,8 +2,8 @@
<TextView <TextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1" android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:maxLines="3" android:maxLines="3"
android:textAlignment="inherit" /> android:textAlignment="inherit"
style="?android:attr/spinnerItemStyle" />

View File

@ -1,28 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="match_parent"
android:padding="16dp"> android:orientation="vertical"
<Button android:padding="16dp">
android:id="@+id/btn_open_bug_tracker"
android:text="@string/open_bug_tracker"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button <Button
android:id="@+id/btn_copy_log" android:id="@+id/btn_open_bug_tracker"
android:text="@string/copy_to_clipboard" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content"/> android:text="@string/open_bug_tracker" />
<Button
android:id="@+id/btn_copy_log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/copy_to_clipboard" />
<TextView <TextView
android:layout_marginTop="8dp" android:id="@+id/crash_report_logs"
android:id="@+id/crash_report_logs" android:layout_width="match_parent"
android:textIsSelectable="true" android:layout_height="0dp"
android:textSize="12sp" android:layout_marginTop="8dp"
android:layout_width="match_parent" android:textIsSelectable="true"
android:layout_height="0dp" android:textSize="12sp"
android:layout_weight="1"/> android:layout_weight="1" />
</LinearLayout> </LinearLayout>

View File

@ -1,17 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="wrap_content"
android:paddingLeft="16dp" android:orientation="vertical"
android:paddingRight="16dp" android:paddingLeft="16dp"
android:paddingTop="8dp" android:paddingRight="16dp"
android:paddingBottom="8dp"> android:paddingTop="8dp"
android:paddingBottom="8dp">
<CheckBox <CheckBox
android:layout_width="match_parent" android:id="@+id/checkbox_do_not_show_again"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:id="@+id/checkbox_do_not_show_again" android:layout_height="wrap_content"
android:text="@string/checkbox_do_not_show_again"/> android:text="@string/checkbox_do_not_show_again" />
</LinearLayout> </LinearLayout>

View File

@ -1,15 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="match_parent"
android:padding="16dp"> android:orientation="vertical"
android:padding="16dp">
<EditText <EditText
android:layout_width="match_parent" android:id="@+id/urlEditText"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:inputType="text" android:layout_height="wrap_content"
android:ems="10" android:inputType="text"
android:id="@+id/urlEditText" /> android:ems="10" />
</LinearLayout> </LinearLayout>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -19,4 +19,4 @@
tools:background="@android:color/holo_green_dark" tools:background="@android:color/holo_green_dark"
tools:text="List item title" /> tools:text="List item title" />
</LinearLayout> </LinearLayout>

View File

@ -1,36 +1,37 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:gravity="center" android:layout_height="match_parent"
android:layout_centerInParent="true" android:orientation="vertical"
android:paddingLeft="40dp" android:gravity="center"
android:paddingRight="40dp" android:layout_centerInParent="true"
xmlns:tools="http://schemas.android.com/tools"> android:paddingLeft="40dp"
android:paddingRight="40dp">
<ImageView
android:id="@+id/emptyViewIcon" <ImageView
android:layout_width="32dp" android:id="@+id/emptyViewIcon"
android:layout_height="32dp" android:layout_width="32dp"
android:visibility="gone" android:layout_height="32dp"
tools:src="@drawable/ic_feed" android:visibility="gone"
tools:visibility="visible"/> tools:src="@drawable/ic_feed"
tools:visibility="visible" />
<TextView
android:id="@+id/emptyViewTitle" <TextView
android:layout_width="wrap_content" android:id="@+id/emptyViewTitle"
android:layout_height="wrap_content" android:layout_width="wrap_content"
tools:text="Title" android:layout_height="wrap_content"
android:textSize="16sp" android:textSize="16sp"
android:textColor="?android:attr/textColorPrimary"/> android:textColor="?android:attr/textColorPrimary"
tools:text="Title" />
<TextView
android:id="@+id/emptyViewMessage" <TextView
android:layout_width="wrap_content" android:id="@+id/emptyViewMessage"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:textSize="14sp" android:layout_height="wrap_content"
tools:text="Message" android:textSize="14sp"
android:textAlignment="center"/> android:textAlignment="center"
tools:text="Message" />
</LinearLayout>
</LinearLayout>

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" > android:orientation="vertical">
<TextView <TextView
android:id="@+id/labelSkipIntro" android:id="@+id/labelSkipIntro"
@ -15,7 +16,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" > android:orientation="horizontal">
<EditText <EditText
android:id="@+id/etxtSkipIntro" android:id="@+id/etxtSkipIntro"
@ -51,7 +52,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" > android:orientation="horizontal">
<EditText <EditText
android:id="@+id/etxtSkipEnd" android:id="@+id/etxtSkipEnd"
@ -73,6 +74,7 @@
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="24dp" android:layout_marginRight="24dp"
android:text="@string/time_seconds" /> android:text="@string/time_seconds" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -1,29 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="48dp" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="48dp" android:id="@+id/secondaryActionButton"
android:layout_marginRight="12dp" android:layout_width="48dp"
android:layout_marginEnd="12dp" android:layout_height="48dp"
android:id="@+id/secondaryActionButton" android:layout_marginRight="12dp"
android:background="?selectableItemBackgroundBorderless" android:layout_marginEnd="12dp"
android:clickable="true" android:background="?selectableItemBackgroundBorderless"
android:focusable="false" android:clickable="true"
android:focusableInTouchMode="false" > android:focusable="false"
android:focusableInTouchMode="false">
<ImageView <ImageView
android:id="@+id/secondaryActionIcon" android:id="@+id/secondaryActionIcon"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_gravity="center" android:layout_gravity="center"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@sample/secondaryaction"/> tools:src="@sample/secondaryaction" />
<de.danoeh.antennapod.ui.common.CircularProgressBar <de.danoeh.antennapod.ui.common.CircularProgressBar
android:id="@+id/secondaryActionProgress" android:id="@+id/secondaryActionProgress"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_gravity="center" android:layout_height="40dp"
android:layout_height="40dp" android:layout_gravity="center"
app:foregroundColor="?attr/action_icon_color"/> app:foregroundColor="?attr/action_icon_color" />
</FrameLayout> </FrameLayout>

View File

@ -17,8 +17,8 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<CheckedTextView
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1" android:id="@android:id/text1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall" android:layout_height="?android:attr/listPreferredItemHeightSmall"
@ -31,5 +31,4 @@
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:maxLines="2" android:maxLines="2"
android:ellipsize="end" android:ellipsize="end" />
/>

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:baselineAligned="false" android:baselineAligned="false"
android:descendantFocusability="blocksDescendants"> android:descendantFocusability="blocksDescendants">
<ImageView <ImageView
android:id="@+id/imgvCover" android:id="@+id/imgvCover"
@ -17,57 +17,59 @@
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
tools:src="@tools:sample/avatars"/> tools:src="@tools:sample/avatars" />
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/txtvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding" style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding" tools:text="00:00:00" />
android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView <TextView
android:id="@+id/txtvStart" android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:ellipsize="end"
tools:text="00:00:00"/> style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
tools:text="@sample/episodes.json/data/title" />
<TextView <TextView
android:id="@+id/txtvTitle" android:id="@+id/txtvLink"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:focusable="false"
tools:text="@sample/episodes.json/data/title" android:focusableInTouchMode="false"
android:ellipsize="end"/> android:visibility="gone"
android:background="?attr/selectableItemBackground"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
tools:visibility="visible"
tools:text="https://example.com" />
<TextView <TextView
android:id="@+id/txtvLink" android:id="@+id/txtvDuration"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle" android:focusable="false"
android:focusable="false" android:focusableInTouchMode="false"
android:focusableInTouchMode="false" style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:visibility="gone" tools:text="Duration: 00:00:00" />
android:background="?attr/selectableItemBackground"
tools:visibility="visible"
tools:text="https://example.com"/>
<TextView
android:id="@+id/txtvDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:focusable="false"
android:focusableInTouchMode="false"
tools:text="Duration: 00:00:00"/>
</LinearLayout> </LinearLayout>
<include layout="@layout/secondary_action"/> <include
layout="@layout/secondary_action" />
</LinearLayout> </LinearLayout>

View File

@ -1,235 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name = "Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/>
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml" />
</module>
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<module name="TreeWalker">
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="AvoidStarImport"/>
<module name="UnusedImports"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap"/>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NeedBraces"/>
<module name="LeftCurly"/>
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
INSTANCE_INIT"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
<property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
<property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LambdaParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="4"/>
<property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="4"/>
<property name="throwsIndent" value="8"/>
<property name="lineWrappingIndentation" value="8"/>
<property name="arrayInitIndent" value="4"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="1"/>
</module>
<module name="VariableDeclarationUsageDistance"/>
<module name="MethodParamPad"/>
<module name="WhitespaceAfter"/>
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
<property name="allowLineBreaks" value="true"/>
</module>
<module name="ParenPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/>
</module>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation"/>
<module name="NestedIfDepth">
<property name="max" value="4"/>
</module>
<module name="NestedTryDepth">
<property name="max" value="2"/>
</module>
<module name="NestedForDepth">
<property name="max" value="2"/>
</module>
</module>
</module>

View File

@ -5,7 +5,7 @@
<module name = "Checker"> <module name = "Checker">
<property name="charset" value="UTF-8"/> <property name="charset" value="UTF-8"/>
<property name="severity" value="error"/> <property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/> <property name="fileExtensions" value="java"/>
<module name="SuppressionFilter"> <module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml" /> <property name="file" value="${config_loc}/suppressions.xml" />
@ -15,6 +15,11 @@
<property name="eachLine" value="true"/> <property name="eachLine" value="true"/>
</module> </module>
<module name="LineLength">
<property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="TreeWalker"> <module name="TreeWalker">
<module name="OuterTypeFilename"/> <module name="OuterTypeFilename"/>
<module name="IllegalTokenText"> <module name="IllegalTokenText">
@ -38,14 +43,35 @@
<property name="tokens" <property name="tokens"
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/> value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module> </module>
<module name="NeedBraces"/>
<module name="LeftCurly"/>
<module name="RightCurly"> <module name="RightCurly">
<property name="id" value="RightCurlySame"/> <property name="id" value="RightCurlySame"/>
<property name="tokens" <property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO"/> value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
INSTANCE_INIT"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module> </module>
<module name="OneStatementPerLine"/> <module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/> <module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/> <module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/> <module name="FallThrough"/>
<module name="UpperEll"/> <module name="UpperEll"/>
<module name="ModifierOrder"/> <module name="ModifierOrder"/>
@ -88,6 +114,16 @@
<message key="name.invalidPattern" <message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/> value="Type name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LambdaParameterName"> <module name="LambdaParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern" <message key="name.invalidPattern"
@ -98,6 +134,12 @@
<message key="name.invalidPattern" <message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/> value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName"> <module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern" <message key="name.invalidPattern"
@ -133,12 +175,25 @@
<property name="lineWrappingIndentation" value="8"/> <property name="lineWrappingIndentation" value="8"/>
<property name="arrayInitIndent" value="4"/> <property name="arrayInitIndent" value="4"/>
</module> </module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="1"/>
</module>
<module name="VariableDeclarationUsageDistance"/>
<module name="MethodParamPad"/>
<module name="WhitespaceAfter"/>
<module name="NoWhitespaceBefore"> <module name="NoWhitespaceBefore">
<property name="tokens" <property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/> value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
<property name="allowLineBreaks" value="true"/> <property name="allowLineBreaks" value="true"/>
</module> </module>
<module name="ParenPad"/> <module name="ParenPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
</module>
<module name="AnnotationLocation"> <module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/> <property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens" <property name="tokens"
@ -149,6 +204,9 @@
<property name="tokens" value="VARIABLE_DEF"/> <property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/> <property name="allowSamelineMultipleAnnotations" value="true"/>
</module> </module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder"> <module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/> <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" <property name="target"
@ -165,6 +223,7 @@
<module name="EmptyCatchBlock"> <module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/> <property name="exceptionVariableName" value="expected"/>
</module> </module>
<module name="CommentsIndentation"/>
<module name="NestedIfDepth"> <module name="NestedIfDepth">
<property name="max" value="4"/> <property name="max" value="4"/>
</module> </module>

View File

@ -3,11 +3,28 @@
"-//Puppy Crawl//DTD Suppressions 1.1//EN" "-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions> <suppressions>
<suppress checks="MethodName" files="core/src/test/java/android/util/Log.java" />
<suppress checks="LineLength" files="strings.xml"/> <suppress checks="LineLength" files="strings.xml"/>
<suppress checks="." files="[\\/]generated-sources[\\/]"/> <suppress checks="." files="[\\/]generated-sources[\\/]"/>
<suppress checks="." files="[\\/]build[\\/]"/> <suppress checks="." files="[\\/]build[\\/]"/>
<suppress checks="." files="[\\/]gen[\\/]"/> <suppress checks="." files="[\\/]gen[\\/]"/>
<suppress checks="." files="[\\/].idea[\\/]"/> <suppress checks="." files="[\\/].idea[\\/]"/>
<!-- Legacy code, should be gradually updated when touching these lines anyway -->
<suppress checks="LineLength" files="(VolumeAdaptionSettingTest.java|MediaMetadataRetrieverCompat.java|FeedItem.java|FeedMedia.java|FeedPreferences.java|Feed.java|DBUpgrader.java|PodDBAdapter.java|PlaybackServiceMediaPlayer.java|PlaybackService.java|LocalPSMP.java|PlaybackServiceTaskManager.java|DBWriter.java|PodcastSearchResult.java|PlaybackServiceTaskManagerTest.java|HTTPBin.java|SPAReceiver.java|UriUtil.java|FeedDiscovererTest.java|PlaybackServiceMediaPlayerTest.java|TextOnlyFeedsTest.java|ItemFragment.java|FeedSettingsFragment.java|UITestUtils.java)"/>
<suppress checks="VariableDeclarationUsageDistance" files="(FeedFilterTest.java|ChapterReader.java|FastBlurTransformation.java|GpodnetService.java|PreferencesTest.java|ItemFilterDialog.java|ItemFragment.java|PlaybackServiceMediaPlayerTest.java)"/>
<suppress checks="ParameterName" files="(FeedMedia.java)"/>
<suppress checks="WhitespaceAround" files="(FeedMedia.java|UserPreferences.java|LongList.java|IntentUtils.java|PlaybackServiceMediaPlayer.java|ShakeListener.java|LocalPSMP.java|PodcastSearchResult.java|NetworkUtils.java|UITestUtils.java|PlaybackPreferencesFragment.java|OnlineFeedViewActivity.java|QueueFragment.java|SPAReceiver.java|SkipIntroEndingChangedEvent.java|GeneratorUtil.java|RewindAfterPauseUtils.java|PlaybackController.java|AutoDownloadPreferencesFragment.java)"/>
<suppress checks="WhitespaceAfter" files="(FeedMedia.java|LongList.java|IntentUtils.java|TimeSpeedConverter.java|LocalPSMP.java|PlaybackController.java|PodcastSearchResult.java|PlaybackPreferencesFragment.java|OnlineFeedViewActivity.java|QueueFragment.java)"/>
<suppress checks="AbbreviationAsWordInName" files="(FeedItemPermutorsTest.java|DBUpgrader.java|PodDBAdapter.java|DBWriter.java|DBReader.java|RewindAfterPauseUtilTest.java|PlaybackServiceMediaPlayer.java|PlaybackService.java|LocalPSMP.java|PlaybackServiceTaskManager.java|GpodnetUploadChangesResponse.java|GpodnetEpisodeActionPostResponse.java|UrlCheckerTest.java|UriUtilTest.java|UriUtil.java|PlaybackServiceTaskManagerTest.java|SPAUtil.java|FeedDiscovererTest.java|PlaybackServiceMediaPlayerTest.java|DefaultPSMPCallback.java|UITestUtils.java|APCleanupAlgorithmTest.java|APNullCleanupAlgorithm.java|APCleanupAlgorithm.java|HTTPBin.java|UITestUtilsTest.java|FeedDiscoverer.java|SPAReceiver.java|APQueueCleanupAlgorithm.java|CancelablePSMPCallback.java)"/>
<suppress checks="NeedBraces" files="(PlaybackServiceMediaPlayerTest.java|FeedPreferences.java|DownloadRequest.java|HTTPBin.java|UITestUtils.java|SPAUtil.java)"/>
<suppress checks="NonEmptyAtclauseDescription" files="(FeedFilter.java|AspectRatioVideoView.java|Playable.java|PlaybackServiceTaskManager.java|PodcastSearchResult.java|OpmlBackupAgent.java)"/>
<suppress checks="OperatorWrapCheck" files="(Atom.java|DBUpgrader.java|PodDBAdapter.java|PlaybackController.java|GpodnetUploadChangesResponse.java|HtmlToPlainText.java|PodcastSearchResult.java|PowerConnectionReceiver.java|FeedDiscoverer.java|DBWriter.java|PlaybackService.java)"/>
<suppress checks="RightCurlyAlone" files="(UserPreferences.java|LockableBottomSheetBehavior.java|NetworkUtils.java|ProxyDialog.java|IntentUtils.java|RewindAfterPauseUtils.java|GpodnetPodcast.java|GeneratorUtil.java|PlaybackController.java|AntennapodHttpClient.java|UriUtil.java|APCleanupAlgorithm.java)"/>
<suppress checks="JavadocParagraph" files="(FeedItemPermutors.java|HtmlToPlainText.java|FeedItemMenuHandler.java|RewindAfterPauseUtils.java|PlaybackServiceMediaPlayer.java|UITestUtils.java|NestedScrollableHost.java|PlaybackService.java)"/>
<suppress checks="JavadocTagContinuationIndentation" files="(ItemEnqueuePositionCalculator.java|LongList.java|DBReader.java|LocalPSMP.java|GpodnetService.java|FeedDiscoverer.java|SPAUtil.java|PlaybackServiceMediaPlayer.java)"/>
<suppress checks="MemberName" files="(OpmlBackupAgent.java|ShakeListener.java|PlaybackController.java|AspectRatioVideoView.java|PlaybackService.java|PlaybackServiceMediaPlayerTest.java)"/>
<suppress checks="LocalVariableName" files="(ShakeListener.java|ItemEnqueuePositionCalculatorTest.java)"/>
<suppress checks="LeftCurly" files="(GpodnetPodcast.java|APCleanupAlgorithm.java|APQueueCleanupAlgorithm.java)"/>
<suppress checks="MissingSwitchDefaultCheck" files="(MainActivity.java|FeedSettingsFragment.java|QueueFragment.java|VideoplayerActivity.java|PlaybackController.java|PreferenceUpgrader.java)"/>
</suppressions> </suppressions>

View File

@ -6,6 +6,10 @@ apply from: "../../playFlavor.gradle"
android { android {
namespace "de.danoeh.antennapod.net.common" namespace "de.danoeh.antennapod.net.common"
lint {
disable 'StaticFieldLeak'
}
} }
dependencies { dependencies {

View File

@ -14,11 +14,9 @@ import java.util.regex.Pattern;
import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.storage.preferences.UserPreferences;
public class NetworkUtils { public abstract class NetworkUtils {
private static final String REGEX_PATTERN_IP_ADDRESS = "([0-9]{1,3}[\\.]){3}[0-9]{1,3}"; private static final String REGEX_PATTERN_IP_ADDRESS = "([0-9]{1,3}[\\.]){3}[0-9]{1,3}";
private NetworkUtils(){}
private static Context context; private static Context context;
public static void init(Context context) { public static void init(Context context) {

View File

@ -8,9 +8,7 @@ import java.net.URL;
/** /**
* Utility methods for dealing with URL encoding. * Utility methods for dealing with URL encoding.
*/ */
public class UriUtil { public abstract class UriUtil {
private UriUtil() {}
public static URI getURIFromRequestUrl(String source) { public static URI getURIFromRequestUrl(String source) {
// try without encoding the URI // try without encoding the URI
try { try {

View File

@ -121,7 +121,9 @@ public class APCleanupAlgorithm extends EpisodeCleanupAlgorithm {
} }
@VisibleForTesting @VisibleForTesting
public int getNumberOfHoursAfterPlayback() { return numberOfHoursAfterPlayback; } public int getNumberOfHoursAfterPlayback() {
return numberOfHoursAfterPlayback;
}
private static Date minusHours(Date baseDate, int numberOfHours) { private static Date minusHours(Date baseDate, int numberOfHours) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();

View File

@ -12,15 +12,8 @@ public class GpodnetPodcast {
private final String mygpoLink; private final String mygpoLink;
private final String author; private final String author;
public GpodnetPodcast(@NonNull String url, public GpodnetPodcast(@NonNull String url, @NonNull String title, @NonNull String description, int subscribers,
@NonNull String title, String logoUrl, String website, String mygpoLink, String author) {
@NonNull String description,
int subscribers,
String logoUrl,
String website,
String mygpoLink,
String author
) {
this.url = url; this.url = url;
this.title = title; this.title = title;
this.description = description; this.description = description;
@ -63,7 +56,9 @@ public class GpodnetPodcast {
return website; return website;
} }
public String getAuthor() { return author; } public String getAuthor() {
return author;
}
public String getMygpoLink() { public String getMygpoLink() {
return mygpoLink; return mygpoLink;

View File

@ -8,9 +8,7 @@ import java.util.concurrent.TimeUnit;
* User might loose context if he/she pauses and resumes the media after longer time. * User might loose context if he/she pauses and resumes the media after longer time.
* Media file should be "rewinded" x seconds after user resumes the playback. * Media file should be "rewinded" x seconds after user resumes the playback.
*/ */
public class RewindAfterPauseUtils { public abstract class RewindAfterPauseUtils {
private RewindAfterPauseUtils(){}
public static final long ELAPSED_TIME_FOR_SHORT_REWIND = TimeUnit.MINUTES.toMillis(1); public static final long ELAPSED_TIME_FOR_SHORT_REWIND = TimeUnit.MINUTES.toMillis(1);
public static final long ELAPSED_TIME_FOR_MEDIUM_REWIND = TimeUnit.HOURS.toMillis(1); public static final long ELAPSED_TIME_FOR_MEDIUM_REWIND = TimeUnit.HOURS.toMillis(1);
public static final long ELAPSED_TIME_FOR_LONG_REWIND = TimeUnit.DAYS.toMillis(1); public static final long ELAPSED_TIME_FOR_LONG_REWIND = TimeUnit.DAYS.toMillis(1);

View File

@ -224,7 +224,8 @@ public abstract class PlaybackController {
}; };
public void onPlaybackEnd() {} public void onPlaybackEnd() {
}
/** /**
* Is called whenever the PlaybackService changes its status. This method * Is called whenever the PlaybackService changes its status. This method

View File

@ -8,7 +8,7 @@ android {
namespace "de.danoeh.antennapod.storage.database" namespace "de.danoeh.antennapod.storage.database"
lint { lint {
disable "StaticFieldLeak", "StringFormatCount", "StringFormatMatches", "StringFormatInvalid", "PluralsCandidate", "StringFormatTrivial" disable "StaticFieldLeak"
} }
} }

View File

@ -41,9 +41,7 @@ import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
* init() or otherwise every public method will throw an Exception * init() or otherwise every public method will throw an Exception
* when called. * when called.
*/ */
public class UserPreferences { public abstract class UserPreferences {
private UserPreferences(){}
private static final String TAG = "UserPreferences"; private static final String TAG = "UserPreferences";
// User Interface // User Interface

View File

@ -5,6 +5,10 @@ apply from: "../../common.gradle"
android { android {
namespace "de.danoeh.antennapod.ui.common" namespace "de.danoeh.antennapod.ui.common"
lint {
disable 'VectorPath'
}
} }
dependencies { dependencies {

View File

@ -17,11 +17,9 @@ import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
public class IntentUtils { public abstract class IntentUtils {
private static final String TAG = "IntentUtils"; private static final String TAG = "IntentUtils";
private IntentUtils(){}
/* /*
* Checks if there is at least one exported activity that can be performed for the intent * Checks if there is at least one exported activity that can be performed for the intent
*/ */

View File

@ -48,13 +48,3 @@ dependencies {
implementation "org.greenrobot:eventbus:$eventbusVersion" implementation "org.greenrobot:eventbus:$eventbusVersion"
implementation 'com.github.ByteHamster:SearchPreference:v2.5.0' implementation 'com.github.ByteHamster:SearchPreference:v2.5.0'
} }
tasks.register('copyLicense', Copy) {
from "../../LICENSE"
into "src/main/assets/"
rename { String fileName ->
fileName + ".txt"
}
}
preBuild.dependsOn copyLicense

View File

@ -1,4 +0,0 @@
# this file is generated automatically
about.html
LICENSE.txt
CONTRIBUTORS.txt

View File

@ -0,0 +1 @@
../../../../../LICENSE

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ImageView <ImageView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:adjustViewBounds="true" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:adjustViewBounds="true"
app:srcCompat="@drawable/teaser" android:importantForAccessibility="no"
android:importantForAccessibility="no"/> app:srcCompat="@drawable/teaser" />

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:layout_width="match_parent"
android:orientation="vertical"> android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent" android:id="@+id/recyclerView"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:id="@+id/recyclerView" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -38,9 +39,10 @@
<ProgressBar <ProgressBar
android:id="@+id/used_space" android:id="@+id/used_space"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal" />
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="8dp"> android:paddingTop="8dp">
<Button <Button
android:id="@+id/selectDeviceButton" android:id="@+id/selectDeviceButton"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="?attr/materialButtonOutlinedStyle" /> style="?attr/materialButtonOutlinedStyle" />
</FrameLayout>
</FrameLayout>

View File

@ -24,6 +24,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:text="@string/gpodnetauth_finish_butsyncnow"/> android:text="@string/gpodnetauth_finish_butsyncnow" />
</LinearLayout> </LinearLayout>

View File

@ -1,40 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="16dp"> android:padding="16dp">
<ImageView <ImageView
android:layout_width="40dp" android:id="@+id/icon"
android:layout_height="40dp" android:layout_width="40dp"
android:id="@+id/icon"/> android:layout_height="40dp" />
<LinearLayout <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="16dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:textColor="?android:attr/textColorPrimary"
android:layout_marginLeft="16dp" android:textSize="16sp"
android:layout_gravity="center_vertical" tools:text="Title" />
android:layout_marginStart="16dp">
<TextView <TextView
tools:text="Title" android:id="@+id/subtitle"
android:textColor="?android:attr/textColorPrimary" android:layout_width="match_parent"
android:textSize="16sp" android:layout_height="wrap_content"
android:layout_width="match_parent" android:textColor="?android:attr/textColorSecondary"
android:layout_height="wrap_content" android:textSize="14sp"
android:id="@+id/title"/> tools:text="Subtitle" />
<TextView
tools:text="Subtitle"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/subtitle"/>
</LinearLayout> </LinearLayout>

View File

@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent" android:layout_width="match_parent"
android:orientation="vertical"> android:layout_height="match_parent"
android:orientation="vertical">
<ProgressBar <ProgressBar
android:layout_width="wrap_content" android:id="@+id/progressBar"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:id="@+id/progressBar" android:layout_height="wrap_content"
android:layout_gravity="center"/> android:layout_gravity="center" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/statistics_list" android:id="@+id/statistics_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingBottom="@dimen/list_vertical_padding" android:paddingBottom="@dimen/list_vertical_padding"
android:paddingTop="@dimen/list_vertical_padding" android:paddingTop="@dimen/list_vertical_padding"
android:scrollbarStyle="outsideOverlay" android:scrollbarStyle="outsideOverlay"
tools:listitem="@layout/statistics_listitem"/> tools:listitem="@layout/statistics_listitem" />
</FrameLayout> </FrameLayout>

View File

@ -1,71 +1,72 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="16dp" android:orientation="vertical"
android:paddingRight="16dp" android:paddingLeft="16dp"
android:paddingTop="8dp" android:paddingRight="16dp"
android:paddingBottom="8dp" android:paddingTop="8dp"
android:background="?android:attr/selectableItemBackground"> android:paddingBottom="8dp"
android:background="?android:attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/imgvCover" android:id="@+id/imgvCover"
android:importantForAccessibility="no" android:layout_width="40dp"
android:layout_width="40dp" android:layout_height="40dp"
android:layout_height="40dp" android:importantForAccessibility="no"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:cropToPadding="true" android:cropToPadding="true"
android:scaleType="fitCenter" android:scaleType="fitCenter"
tools:src="@tools:sample/avatars" tools:src="@tools:sample/avatars"
tools:background="@android:color/holo_green_dark"/> tools:background="@android:color/holo_green_dark" />
<TextView <TextView
android:id="@+id/txtvTitle" android:id="@+id/txtvTitle"
android:lines="1" android:layout_width="wrap_content"
android:ellipsize="end" android:layout_height="wrap_content"
android:singleLine="true" android:lines="1"
android:textColor="?android:attr/textColorPrimary" android:ellipsize="end"
android:textSize="16sp" android:singleLine="true"
android:layout_width="wrap_content" android:textColor="?android:attr/textColorPrimary"
android:layout_height="wrap_content" android:textSize="16sp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_toRightOf="@id/imgvCover" android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover" android:layout_toEndOf="@id/imgvCover"
android:layout_alignTop="@id/imgvCover" android:layout_alignTop="@id/imgvCover"
android:layout_alignWithParentIfMissing="true" android:layout_alignWithParentIfMissing="true"
tools:text="Feed title"/> tools:text="Feed title" />
<TextView <TextView
android:id="@+id/chip" android:id="@+id/chip"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="13sp" android:textSize="13sp"
android:layout_toEndOf="@+id/imgvCover" android:layout_toEndOf="@+id/imgvCover"
android:layout_toRightOf="@+id/imgvCover" android:layout_toRightOf="@+id/imgvCover"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_below="@+id/txtvTitle" android:layout_below="@+id/txtvTitle"
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
android:layout_marginRight="4dp" android:layout_marginRight="4dp"
android:text="⬤" android:text="⬤"
tools:ignore="HardcodedText"/> tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/txtvValue" android:id="@+id/txtvValue"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:lines="1" android:lines="1"
android:textColor="?android:attr/textColorTertiary" android:textColor="?android:attr/textColorTertiary"
android:textSize="14sp" android:textSize="14sp"
android:layout_toEndOf="@+id/chip" android:layout_toEndOf="@+id/chip"
android:layout_toRightOf="@+id/chip" android:layout_toRightOf="@+id/chip"
android:layout_below="@+id/txtvTitle" android:layout_below="@+id/txtvTitle"
tools:text="23 hours"/> tools:text="23 hours" />
</RelativeLayout> </RelativeLayout>