Commit c34e36d1 authored by Christophe Henry's avatar Christophe Henry

Solves #18: Setup a linter

- Also fixes lint issues
parent b8e436d8
...@@ -65,6 +65,13 @@ you have the knowledge. ...@@ -65,6 +65,13 @@ you have the knowledge.
If you are not a developer, you can contribute by localizing the application in your language. If you are not a developer, you can contribute by localizing the application in your language.
Please read the [Android localization guide](https://developer.android.com/guide/topics/resources/localization). Please read the [Android localization guide](https://developer.android.com/guide/topics/resources/localization).
## Running tests and linter
Ensure you ran the linters:
```
./gradlew spotlessApply lintFix
```
# Contributors # Contributors
......
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: "kotlin-android" apply plugin: "kotlin-android"
apply plugin: "kotlin-android-extensions" apply plugin: "kotlin-android-extensions"
apply plugin: "kotlinx-serialization"
apply plugin: "kotlin-kapt" apply plugin: "kotlin-kapt"
apply plugin: "androidx.navigation.safeargs.kotlin" apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: "com.diffplug.gradle.spotless"
android { android {
def schema_location = "$projectDir/src/main/java/fr/chenry/android/freshrss/store/database/migrations".toString() def schema_location = "$projectDir/src/main/java/fr/chenry/android/freshrss/store/database/migrations".toString()
...@@ -60,6 +60,32 @@ android { ...@@ -60,6 +60,32 @@ android {
} }
} }
configurations {
ktlint
}
spotless {
format "misc", {
target "**/*.gradle", "**/*.md", "**/.gitignore", "**/*.kt"
trimTrailingWhitespace()
endWithNewline()
}
kotlin {
ktlint().userData([
"trim_trailing_whitespace": true,
"insert_final_newline": true,
"max_line_length": 120,
])
}
format "xml", {
target fileTree(".") {
include "**/*.xml"
exclude "**/build/**"
}
eclipseWtp("xml").configFile "$rootDir/freshrss.xmlformat.prefs".toString()
}
}
dependencies { dependencies {
def lifecycle_version = "2.0.0" def lifecycle_version = "2.0.0"
def room_version = "2.1.0-alpha04" def room_version = "2.1.0-alpha04"
...@@ -72,6 +98,9 @@ dependencies { ...@@ -72,6 +98,9 @@ dependencies {
def android_support_version = "28.0.0" def android_support_version = "28.0.0"
def android_navigation = "1.0.0" def android_navigation = "1.0.0"
// Linter
ktlint "com.github.shyiko:ktlint:0.31.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation fileTree(include: ["*.jar"], dir: "libs") implementation fileTree(include: ["*.jar"], dir: "libs")
...@@ -98,7 +127,7 @@ dependencies { ...@@ -98,7 +127,7 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
// Room // Room
...@@ -133,7 +162,6 @@ dependencies { ...@@ -133,7 +162,6 @@ dependencies {
implementation "eu.davidea:flexible-adapter:5.1.0" implementation "eu.davidea:flexible-adapter:5.1.0"
implementation "eu.davidea:flexible-adapter-ui:1.0.0" implementation "eu.davidea:flexible-adapter-ui:1.0.0"
// Tests // Tests
testImplementation "junit:junit:4.12" testImplementation "junit:junit:4.12"
androidTestImplementation "androidx.test:runner:$test_runnner_version" androidTestImplementation "androidx.test:runner:$test_runnner_version"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution" xmlns:dist="http://schemas.android.com/apk/distribution"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="fr.chenry.android.freshrss"> package="fr.chenry.android.freshrss">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<dist:module dist:instant="true" /> <dist:module dist:instant="true" />
<application <application
android:name=".FreshRSSApplication" android:name=".FreshRSSApplication"
android:allowBackup="true" android:allowBackup="true"
...@@ -29,13 +27,11 @@ ...@@ -29,13 +27,11 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name=".RefresherService" android:name=".RefresherService"
android:enabled="true" android:enabled="true"
android:exported="false"> android:exported="false">
</service> </service>
<activity <activity
android:name=".activities.LoginActivity" android:name=".activities.LoginActivity"
android:label="@string/app_name" android:label="@string/app_name"
...@@ -51,5 +47,4 @@ ...@@ -51,5 +47,4 @@
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
...@@ -98,4 +98,4 @@ class FreshRSSApplication: Application() { ...@@ -98,4 +98,4 @@ class FreshRSSApplication: Application() {
} }
} }
} }
} }
\ No newline at end of file
...@@ -4,7 +4,7 @@ import android.content.Intent ...@@ -4,7 +4,7 @@ import android.content.Intent
class MailIntent(address: String, subject: String = "", body: String = "", cc: String = ""): class MailIntent(address: String, subject: String = "", body: String = "", cc: String = ""):
Intent(ACTION_SEND) { Intent(ACTION_SEND) {
init { init {
putExtra(EXTRA_EMAIL, arrayOf(address)) putExtra(EXTRA_EMAIL, arrayOf(address))
putExtra(EXTRA_TEXT, body) putExtra(EXTRA_TEXT, body)
...@@ -12,4 +12,4 @@ class MailIntent(address: String, subject: String = "", body: String = "", cc: S ...@@ -12,4 +12,4 @@ class MailIntent(address: String, subject: String = "", body: String = "", cc: S
putExtra(EXTRA_CC, cc) putExtra(EXTRA_CC, cc)
type = "message/rfc822" type = "message/rfc822"
} }
} }
\ No newline at end of file
...@@ -23,4 +23,4 @@ class FRSSWebViewClient(private val fragment: Fragment, private val sourceUrl: U ...@@ -23,4 +23,4 @@ class FRSSWebViewClient(private val fragment: Fragment, private val sourceUrl: U
return true return true
} }
} }
\ No newline at end of file
...@@ -22,4 +22,4 @@ enum class SubscriptionSection(val navigationButtonId: Int): Parcelable { ...@@ -22,4 +22,4 @@ enum class SubscriptionSection(val navigationButtonId: Int): Parcelable {
else -> ALL else -> ALL
} }
} }
} }
\ No newline at end of file
...@@ -67,4 +67,4 @@ class SubscriptionCategoryViewItem(val subscriptionCategory: SubscriptionCategor ...@@ -67,4 +67,4 @@ class SubscriptionCategoryViewItem(val subscriptionCategory: SubscriptionCategor
if(other !is SubscriptionCategoryViewItem) false else subscriptionCategory == other.subscriptionCategory if(other !is SubscriptionCategoryViewItem) false else subscriptionCategory == other.subscriptionCategory
override fun hashCode(): Int = subscriptionCategory.hashCode() override fun hashCode(): Int = subscriptionCategory.hashCode()
} }
\ No newline at end of file
...@@ -48,4 +48,4 @@ open class SubscriptionViewHeaderItem(val title: String): ...@@ -48,4 +48,4 @@ open class SubscriptionViewHeaderItem(val title: String):
object SubscriptionCategoryViewHeaderItem: object SubscriptionCategoryViewHeaderItem:
SubscriptionViewHeaderItem(FreshRSSApplication.getStringR(R.string.subscription_categories)) SubscriptionViewHeaderItem(FreshRSSApplication.getStringR(R.string.subscription_categories))
\ No newline at end of file
...@@ -110,4 +110,4 @@ object Store { ...@@ -110,4 +110,4 @@ object Store {
} }
} }
} }
} }
\ No newline at end of file
...@@ -9,4 +9,4 @@ class Endpoints(private val base: String) { ...@@ -9,4 +9,4 @@ class Endpoints(private val base: String) {
val tagEndpoint = "${this.base}/reader/api/0/tag/list" val tagEndpoint = "${this.base}/reader/api/0/tag/list"
val unreadItemsEndpoint = "${this.base}/reader/api/0/stream/contents/user/-/state/com.google/reading-list" val unreadItemsEndpoint = "${this.base}/reader/api/0/stream/contents/user/-/state/com.google/reading-list"
val editTagEnpoint = "${this.base}/reader/api/0/edit-tag" val editTagEnpoint = "${this.base}/reader/api/0/edit-tag"
} }
\ No newline at end of file
...@@ -37,4 +37,4 @@ data class ContentItemOrigin( ...@@ -37,4 +37,4 @@ data class ContentItemOrigin(
data class Summary(val content: String) data class Summary(val content: String)
data class Href(val href: String) data class Href(val href: String)
\ No newline at end of file
...@@ -17,4 +17,4 @@ class MilliSecTimestampDeserializer: LocalDateTimeDeserializer() { ...@@ -17,4 +17,4 @@ class MilliSecTimestampDeserializer: LocalDateTimeDeserializer() {
val tz = if(_format.isTimezoneExplicit) _format.timeZone else DateTimeZone.forTimeZone(ctxt?.timeZone) val tz = if(_format.isTimezoneExplicit) _format.timeZone else DateTimeZone.forTimeZone(ctxt?.timeZone)
return LocalDateTime(p?.valueAsString?.toLongOrNull() ?: 0, tz) return LocalDateTime(p?.valueAsString?.toLongOrNull() ?: 0, tz)
} }
} }
\ No newline at end of file
...@@ -27,4 +27,4 @@ data class SubscriptionCategoryApiItem( ...@@ -27,4 +27,4 @@ data class SubscriptionCategoryApiItem(
class HtmlEntitiesDeserializer: StringDeserializer() { class HtmlEntitiesDeserializer: StringDeserializer() {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?) = super.deserialize(p, ctxt).unescapeHtml4() override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?) = super.deserialize(p, ctxt).unescapeHtml4()
} }
\ No newline at end of file
...@@ -17,4 +17,4 @@ object TagsDeserializer: ResponseDeserializable<List<String>> { ...@@ -17,4 +17,4 @@ object TagsDeserializer: ResponseDeserializable<List<String>> {
listOf() listOf()
} }
} }
} }
\ No newline at end of file
...@@ -5,4 +5,4 @@ data class UnreadCountsHandler(val max: Int, val unreadcounts: List<UnreadCount> ...@@ -5,4 +5,4 @@ data class UnreadCountsHandler(val max: Int, val unreadcounts: List<UnreadCount>
data class UnreadCount( data class UnreadCount(
val id: String, val id: String,
val count: Int val count: Int
) )
\ No newline at end of file
...@@ -83,4 +83,4 @@ abstract class FreshRSSDabatabase: RoomDatabase() { ...@@ -83,4 +83,4 @@ abstract class FreshRSSDabatabase: RoomDatabase() {
getSubscriptionCategoriesDAO().insertAll(subscriptionCategories) getSubscriptionCategoriesDAO().insertAll(subscriptionCategories)
fun getCategoriesById(ids: List<String>) = getSubscriptionCategoriesDAO().byIds(ids) fun getCategoriesById(ids: List<String>) = getSubscriptionCategoriesDAO().byIds(ids)
fun getAllCategories() = getSubscriptionCategoriesDAO().all() fun getAllCategories() = getSubscriptionCategoriesDAO().all()
} }
\ No newline at end of file
...@@ -48,4 +48,4 @@ interface AuthTokensDAO { ...@@ -48,4 +48,4 @@ interface AuthTokensDAO {
@Query("SELECT * FROM accounts") @Query("SELECT * FROM accounts")
fun getAuthTokens(): Flowable<List<Account>> fun getAuthTokens(): Flowable<List<Account>>
} }
\ No newline at end of file
...@@ -79,4 +79,4 @@ interface ArticlesDAO { ...@@ -79,4 +79,4 @@ interface ArticlesDAO {
@Query("SELECT * FROM articles WHERE streamId = :streamId AND readStatus = :readStatus") @Query("SELECT * FROM articles WHERE streamId = :streamId AND readStatus = :readStatus")
fun getByStreamIdAndUnread(streamId: StreamId, readStatus: String = ReadStatus.UNREAD.name): LiveData<Articles> fun getByStreamIdAndUnread(streamId: StreamId, readStatus: String = ReadStatus.UNREAD.name): LiveData<Articles>
} }
\ No newline at end of file
...@@ -35,4 +35,4 @@ interface SubscriptionCategoriesDAO { ...@@ -35,4 +35,4 @@ interface SubscriptionCategoriesDAO {
@Query("SELECT * FROM subscription_categories") @Query("SELECT * FROM subscription_categories")
fun all(): Flowable<SubscriptionCategories> fun all(): Flowable<SubscriptionCategories>
} }
\ No newline at end of file
...@@ -17,4 +17,4 @@ class AccountVM: ViewModel() { ...@@ -17,4 +17,4 @@ class AccountVM: ViewModel() {
source.observeForever {if(it.isNotEmpty()) value = it.first()} source.observeForever {if(it.isNotEmpty()) value = it.first()}
} }
} }
} }
\ No newline at end of file
...@@ -29,4 +29,4 @@ class SubscriptionArticleVMF(private val articleId: ItemId): ViewModelProvider.N ...@@ -29,4 +29,4 @@ class SubscriptionArticleVMF(private val articleId: ItemId): ViewModelProvider.N
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return SubscriptionArticleVM(articleId) as T return SubscriptionArticleVM(articleId) as T
} }
} }
\ No newline at end of file
...@@ -35,4 +35,4 @@ class SubscriptionArticlesVMF(private val streamId: String, private val readStat ...@@ -35,4 +35,4 @@ class SubscriptionArticlesVMF(private val streamId: String, private val readStat
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return SubscriptionArticlesVM(streamId, readStatus) as T return SubscriptionArticlesVM(streamId, readStatus) as T
} }
} }
\ No newline at end of file
...@@ -48,4 +48,4 @@ class InstanceUrl(val protocole: String, base: String) { ...@@ -48,4 +48,4 @@ class InstanceUrl(val protocole: String, base: String) {
return InstanceUrl(authorizedProtocols[0], url) return InstanceUrl(authorizedProtocols[0], url)
} }
} }
} }
\ No newline at end of file
...@@ -104,4 +104,4 @@ fun <V, E> Promise<V, E>.getOrDefault(default: V) = try { ...@@ -104,4 +104,4 @@ fun <V, E> Promise<V, E>.getOrDefault(default: V) = try {
} }
fun <T: Any> T?.whenNotNull(body: (T) -> Unit) = if(this !== null) body(this).let {this} else this fun <T: Any> T?.whenNotNull(body: (T) -> Unit) = if(this !== null) body(this).let {this} else this
fun <T: Any> T?.whenNull(body: () -> Unit) = this ?: body().let {this} fun <T: Any> T?.whenNull(body: () -> Unit) = this ?: body().let {this}
\ No newline at end of file
...@@ -26,4 +26,4 @@ class LollipopFixedWebView: WebView { ...@@ -26,4 +26,4 @@ class LollipopFixedWebView: WebView {
companion object { companion object {
fun getFixedContext(context: Context): Context = context.createConfigurationContext(Configuration()) fun getFixedContext(context: Context): Context = context.createConfigurationContext(Configuration())
} }
} }
\ No newline at end of file
...@@ -34,4 +34,3 @@ enum class NotificationChanels(nameResourceId: Int, descriptionResourceId: Int, ...@@ -34,4 +34,3 @@ enum class NotificationChanels(nameResourceId: Int, descriptionResourceId: Int,
} }
} }
} }
...@@ -29,4 +29,4 @@ class SquaredImageView(context: Context, attrs: AttributeSet?, defStyleAttr: Int ...@@ -29,4 +29,4 @@ class SquaredImageView(context: Context, attrs: AttributeSet?, defStyleAttr: Int
return max(measuredWidth, maxWidth).let {setMeasuredDimension(it, it)} return max(measuredWidth, maxWidth).let {setMeasuredDimension(it, it)}
} }
} }
\ No newline at end of file
...@@ -23,4 +23,4 @@ class Try<T: Any>(body: () -> T) { ...@@ -23,4 +23,4 @@ class Try<T: Any>(body: () -> T) {
fun orElseDo(body: () -> Unit) = if(!isSuccess) body() else Unit fun orElseDo(body: () -> Unit) = if(!isSuccess) body() else Unit
fun getOrDefault(default: T) = if(isSuccess) value else default fun getOrDefault(default: T) = if(isSuccess) value else default
fun getOrNull() = if(isSuccess) value else null fun getOrNull() = if(isSuccess) value else null
} }
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:height="108dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportHeight="108" android:height="108dp"
android:viewportWidth="108" android:viewportHeight="108"
android:width="108dp"> android:viewportWidth="108"
android:width="108dp">
<path <path
android:pathData="M54,54m-8.25,0a8.25,8.25 0,1 1,16.5 0a8.25,8.25 0,1 1,-16.5 0" android:pathData="M54,54m-8.25,0a8.25,8.25 0,1 1,16.5 0a8.25,8.25 0,1 1,-16.5 0"
android:strokeWidth="0.25" android:strokeWidth="0.25"
android:fillColor="@color/logo_grey"/> android:fillColor="@color/logo_grey" />
<path <path
android:pathData="M22.807,54A31.193,31.193 0,1 1,54 85.193" android:pathData="M22.807,54A31.193,31.193 0,1 1,54 85.193"
android:strokeAlpha="0.3" android:strokeAlpha="0.3"
android:strokeWidth="6.075" android:strokeWidth="6.075"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="@color/logo_grey"/> android:strokeColor="@color/logo_grey" />
<path <path
android:pathData="m34.101,54a19.899,19.899 0,1 1,19.899 19.899" android:pathData="m34.101,54a19.899,19.899 0,1 1,19.899 19.899"
android:strokeAlpha="0.3" android:strokeAlpha="0.3"
android:strokeWidth="6.075" android:strokeWidth="6.075"
android:strokeColor="@color/logo_grey"/> android:strokeColor="@color/logo_grey" />
<path <path
android:pathData="M54,22.807A31.193,31.193 0,0 1,85.193 54" android:pathData="M54,22.807A31.193,31.193 0,0 1,85.193 54"
android:strokeWidth="6.075" android:strokeWidth="6.075"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="@color/logo_grey"/> android:strokeColor="@color/logo_grey" />
<path <path
android:pathData="m54,34.101a19.899,19.899 0,0 1,19.899 19.899" android:pathData="m54,34.101a19.899,19.899 0,0 1,19.899 19.899"
android:strokeWidth="6.075" android:strokeWidth="6.075"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="@color/logo_grey"/> android:strokeColor="@color/logo_grey" />
</vector> </vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/badge_radius" /> <corners android:radius="@dimen/badge_radius" />
<solid android:color="@color/alert_inactive"/> <solid android:color="@color/alert_inactive" />
<size android:width="@dimen/badge_width" android:height="@dimen/badge_height" /> <size
android:width="@dimen/badge_width"
android:height="@dimen/badge_height" />
</shape> </shape>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp" android:width="24dp"
android:viewportWidth="24.0" android:height="24dp"
android:viewportHeight="24.0"> android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/> android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z" />
</vector> </vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp" android:width="24dp"
android:viewportWidth="24.0" android:height="24dp"
android:viewportHeight="24.0"> android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/> android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
</vector> </vector>
\ No newline at end of file
<vector android:height="24dp" android:viewportHeight="25" <vector
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:height="24dp"
<path android:fillColor="#FFF" android:viewportHeight="25"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FFF"
android:pathData=" android:pathData="
M20,4 M20,4
L4,4 L4,4
...@@ -29,5 +34,5 @@ ...@@ -29,5 +34,5 @@
L20,6 L20,6
L20.3,4 L20.3,4
L12,0z L12,0z
"/> " />
</vector> </vector>
\ No newline at end of file
<vector android:height="24dp" android:tint="#FFFFFF" <vector
android:viewportHeight="24.0" android:viewportWidth="24.0" android:height="24dp"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:tint="#FFFFFF"
<path android:fillColor="#FFF" android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8l8,5 8,-5v10zM12,11L4,6h16l-8,5z"/> android:viewportHeight="24.0"
</vector> android:viewportWidth="24.0"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FFF"
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8l8,5 8,-5v10zM12,11L4,6h16l-8,5z" />
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp" android:width="24dp"
android:viewportWidth="24.0" android:height="24dp"
android:viewportHeight="24.0"> android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/> android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z" />
</vector> </vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector