Merge branch 'dev' into feature/sync2

feature/sync2
Alinson S. Xavier 4 years ago
commit 370ddfb8db
No known key found for this signature in database
GPG Key ID: DCA0DAD4D2F58624

@ -18,8 +18,6 @@ allprojects {
mavenCentral() mavenCentral()
maven(url = "https://plugins.gradle.org/m2/") maven(url = "https://plugins.gradle.org/m2/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
maven(url = "https://kotlin.bintray.com/ktor")
maven(url = "https://kotlin.bintray.com/kotlin-js-wrappers")
maven(url = "https://jitpack.io") maven(url = "https://jitpack.io")
} }
} }

@ -18,7 +18,7 @@
*/ */
plugins { plugins {
id("com.github.triplet.play") version "3.6.0" id("com.github.triplet.play") version "3.7.0"
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.kapt") id("org.jetbrains.kotlin.kapt")
@ -32,13 +32,13 @@ tasks.compileLint {
android { android {
compileSdk = 30 compileSdk = 31
defaultConfig { defaultConfig {
versionCode = 20003 versionCode = 20003
versionName = "2.0.3" versionName = "2.0.3"
minSdk = 23 minSdk = 23
targetSdk = 30 targetSdk = 31
applicationId = "org.isoron.uhabits" applicationId = "org.isoron.uhabits"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@ -86,10 +86,10 @@ android {
} }
dependencies { dependencies {
val daggerVersion = "2.40" val daggerVersion = "2.40.3"
val kotlinVersion = "1.5.31" val kotlinVersion = "1.6.0"
val kxCoroutinesVersion = "1.5.2" val kxCoroutinesVersion = "1.5.2"
val ktorVersion = "1.6.4" val ktorVersion = "1.6.6"
val espressoVersion = "3.4.0" val espressoVersion = "3.4.0"
androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion")
@ -98,7 +98,7 @@ dependencies {
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito:2.28.1") androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito:2.28.1")
androidTestImplementation("io.ktor:ktor-client-mock:$ktorVersion") androidTestImplementation("io.ktor:ktor-client-mock:$ktorVersion")
androidTestImplementation("io.ktor:ktor-jackson:$ktorVersion") androidTestImplementation("io.ktor:ktor-jackson:$ktorVersion")
androidTestImplementation("androidx.annotation:annotation:1.2.0") androidTestImplementation("androidx.annotation:annotation:1.3.0")
androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0") androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
androidTestImplementation("androidx.test:rules:1.4.0") androidTestImplementation("androidx.test:rules:1.4.0")

@ -17,9 +17,10 @@
~ with this program. If not, see <http://www.gnu.org/licenses/>. ~ with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.isoron.uhabits"> package="org.isoron.uhabits">
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@ -48,11 +49,11 @@
android:name=".activities.habits.list.ListHabitsActivity" android:name=".activities.habits.list.ListHabitsActivity"
android:exported="true" android:exported="true"
android:label="@string/main_activity_title" android:label="@string/main_activity_title"
android:launchMode="singleTop"> android:launchMode="singleTop" />
</activity>
<activity-alias <activity-alias
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true"
android:label="@string/main_activity_title" android:label="@string/main_activity_title"
android:launchMode="singleTop" android:launchMode="singleTop"
android:targetActivity=".activities.habits.list.ListHabitsActivity"> android:targetActivity=".activities.habits.list.ListHabitsActivity">
@ -85,6 +86,7 @@
<activity <activity
android:name=".widgets.activities.HabitPickerDialog" android:name=".widgets.activities.HabitPickerDialog"
android:exported="true"
android:theme="@style/Theme.AppCompat.Light.Dialog"> android:theme="@style/Theme.AppCompat.Light.Dialog">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
@ -93,6 +95,7 @@
<activity <activity
android:name=".widgets.activities.BooleanHabitPickerDialog" android:name=".widgets.activities.BooleanHabitPickerDialog"
android:exported="true"
android:theme="@style/Theme.AppCompat.Light.Dialog"> android:theme="@style/Theme.AppCompat.Light.Dialog">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
@ -101,6 +104,7 @@
<activity <activity
android:name=".widgets.activities.NumericalHabitPickerDialog" android:name=".widgets.activities.NumericalHabitPickerDialog"
android:exported="true"
android:theme="@style/Theme.AppCompat.Light.Dialog"> android:theme="@style/Theme.AppCompat.Light.Dialog">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
@ -117,9 +121,10 @@
<activity <activity
android:name=".widgets.activities.NumericalCheckmarkWidgetActivity" android:name=".widgets.activities.NumericalCheckmarkWidgetActivity"
android:excludeFromRecents="true"
android:exported="true"
android:label="NumericalCheckmarkWidget" android:label="NumericalCheckmarkWidget"
android:noHistory="true" android:noHistory="true"
android:excludeFromRecents="true"
android:theme="@style/Theme.AppCompat.Light.Dialog"> android:theme="@style/Theme.AppCompat.Light.Dialog">
<intent-filter> <intent-filter>
<action android:name="org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY" /> <action android:name="org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY" />
@ -128,13 +133,14 @@
<activity <activity
android:name=".notifications.SnoozeDelayPickerActivity" android:name=".notifications.SnoozeDelayPickerActivity"
android:taskAffinity=""
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:taskAffinity=""
android:theme="@android:style/Theme.Translucent.NoTitleBar" /> android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<receiver <receiver
android:name=".widgets.CheckmarkWidgetProvider" android:name=".widgets.CheckmarkWidgetProvider"
android:exported="true"
android:label="@string/checkmark"> android:label="@string/checkmark">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -152,6 +158,7 @@
<receiver <receiver
android:name=".widgets.HistoryWidgetProvider" android:name=".widgets.HistoryWidgetProvider"
android:exported="true"
android:label="@string/history"> android:label="@string/history">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -164,6 +171,7 @@
<receiver <receiver
android:name=".widgets.ScoreWidgetProvider" android:name=".widgets.ScoreWidgetProvider"
android:exported="true"
android:label="@string/score"> android:label="@string/score">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -176,6 +184,7 @@
<receiver <receiver
android:name=".widgets.StreakWidgetProvider" android:name=".widgets.StreakWidgetProvider"
android:exported="true"
android:label="@string/streaks"> android:label="@string/streaks">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -188,6 +197,7 @@
<receiver <receiver
android:name=".widgets.FrequencyWidgetProvider" android:name=".widgets.FrequencyWidgetProvider"
android:exported="true"
android:label="@string/frequency"> android:label="@string/frequency">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -200,6 +210,7 @@
<receiver <receiver
android:name=".widgets.TargetWidgetProvider" android:name=".widgets.TargetWidgetProvider"
android:exported="true"
android:label="@string/target"> android:label="@string/target">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -210,13 +221,17 @@
android:resource="@xml/widget_target_info" /> android:resource="@xml/widget_target_info" />
</receiver> </receiver>
<receiver android:name=".receivers.ReminderReceiver"> <receiver
android:name=".receivers.ReminderReceiver"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".receivers.WidgetReceiver"> <receiver android:name=".receivers.WidgetReceiver"
android:exported="true"
android:permission="false">
<intent-filter> <intent-filter>
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<action android:name="org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE" /> <action android:name="org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE" />
@ -267,7 +282,7 @@
<!-- Locale/Tasker --> <!-- Locale/Tasker -->
<receiver <receiver
android:name=".automation.FireSettingReceiver" android:name=".automation.FireSettingReceiver"
android:exported="true"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" /> <action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" />
</intent-filter> </intent-filter>

@ -25,8 +25,6 @@ import android.app.AlarmManager.RTC_WAKEUP
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Context.ALARM_SERVICE import android.content.Context.ALARM_SERVICE
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.M
import android.util.Log import android.util.Log
import org.isoron.uhabits.core.AppScope import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
@ -58,10 +56,7 @@ class IntentScheduler
) )
return SchedulerResult.IGNORED return SchedulerResult.IGNORED
} }
if (SDK_INT >= M) manager.setExactAndAllowWhileIdle(alarmType, timestamp, intent)
manager.setExactAndAllowWhileIdle(alarmType, timestamp, intent)
else
manager.setExact(alarmType, timestamp, intent)
return SchedulerResult.OK return SchedulerResult.OK
} }

@ -20,6 +20,7 @@
package org.isoron.uhabits.intents package org.isoron.uhabits.intents
import android.app.PendingIntent import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.PendingIntent.getBroadcast import android.app.PendingIntent.getBroadcast
import android.content.Context import android.content.Context
@ -49,7 +50,7 @@ class PendingIntentFactory
action = WidgetReceiver.ACTION_ADD_REPETITION action = WidgetReceiver.ACTION_ADD_REPETITION
if (timestamp != null) putExtra("timestamp", timestamp.unixTime) if (timestamp != null) putExtra("timestamp", timestamp.unixTime)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun dismissNotification(habit: Habit): PendingIntent = fun dismissNotification(habit: Habit): PendingIntent =
@ -60,7 +61,7 @@ class PendingIntentFactory
action = WidgetReceiver.ACTION_DISMISS_REMINDER action = WidgetReceiver.ACTION_DISMISS_REMINDER
data = Uri.parse(habit.uriString) data = Uri.parse(habit.uriString)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun removeRepetition(habit: Habit, timestamp: Timestamp?): PendingIntent = fun removeRepetition(habit: Habit, timestamp: Timestamp?): PendingIntent =
@ -72,7 +73,7 @@ class PendingIntentFactory
data = Uri.parse(habit.uriString) data = Uri.parse(habit.uriString)
if (timestamp != null) putExtra("timestamp", timestamp.unixTime) if (timestamp != null) putExtra("timestamp", timestamp.unixTime)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun showHabit(habit: Habit): PendingIntent = fun showHabit(habit: Habit): PendingIntent =
@ -84,7 +85,7 @@ class PendingIntentFactory
habit habit
) )
) )
.getPendingIntent(0, FLAG_UPDATE_CURRENT)!! .getPendingIntent(0, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)!!
fun showReminder( fun showReminder(
habit: Habit, habit: Habit,
@ -100,7 +101,7 @@ class PendingIntentFactory
putExtra("timestamp", timestamp) putExtra("timestamp", timestamp)
putExtra("reminderTime", reminderTime) putExtra("reminderTime", reminderTime)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun snoozeNotification(habit: Habit): PendingIntent = fun snoozeNotification(habit: Habit): PendingIntent =
@ -111,7 +112,7 @@ class PendingIntentFactory
data = Uri.parse(habit.uriString) data = Uri.parse(habit.uriString)
action = ReminderReceiver.ACTION_SNOOZE_REMINDER action = ReminderReceiver.ACTION_SNOOZE_REMINDER
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun toggleCheckmark(habit: Habit, timestamp: Long?): PendingIntent = fun toggleCheckmark(habit: Habit, timestamp: Long?): PendingIntent =
@ -123,7 +124,7 @@ class PendingIntentFactory
action = WidgetReceiver.ACTION_TOGGLE_REPETITION action = WidgetReceiver.ACTION_TOGGLE_REPETITION
if (timestamp != null) putExtra("timestamp", timestamp) if (timestamp != null) putExtra("timestamp", timestamp)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun setNumericalValue( fun setNumericalValue(
@ -142,7 +143,7 @@ class PendingIntentFactory
putExtra("numericalValue", numericalValue) putExtra("numericalValue", numericalValue)
if (timestamp != null) putExtra("timestamp", timestamp) if (timestamp != null) putExtra("timestamp", timestamp)
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
fun updateWidgets(): PendingIntent = fun updateWidgets(): PendingIntent =
@ -152,6 +153,6 @@ class PendingIntentFactory
Intent(context, WidgetReceiver::class.java).apply { Intent(context, WidgetReceiver::class.java).apply {
action = WidgetReceiver.ACTION_UPDATE_WIDGETS_VALUE action = WidgetReceiver.ACTION_UPDATE_WIDGETS_VALUE
}, },
FLAG_UPDATE_CURRENT FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
) )
} }

@ -153,13 +153,15 @@ class AndroidNotificationTray
if (preferences.shouldMakeNotificationsLed()) if (preferences.shouldMakeNotificationsLed())
builder.setLights(Color.RED, 1000, 1000) builder.setLights(Color.RED, 1000, 1000)
val snoozeAction = Action( if (SDK_INT < Build.VERSION_CODES.S) {
R.drawable.ic_action_snooze, val snoozeAction = Action(
context.getString(R.string.snooze), R.drawable.ic_action_snooze,
pendingIntents.snoozeNotification(habit) context.getString(R.string.snooze),
) pendingIntents.snoozeNotification(habit)
wearableExtender.addAction(snoozeAction) )
builder.addAction(snoozeAction) wearableExtender.addAction(snoozeAction)
builder.addAction(snoozeAction)
}
builder.extend(wearableExtender) builder.extend(wearableExtender)
return builder.build() return builder.build()

@ -22,6 +22,8 @@ import android.content.BroadcastReceiver
import android.content.ContentUris import android.content.ContentUris
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.util.Log import android.util.Log
import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
@ -76,8 +78,21 @@ class ReminderReceiver : BroadcastReceiver() {
} }
ACTION_SNOOZE_REMINDER -> { ACTION_SNOOZE_REMINDER -> {
if (habit == null) return if (habit == null) return
Log.d("ReminderReceiver", String.format("onSnoozePressed habit=%d", habit.id)) if (SDK_INT < Build.VERSION_CODES.S) {
reminderController.onSnoozePressed(habit, context) Log.d(
"ReminderReceiver",
String.format("onSnoozePressed habit=%d", habit.id)
)
reminderController.onSnoozePressed(habit, context)
} else {
Log.w(
"ReminderReceiver",
String.format(
"onSnoozePressed habit=%d, should be deactivated in recent versions.",
habit.id
)
)
}
} }
Intent.ACTION_BOOT_COMPLETED -> { Intent.ACTION_BOOT_COMPLETED -> {
Log.d("ReminderReceiver", "onBootCompleted") Log.d("ReminderReceiver", "onBootCompleted")

@ -43,11 +43,11 @@ kotlin {
val jvmMain by getting { val jvmMain by getting {
dependencies { dependencies {
implementation(kotlin("stdlib-jdk8")) implementation(kotlin("stdlib-jdk8"))
compileOnly("com.google.dagger:dagger:2.40") compileOnly("com.google.dagger:dagger:2.40.3")
implementation("com.google.guava:guava:31.0.1-android") implementation("com.google.guava:guava:31.0.1-android")
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.31") implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2")
implementation("androidx.annotation:annotation:1.2.0") implementation("androidx.annotation:annotation:1.3.0")
implementation("com.google.code.findbugs:jsr305:3.0.2") implementation("com.google.code.findbugs:jsr305:3.0.2")
implementation("com.opencsv:opencsv:5.5.2") implementation("com.opencsv:opencsv:5.5.2")
implementation("commons-codec:commons-codec:1.15") implementation("commons-codec:commons-codec:1.15")

@ -23,13 +23,11 @@ import org.isoron.uhabits.core.commands.Command
import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.commands.DeleteHabitsCommand import org.isoron.uhabits.core.commands.DeleteHabitsCommand
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.tasks.Task import org.isoron.uhabits.core.tasks.Task
import org.isoron.uhabits.core.tasks.TaskRunner import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
import java.util.HashMap import java.util.HashMap
import java.util.Locale import java.util.Locale
import java.util.Objects import java.util.Objects
@ -106,17 +104,17 @@ class NotificationTray @Inject constructor(
internal class NotificationData(val timestamp: Timestamp, val reminderTime: Long) internal class NotificationData(val timestamp: Timestamp, val reminderTime: Long)
private inner class ShowNotificationTask(private val habit: Habit, data: NotificationData) : private inner class ShowNotificationTask(private val habit: Habit, data: NotificationData) :
Task { Task {
var todayValue = 0 var isCompleted = false
private val timestamp: Timestamp = data.timestamp private val timestamp: Timestamp = data.timestamp
private val reminderTime: Long = data.reminderTime private val reminderTime: Long = data.reminderTime
override fun doInBackground() { override fun doInBackground() {
val today = getTodayWithOffset() isCompleted = habit.isCompletedToday()
todayValue = habit.computedEntries.get(today).value
} }
override fun onPostExecute() { override fun onPostExecute() {
systemTray.log("Showing notification for habit=" + habit.id) systemTray.log("Showing notification for habit=" + habit.id)
if (todayValue != Entry.UNKNOWN) { if (isCompleted) {
systemTray.log( systemTray.log(
String.format( String.format(
Locale.US, Locale.US,

@ -33,9 +33,9 @@ application {
} }
dependencies { dependencies {
val ktorVersion = "1.6.4" val ktorVersion = "1.6.6"
val kotlinVersion = "1.5.31" val kotlinVersion = "1.6.0"
val logbackVersion = "1.2.6" val logbackVersion = "1.2.7"
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("io.ktor:ktor-server-netty:$ktorVersion") implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logbackVersion") implementation("ch.qos.logback:logback-classic:$logbackVersion")

Loading…
Cancel
Save