diff --git a/app/build.gradle b/app/build.gradle index 8809e4b0a..028a779ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,10 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' -apply plugin: 'witness' -apply from: 'witness.gradle' +apply plugin: 'com.android.legacy-kapt' android { + namespace "de.grobox.transportr" defaultConfig { versionCode 131 @@ -13,7 +12,7 @@ android { applicationId "de.grobox.liberario" minSdkVersion 24 - compileSdk 33 + compileSdk 34 targetSdkVersion 34 testInstrumentationRunner 'de.grobox.transportr.MockTestRunner' @@ -24,12 +23,17 @@ android { } } + buildFeatures { + buildConfig true + viewBinding true + } + buildTypes { release { resValue "string", "app_name", "Transportr" shrinkResources true minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt' } debug { @@ -38,8 +42,8 @@ android { resValue "string", "app_name", "Transportr Devel" shrinkResources false minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-test.txt' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt' + testProguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt', 'proguard-test.txt' lintOptions { disable 'ProtectedPermissions' @@ -52,11 +56,6 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 } - dexOptions { - preDexLibraries !project.hasProperty('buildServer') - javaMaxHeapSize "1g" - } - sourceSets { androidTest { assets.srcDirs += files("$projectDir/schemas".toString()) @@ -87,7 +86,7 @@ android { buildTypes.release.signingConfig = null } - lintOptions { + lint { checkReleaseBuilds false disable 'MissingTranslation', // don't put too much pressure on Transifex contributors 'InvalidPackage', @@ -138,12 +137,8 @@ dependencies { implementation "com.google.dagger:dagger:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion" - implementation('com.google.guava:guava:29.0-android') { - exclude module: 'failureaccess' - exclude group: 'com.google.j2objc' - } - implementation('com.gitlab.opentransitmap:public-transport-enabler:09b90d37bfe452f7845f73aac256fd7eb2ae978a') { - exclude group: 'com.google.guava' // included above + implementation("org.jspecify:jspecify:1.0.0") + implementation('com.gitlab.opentransitmap:public-transport-enabler:1b2afb8f0224ed6d2461cf2c8e5a4a83f7fa20f6') { exclude group: 'org.json', module: 'json' // provided by Android exclude group: 'net.sf.kxml', module: 'kxml2' // provided by Android exclude group: 'org.slf4j', module: 'slf4j-api' // v. 2.0.16 broken diff --git a/app/libs/gradle-witness.jar b/app/libs/gradle-witness.jar deleted file mode 100644 index eeb8b2286..000000000 Binary files a/app/libs/gradle-witness.jar and /dev/null differ diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt index cca60dbe4..68c9dc7ae 100644 --- a/app/proguard-rules.txt +++ b/app/proguard-rules.txt @@ -1,3 +1,5 @@ +# todo: try to disable and test for breakages +-dontoptimize -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml index 29d7e635c..55829b4c4 100644 --- a/app/src/debug/AndroidManifest.xml +++ b/app/src/debug/AndroidManifest.xml @@ -1,6 +1,5 @@ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1da81a4dd..1e0c4bfb7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ diff --git a/app/src/main/java/de/grobox/transportr/TransportrFragment.java b/app/src/main/java/de/grobox/transportr/TransportrFragment.java index d04539608..15c5b3399 100644 --- a/app/src/main/java/de/grobox/transportr/TransportrFragment.java +++ b/app/src/main/java/de/grobox/transportr/TransportrFragment.java @@ -25,10 +25,10 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.Toolbar; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; -@ParametersAreNonnullByDefault +@NullMarked public abstract class TransportrFragment extends Fragment { protected AppComponent getComponent() { diff --git a/app/src/main/java/de/grobox/transportr/ViewModelFactory.java b/app/src/main/java/de/grobox/transportr/ViewModelFactory.java index 795437093..4341039cb 100644 --- a/app/src/main/java/de/grobox/transportr/ViewModelFactory.java +++ b/app/src/main/java/de/grobox/transportr/ViewModelFactory.java @@ -22,13 +22,13 @@ import java.util.Map; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import javax.inject.Inject; import javax.inject.Provider; import javax.inject.Singleton; @Singleton -@ParametersAreNonnullByDefault +@NullMarked public class ViewModelFactory implements ViewModelProvider.Factory { private final Map, Provider> creators; diff --git a/app/src/main/java/de/grobox/transportr/about/AboutActivity.kt b/app/src/main/java/de/grobox/transportr/about/AboutActivity.kt index f1329c022..e8cb92236 100644 --- a/app/src/main/java/de/grobox/transportr/about/AboutActivity.kt +++ b/app/src/main/java/de/grobox/transportr/about/AboutActivity.kt @@ -26,7 +26,7 @@ import androidx.fragment.app.FragmentPagerAdapter import com.mikepenz.aboutlibraries.LibsBuilder import de.grobox.transportr.R import de.grobox.transportr.TransportrActivity -import kotlinx.android.synthetic.main.activity_about.* +import de.grobox.transportr.databinding.ActivityAboutBinding class AboutActivity : TransportrActivity() { @@ -35,13 +35,17 @@ class AboutActivity : TransportrActivity() { val TAG : String = AboutActivity::class.java.simpleName } - public override fun onCreate(savedInstanceState: Bundle?) { + private lateinit var binding: ActivityAboutBinding + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_about) + binding = ActivityAboutBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) setUpCustomToolbar(false) - pager.adapter = AboutPagerAdapter(supportFragmentManager) - tabLayout.setupWithViewPager(pager) + binding.pager.adapter = AboutPagerAdapter(supportFragmentManager) + binding.tabLayout.setupWithViewPager(binding.pager) } private inner class AboutPagerAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm) { diff --git a/app/src/main/java/de/grobox/transportr/about/ContributorsActivity.kt b/app/src/main/java/de/grobox/transportr/about/ContributorsActivity.kt index ed3902cfd..7c02e2fd9 100644 --- a/app/src/main/java/de/grobox/transportr/about/ContributorsActivity.kt +++ b/app/src/main/java/de/grobox/transportr/about/ContributorsActivity.kt @@ -25,7 +25,7 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import de.grobox.transportr.R import de.grobox.transportr.TransportrActivity -import kotlinx.android.synthetic.main.activity_about.* +import de.grobox.transportr.databinding.ActivityAboutBinding class ContributorsActivity : TransportrActivity() { @@ -34,13 +34,17 @@ class ContributorsActivity : TransportrActivity() { val TAG : String = ContributorsActivity::class.java.simpleName } - public override fun onCreate(savedInstanceState: Bundle?) { + private lateinit var binding: ActivityAboutBinding + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_about) + binding = ActivityAboutBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) setUpCustomToolbar(false) - pager.adapter = ContributorsPagerAdapter(supportFragmentManager) - tabLayout.setupWithViewPager(pager) + binding.pager.adapter = ContributorsPagerAdapter(supportFragmentManager) + binding.tabLayout.setupWithViewPager(binding.pager) } private inner class ContributorsPagerAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm) { diff --git a/app/src/main/java/de/grobox/transportr/departures/DepartureAdapter.java b/app/src/main/java/de/grobox/transportr/departures/DepartureAdapter.java index 0a4bb1fec..51e226a25 100644 --- a/app/src/main/java/de/grobox/transportr/departures/DepartureAdapter.java +++ b/app/src/main/java/de/grobox/transportr/departures/DepartureAdapter.java @@ -30,6 +30,7 @@ import java.util.Date; import de.grobox.transportr.R; +import de.grobox.transportr.databinding.ListItemDepartureBinding; import de.schildbach.pte.dto.Departure; class DepartureAdapter extends RecyclerView.Adapter { @@ -74,8 +75,8 @@ public boolean areContentsTheSame(Departure d1, Departure d2) { @NonNull @Override public DepartureViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { - View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_departure, viewGroup, false); - return new DepartureViewHolder(v); + ListItemDepartureBinding binding = ListItemDepartureBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false); + return new DepartureViewHolder(binding); } @Override diff --git a/app/src/main/java/de/grobox/transportr/departures/DepartureViewHolder.kt b/app/src/main/java/de/grobox/transportr/departures/DepartureViewHolder.kt index e1afa19b0..599b9b8ea 100644 --- a/app/src/main/java/de/grobox/transportr/departures/DepartureViewHolder.kt +++ b/app/src/main/java/de/grobox/transportr/departures/DepartureViewHolder.kt @@ -27,6 +27,7 @@ import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import de.grobox.transportr.R +import de.grobox.transportr.databinding.ListItemDepartureBinding import de.grobox.transportr.ui.LineView import de.grobox.transportr.utils.DateUtils.formatDelay import de.grobox.transportr.utils.DateUtils.formatTime @@ -34,20 +35,19 @@ import de.grobox.transportr.utils.DateUtils.formatRelativeTime import de.grobox.transportr.utils.TransportrUtils.getLineColor import de.grobox.transportr.utils.TransportrUtils.getLocationName import de.schildbach.pte.dto.Departure -import kotlinx.android.synthetic.main.list_item_departure.view.* import java.util.* -internal class DepartureViewHolder(v: View) : RecyclerView.ViewHolder(v) { +internal class DepartureViewHolder(binding: ListItemDepartureBinding) : RecyclerView.ViewHolder(binding.root) { - private val card: CardView = v as CardView - private val line: LineView = v.line - private val lineName: TextView = v.lineNameView - private val timeRel: TextView = v.departureTimeRel - private val timeAbs: TextView = v.departureTimeAbs - private val delay: TextView = v.delay - private val destination: TextView = v.destinationView - private val position: TextView = v.positionView - private val message: TextView = v.messageView + private val card: CardView = binding.root as CardView + private val line: LineView = binding.line + private val lineName: TextView = binding.lineNameView + private val timeRel: TextView = binding.departureTimeRel + private val timeAbs: TextView = binding.departureTimeAbs + private val delay: TextView = binding.delay + private val destination: TextView = binding.destinationView + private val position: TextView = binding.positionView + private val message: TextView = binding.messageView fun bind(dep: Departure) { // times and delay diff --git a/app/src/main/java/de/grobox/transportr/departures/DeparturesActivity.java b/app/src/main/java/de/grobox/transportr/departures/DeparturesActivity.java index 13ea7a699..a6084d2bd 100644 --- a/app/src/main/java/de/grobox/transportr/departures/DeparturesActivity.java +++ b/app/src/main/java/de/grobox/transportr/departures/DeparturesActivity.java @@ -47,7 +47,7 @@ import java.util.Date; import java.util.List; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import de.grobox.transportr.R; import de.grobox.transportr.TransportrActivity; @@ -68,7 +68,7 @@ import static de.grobox.transportr.utils.TransportrUtils.getDragDistance; import static de.schildbach.pte.dto.QueryDeparturesResult.Status.OK; -@ParametersAreNonnullByDefault +@NullMarked public class DeparturesActivity extends TransportrActivity implements LoaderCallbacks, TimeDateListener { diff --git a/app/src/main/java/de/grobox/transportr/favorites/locations/SpecialLocationFragment.kt b/app/src/main/java/de/grobox/transportr/favorites/locations/SpecialLocationFragment.kt index c32d4e169..a579973e7 100644 --- a/app/src/main/java/de/grobox/transportr/favorites/locations/SpecialLocationFragment.kt +++ b/app/src/main/java/de/grobox/transportr/favorites/locations/SpecialLocationFragment.kt @@ -40,10 +40,10 @@ import de.grobox.transportr.locations.LocationView import de.grobox.transportr.locations.LocationsViewModel import de.grobox.transportr.locations.WrapLocation import de.grobox.transportr.settings.SettingsManager -import javax.annotation.ParametersAreNonnullByDefault +import org.jspecify.annotations.NullMarked import javax.inject.Inject -@ParametersAreNonnullByDefault +@NullMarked abstract class SpecialLocationFragment : DialogFragment(), LocationView.LocationViewListener { @Inject diff --git a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripAdapter.java b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripAdapter.java index 8e6b02bf2..e95825dbd 100644 --- a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripAdapter.java +++ b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripAdapter.java @@ -30,7 +30,7 @@ import java.util.Collection; import java.util.List; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import de.grobox.transportr.R; @@ -38,7 +38,7 @@ import static de.grobox.transportr.favorites.trips.FavoriteTripType.HOME; import static de.grobox.transportr.favorites.trips.FavoriteTripType.WORK; -@ParametersAreNonnullByDefault +@NullMarked class FavoriteTripAdapter extends RecyclerView.Adapter { private final SortedList items = new SortedList<>(FavoriteTripItem.class, new SortedList.Callback() { diff --git a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripItem.java b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripItem.java index 3149a4a96..e3937c4fe 100644 --- a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripItem.java +++ b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripItem.java @@ -21,11 +21,10 @@ import androidx.annotation.Nullable; -import com.google.common.base.Objects; +import org.jspecify.annotations.NullMarked; import java.util.Date; - -import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Objects; import de.grobox.transportr.data.locations.HomeLocation; import de.grobox.transportr.data.locations.WorkLocation; @@ -37,7 +36,7 @@ import static de.grobox.transportr.favorites.trips.FavoriteTripType.WORK; import static de.grobox.transportr.locations.WrapLocation.WrapType.GPS; -@ParametersAreNonnullByDefault +@NullMarked public class FavoriteTripItem extends StoredSearch implements Comparable { private final FavoriteTripType type; @@ -133,13 +132,13 @@ boolean equalsAllFields(Object o) { if (!(o instanceof FavoriteTripItem)) return false; final FavoriteTripItem other = (FavoriteTripItem) o; - if (!Objects.equal(this.type, other.type)) + if (!Objects.equals(this.type, other.type)) return false; - if (!Objects.equal(this.from, other.from)) + if (!Objects.equals(this.from, other.from)) return false; - if (!Objects.equal(this.to, other.to)) + if (!Objects.equals(this.to, other.to)) return false; - if (!Objects.equal(this.via, other.via)) + if (!Objects.equals(this.via, other.via)) return false; if (this.count != other.count) return false; diff --git a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripListener.java b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripListener.java index c3cac3ad6..a339cbaa1 100644 --- a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripListener.java +++ b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripListener.java @@ -19,9 +19,9 @@ package de.grobox.transportr.favorites.trips; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; -@ParametersAreNonnullByDefault +@NullMarked public interface FavoriteTripListener { void onFavoriteClicked(FavoriteTripItem item); diff --git a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripsFragment.java b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripsFragment.java index 708e35db0..ae824ef57 100644 --- a/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripsFragment.java +++ b/app/src/main/java/de/grobox/transportr/favorites/trips/FavoriteTripsFragment.java @@ -28,7 +28,7 @@ import java.util.List; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import javax.inject.Inject; import androidx.annotation.NonNull; @@ -51,7 +51,7 @@ import static de.grobox.transportr.favorites.trips.FavoriteTripType.WORK; import static de.grobox.transportr.utils.IntentUtils.findDirections; -@ParametersAreNonnullByDefault +@NullMarked public abstract class FavoriteTripsFragment extends TransportrFragment implements FavoriteTripListener { @Inject protected ViewModelProvider.Factory viewModelFactory; diff --git a/app/src/main/java/de/grobox/transportr/locations/LineAdapter.kt b/app/src/main/java/de/grobox/transportr/locations/LineAdapter.kt index f77a7cee2..d2ef96b46 100644 --- a/app/src/main/java/de/grobox/transportr/locations/LineAdapter.kt +++ b/app/src/main/java/de/grobox/transportr/locations/LineAdapter.kt @@ -23,6 +23,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import de.grobox.transportr.R +import de.grobox.transportr.databinding.ListItemLineBinding import de.grobox.transportr.ui.LineView import de.grobox.transportr.utils.TransportrUtils import de.schildbach.pte.dto.Line @@ -33,8 +34,8 @@ internal class LineAdapter : RecyclerView.Adapter() { private var lines: List = emptyList() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LineViewHolder { - val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item_line, parent, false) as LineView - return LineViewHolder(v) + val binding = ListItemLineBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return LineViewHolder(binding.root) } override fun onBindViewHolder(holder: LineViewHolder, position: Int) { diff --git a/app/src/main/java/de/grobox/transportr/locations/LocationAdapter.java b/app/src/main/java/de/grobox/transportr/locations/LocationAdapter.java index 950086109..e863f952e 100644 --- a/app/src/main/java/de/grobox/transportr/locations/LocationAdapter.java +++ b/app/src/main/java/de/grobox/transportr/locations/LocationAdapter.java @@ -37,7 +37,7 @@ import java.util.List; import java.util.regex.Pattern; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -55,7 +55,7 @@ import static de.grobox.transportr.locations.WrapLocation.WrapType.GPS; import static de.grobox.transportr.locations.WrapLocation.WrapType.NORMAL; -@ParametersAreNonnullByDefault +@NullMarked class LocationAdapter extends ArrayAdapter implements Filterable { private @Nullable HomeLocation homeLocation; diff --git a/app/src/main/java/de/grobox/transportr/locations/LocationFragment.java b/app/src/main/java/de/grobox/transportr/locations/LocationFragment.java index 511577790..93bd1743e 100644 --- a/app/src/main/java/de/grobox/transportr/locations/LocationFragment.java +++ b/app/src/main/java/de/grobox/transportr/locations/LocationFragment.java @@ -30,6 +30,8 @@ import androidx.loader.content.Loader; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -45,7 +47,7 @@ import java.util.SortedSet; import java.util.TreeSet; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import javax.inject.Inject; import de.grobox.transportr.R; @@ -66,7 +68,6 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static androidx.recyclerview.widget.RecyclerView.HORIZONTAL; -import static com.google.common.base.Strings.isNullOrEmpty; import static de.grobox.transportr.departures.DeparturesActivity.MAX_DEPARTURES; import static de.grobox.transportr.departures.DeparturesLoader.getBundle; import static de.grobox.transportr.utils.Constants.LOADER_DEPARTURES; @@ -75,7 +76,7 @@ import static de.schildbach.pte.dto.LocationType.COORD; import static de.schildbach.pte.dto.QueryDeparturesResult.Status.OK; -@ParametersAreNonnullByDefault +@NullMarked public class LocationFragment extends TransportrFragment implements LoaderCallbacks, ReverseGeocoderCallback, OnGlobalLayoutListener { @@ -191,7 +192,7 @@ private void showLocation() { locationName.setText(location.getName()); locationIcon.setImageDrawable(ContextCompat.getDrawable(getContext(), location.getDrawable())); StringBuilder locationInfoStr = new StringBuilder(); - if (!isNullOrEmpty(location.getLocation().place)) { + if (!TextUtils.isEmpty(location.getLocation().place)) { locationInfoStr.append(location.getLocation().place); } if (location.getLocation().hasCoord()) { diff --git a/app/src/main/java/de/grobox/transportr/locations/LocationView.kt b/app/src/main/java/de/grobox/transportr/locations/LocationView.kt index 99e0f9715..75c614564 100644 --- a/app/src/main/java/de/grobox/transportr/locations/LocationView.kt +++ b/app/src/main/java/de/grobox/transportr/locations/LocationView.kt @@ -25,9 +25,6 @@ import android.content.Context.LAYOUT_INFLATER_SERVICE import android.os.AsyncTask.Status.FINISHED import android.os.Bundle import android.os.Parcelable -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.core.view.ViewCompat import android.text.Editable import android.text.TextWatcher import android.util.AttributeSet @@ -35,10 +32,11 @@ import android.util.Log import android.util.SparseArray import android.view.LayoutInflater import android.view.View -import android.view.View.OnFocusChangeListener import android.view.inputmethod.InputMethodManager import android.widget.* -import com.google.common.base.Strings.isNullOrEmpty +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.core.view.ViewCompat import de.grobox.transportr.R import de.grobox.transportr.data.locations.FavoriteLocation import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType @@ -65,7 +63,7 @@ open class LocationView @JvmOverloads constructor(context: Context, attrs: Attri private var transportNetwork: TransportNetwork? = null private var location: WrapLocation? = null private var suggestLocationsTaskPending = false - protected val ui: LocationViewHolder + val ui: LocationViewHolder protected var listener: LocationViewListener? = null protected val hint: String? @@ -137,7 +135,7 @@ open class LocationView @JvmOverloads constructor(context: Context, attrs: Attri }) } - protected class LocationViewHolder internal constructor(view: View) { + class LocationViewHolder internal constructor(view: View) { val status: ImageView = view.findViewById(R.id.statusButton) val location: AutoCompleteTextView = view.findViewById(R.id.location) internal val progress: ProgressBar = view.findViewById(R.id.progress) @@ -164,7 +162,7 @@ open class LocationView @JvmOverloads constructor(context: Context, attrs: Attri val text = state.getString(TEXT) if (loc != null) { setLocation(loc) - } else if (!isNullOrEmpty(text)) { + } else if (!text.isNullOrEmpty()) { ui.location.setText(text) ui.clear.visibility = VISIBLE } diff --git a/app/src/main/java/de/grobox/transportr/locations/ReverseGeocoder.kt b/app/src/main/java/de/grobox/transportr/locations/ReverseGeocoder.kt index a6e4ba124..866d98bee 100644 --- a/app/src/main/java/de/grobox/transportr/locations/ReverseGeocoder.kt +++ b/app/src/main/java/de/grobox/transportr/locations/ReverseGeocoder.kt @@ -103,7 +103,7 @@ class ReverseGeocoder(private val context: Context, private val callback: Revers @Throws(IOException::class) override fun onResponse(call: Call, response: Response) { - val body = response.body + val body = response.body() if (!response.isSuccessful || body == null) { callback.onLocationRetrieved(getWrapLocation(lat, lon)) return diff --git a/app/src/main/java/de/grobox/transportr/locations/SuggestLocationsTask.java b/app/src/main/java/de/grobox/transportr/locations/SuggestLocationsTask.java index fd32e8118..f9c7d123b 100644 --- a/app/src/main/java/de/grobox/transportr/locations/SuggestLocationsTask.java +++ b/app/src/main/java/de/grobox/transportr/locations/SuggestLocationsTask.java @@ -22,13 +22,13 @@ import android.os.AsyncTask; import androidx.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import de.grobox.transportr.networks.TransportNetwork; import de.schildbach.pte.NetworkProvider; import de.schildbach.pte.dto.SuggestLocationsResult; -@ParametersAreNonnullByDefault +@NullMarked class SuggestLocationsTask extends AsyncTask { private final TransportNetwork network; diff --git a/app/src/main/java/de/grobox/transportr/locations/WrapLocation.java b/app/src/main/java/de/grobox/transportr/locations/WrapLocation.java index 03a2e497e..50bc05522 100644 --- a/app/src/main/java/de/grobox/transportr/locations/WrapLocation.java +++ b/app/src/main/java/de/grobox/transportr/locations/WrapLocation.java @@ -19,7 +19,8 @@ package de.grobox.transportr.locations; -import com.google.common.base.Strings; +import android.text.TextUtils; + import com.mapbox.mapboxsdk.geometry.LatLng; import java.io.Serializable; @@ -35,10 +36,10 @@ import de.schildbach.pte.dto.Point; import de.schildbach.pte.dto.Product; -import static com.google.common.base.Preconditions.checkArgument; import static de.grobox.transportr.locations.WrapLocation.WrapType.NORMAL; import static de.schildbach.pte.dto.LocationType.ANY; import static de.schildbach.pte.dto.LocationType.COORD; +import static de.schildbach.pte.util.Preconditions.checkArgument; public class WrapLocation implements Serializable { @@ -70,7 +71,7 @@ public WrapLocation(Location l) { } public WrapLocation(WrapType wrapType) { - checkArgument(wrapType != NORMAL, "Type can't be normal"); + checkArgument(wrapType != NORMAL, () -> "Type can't be normal"); this.wrapType = wrapType; this.type = ANY; } @@ -80,7 +81,7 @@ public WrapLocation(LatLng latLng) { this.type = COORD; this.lat = (int) (latLng.getLatitude() * 1E6); this.lon = (int) (latLng.getLongitude() * 1E6); - checkArgument(lat != 0 || lon != 0, "Null Island is not a valid location"); + checkArgument(lat != 0 || lon != 0, () -> "Null Island is not a valid location"); } public WrapType getWrapType() { @@ -101,7 +102,7 @@ public String getId() { } public boolean hasId() { - return !Strings.isNullOrEmpty(id); + return !TextUtils.isEmpty(id); } public final boolean hasLocation() { diff --git a/app/src/main/java/de/grobox/transportr/map/MapActivity.java b/app/src/main/java/de/grobox/transportr/map/MapActivity.java index 9babaa9a8..ea585847d 100644 --- a/app/src/main/java/de/grobox/transportr/map/MapActivity.java +++ b/app/src/main/java/de/grobox/transportr/map/MapActivity.java @@ -31,7 +31,7 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.mapbox.mapboxsdk.geometry.LatLng; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import javax.inject.Inject; import androidx.annotation.NonNull; @@ -60,7 +60,7 @@ import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED; import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FOCAL_PRESSED; -@ParametersAreNonnullByDefault +@NullMarked public class MapActivity extends DrawerActivity implements LocationViewListener { @Inject ViewModelProvider.Factory viewModelFactory; diff --git a/app/src/main/java/de/grobox/transportr/networks/Continent.kt b/app/src/main/java/de/grobox/transportr/networks/Continent.kt index 8520a5c65..42878715f 100644 --- a/app/src/main/java/de/grobox/transportr/networks/Continent.kt +++ b/app/src/main/java/de/grobox/transportr/networks/Continent.kt @@ -22,9 +22,7 @@ package de.grobox.transportr.networks import android.content.Context import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import javax.annotation.concurrent.Immutable -@Immutable internal class Continent constructor( @param:StringRes @field:StringRes @get:StringRes val name: Int, @param:DrawableRes @field:DrawableRes @get:DrawableRes val contour: Int, diff --git a/app/src/main/java/de/grobox/transportr/networks/Country.kt b/app/src/main/java/de/grobox/transportr/networks/Country.kt index 57ff7cd6c..5f858db18 100644 --- a/app/src/main/java/de/grobox/transportr/networks/Country.kt +++ b/app/src/main/java/de/grobox/transportr/networks/Country.kt @@ -21,9 +21,7 @@ package de.grobox.transportr.networks import android.content.Context import androidx.annotation.StringRes -import javax.annotation.concurrent.Immutable -@Immutable internal class Country constructor( @param:StringRes @field:StringRes @get:StringRes val name: Int, val flag: String, diff --git a/app/src/main/java/de/grobox/transportr/networks/TransportNetwork.kt b/app/src/main/java/de/grobox/transportr/networks/TransportNetwork.kt index afe0ca744..be803e28d 100644 --- a/app/src/main/java/de/grobox/transportr/networks/TransportNetwork.kt +++ b/app/src/main/java/de/grobox/transportr/networks/TransportNetwork.kt @@ -22,14 +22,12 @@ package de.grobox.transportr.networks import android.content.Context import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import com.google.common.base.Preconditions.checkArgument +import de.schildbach.pte.util.Preconditions.checkArgument import de.grobox.transportr.R import de.schildbach.pte.NetworkId import de.schildbach.pte.NetworkProvider import java.lang.ref.SoftReference -import javax.annotation.concurrent.Immutable -@Immutable data class TransportNetwork internal constructor( val id: NetworkId, @field:StringRes private val name: Int = 0, diff --git a/app/src/main/java/de/grobox/transportr/networks/TransportNetworks.kt b/app/src/main/java/de/grobox/transportr/networks/TransportNetworks.kt index df2425acf..3855d6f05 100644 --- a/app/src/main/java/de/grobox/transportr/networks/TransportNetworks.kt +++ b/app/src/main/java/de/grobox/transportr/networks/TransportNetworks.kt @@ -23,11 +23,9 @@ import android.annotation.SuppressLint import android.util.Base64 import android.content.Context import de.grobox.transportr.R -import de.grobox.transportr.networks.TransportNetwork.Status.ALPHA import de.grobox.transportr.networks.TransportNetwork.Status.BETA import de.schildbach.pte.* import okhttp3.HttpUrl -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import java.util.* @SuppressLint("ConstantLocale") @@ -74,7 +72,7 @@ private val networks = arrayOf( id = NetworkId.VBB, description = R.string.np_desc_vbb, logo = R.drawable.network_vbb_logo, - factory = { VbbProvider("{\"type\":\"AID\",\"aid\":\"hafas-vbb-apps\"}", "RCTJM2fFxFfxxQfI".toByteArray(Charsets.UTF_8)) } + factory = { VbbProvider("{\"type\":\"AID\",\"aid\":\"hafas-vbb-apps\"}") } ), TransportNetwork( id = NetworkId.BAYERN, @@ -101,13 +99,13 @@ private val networks = arrayOf( description = R.string.np_desc_invg, logo = R.drawable.network_invg_logo, status = BETA, - factory = { InvgProvider("{\"type\":\"AID\",\"aid\":\"GITvwi3BGOmTQ2a5\"}", "ERxotxpwFT7uYRsI".toByteArray(Charsets.UTF_8)) } + factory = { InvgProvider("{\"type\":\"AID\",\"aid\":\"GITvwi3BGOmTQ2a5\"}") } ), TransportNetwork ( id = NetworkId.VBN, description = R.string.np_desc_vbn, logo = R.drawable.network_vbn_logo, - factory = { VbnProvider("{\"type\":\"AID\",\"aid\":\"rnOHBWhesvc7gFkd\"}", "SP31mBufSyCLmNxp".toByteArray(Charsets.UTF_8)) } + factory = { VbnProvider("{\"type\":\"AID\",\"aid\":\"rnOHBWhesvc7gFkd\"}") } ), TransportNetwork ( id = NetworkId.SH, @@ -211,7 +209,7 @@ private val networks = arrayOf( id = NetworkId.KVV, description = R.string.np_desc_kvv, logo = R.drawable.network_kvv_logo, - factory = { KvvProvider("https://projekte.kvv-efa.de/oeffi/".toHttpUrlOrNull()) } + factory = { KvvProvider(HttpUrl.get("https://projekte.kvv-efa.de/oeffi/")) } ), TransportNetwork( id = NetworkId.NVBW, @@ -230,7 +228,7 @@ private val networks = arrayOf( name = R.string.np_name_vgs, description = R.string.np_desc_vgs, logo = R.drawable.network_vgs_logo, - factory = { VgsProvider("{\"type\":\"AID\",\"aid\":\"51XfsVqgbdA6oXzHrx75jhlocRg6Xe\"}", "HJtlubisvxiJxss".toByteArray(Charsets.UTF_8)) } + factory = { VgsProvider("{\"type\":\"AID\",\"aid\":\"51XfsVqgbdA6oXzHrx75jhlocRg6Xe\"}") } ), TransportNetwork( id = NetworkId.VRS, diff --git a/app/src/main/java/de/grobox/transportr/trips/BaseViewHolder.kt b/app/src/main/java/de/grobox/transportr/trips/BaseViewHolder.kt index f40c326a2..1cf9190a8 100644 --- a/app/src/main/java/de/grobox/transportr/trips/BaseViewHolder.kt +++ b/app/src/main/java/de/grobox/transportr/trips/BaseViewHolder.kt @@ -35,6 +35,7 @@ import de.schildbach.pte.dto.Position import de.schildbach.pte.dto.Stop import java.util.* +// TODO can we somehow make use of view binding here (needs XML "superclass") internal abstract class BaseViewHolder(v: View) : RecyclerView.ViewHolder(v) { protected val context: Context = v.context diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/LegAdapter.kt b/app/src/main/java/de/grobox/transportr/trips/detail/LegAdapter.kt index 47e40602a..19a743946 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/LegAdapter.kt +++ b/app/src/main/java/de/grobox/transportr/trips/detail/LegAdapter.kt @@ -23,6 +23,7 @@ import androidx.recyclerview.widget.RecyclerView.Adapter import android.view.LayoutInflater import android.view.ViewGroup import de.grobox.transportr.R +import de.grobox.transportr.databinding.ListItemLegBinding import de.grobox.transportr.trips.detail.LegViewHolder.LegType import de.grobox.transportr.trips.detail.LegViewHolder.LegType.* import de.schildbach.pte.dto.Trip.Leg @@ -33,8 +34,8 @@ internal class LegAdapter internal constructor( private val showLineName: Boolean) : Adapter() { override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): LegViewHolder { - val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.list_item_leg, viewGroup, false) - return LegViewHolder(v, listener, showLineName) + val binding = ListItemLegBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) + return LegViewHolder(binding, listener, showLineName) } override fun onBindViewHolder(ui: LegViewHolder, i: Int) { diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/LegViewHolder.kt b/app/src/main/java/de/grobox/transportr/trips/detail/LegViewHolder.kt index 36a8e94ba..0f9537f09 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/LegViewHolder.kt +++ b/app/src/main/java/de/grobox/transportr/trips/detail/LegViewHolder.kt @@ -29,9 +29,8 @@ import android.widget.TextView import androidx.core.content.ContextCompat.getColor import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.google.common.base.Strings -import com.google.common.base.Strings.isNullOrEmpty import de.grobox.transportr.R +import de.grobox.transportr.databinding.ListItemLegBinding import de.grobox.transportr.trips.BaseViewHolder import de.grobox.transportr.trips.detail.LegViewHolder.LegType.* import de.grobox.transportr.ui.LineView @@ -43,10 +42,9 @@ import de.schildbach.pte.dto.Line import de.schildbach.pte.dto.Stop import de.schildbach.pte.dto.Style.RED import de.schildbach.pte.dto.Trip.* -import kotlinx.android.synthetic.main.list_item_leg.view.* -internal class LegViewHolder(v: View, private val listener: LegClickListener, private val showLineName: Boolean) : BaseViewHolder(v) { +internal class LegViewHolder(binding: ListItemLegBinding, private val listener: LegClickListener, private val showLineName: Boolean) : BaseViewHolder(binding.root) { internal enum class LegType { FIRST, MIDDLE, LAST, FIRST_LAST @@ -56,24 +54,24 @@ internal class LegViewHolder(v: View, private val listener: LegClickListener, pr internal val DEFAULT_LINE_COLOR = RED } - private val fromCircle: ImageView = v.fromCircle - private val fromLocation: TextView = v.fromLocation - private val fromPlatform: TextView = v.fromPlatform - private val fromButton: ImageButton = v.fromButton - - private val lineBar: ImageView = v.lineBar - private val lineView: LineView = v.lineView - private val lineDestination: TextView = v.lineDestination - private val message: TextView = v.message - private val duration: TextView = v.duration - private val stopsText: TextView = v.stopsText - private val stopsButton: ImageButton = v.stopsButton - private val stopsList: RecyclerView = v.stopsList - - private val toCircle: ImageView = v.toCircle - private val toLocation: TextView = v.toLocation - private val toPlatform: TextView = v.toPlatform - private val toButton: ImageButton = v.toButton + private val fromCircle: ImageView = binding.fromCircle + private val fromLocation: TextView = binding.fromLocation + private val fromPlatform: TextView = binding.fromPlatform + private val fromButton: ImageButton = binding.fromButton + + private val lineBar: ImageView = binding.lineBar + private val lineView: LineView = binding.lineView + private val lineDestination: TextView = binding.lineDestination + private val message: TextView = binding.message + private val duration: TextView = binding.duration + private val stopsText: TextView = binding.stopsText + private val stopsButton: ImageButton = binding.stopsButton + private val stopsList: RecyclerView = binding.stopsList + + private val toCircle: ImageView = binding.toCircle + private val toLocation: TextView = binding.toLocation + private val toPlatform: TextView = binding.toPlatform + private val toButton: ImageButton = binding.toButton private val adapter = StopAdapter(listener) fun bind(leg: Leg, legType: LegType) { @@ -131,7 +129,7 @@ internal class LegViewHolder(v: View, private val listener: LegClickListener, pr // Line lineView.setLine(leg.line, lineColor) - if (showLineName && !isNullOrEmpty(leg.line.name)) { + if (showLineName && !leg.line.name.isNullOrEmpty()) { lineDestination.text = leg.line.name } else if (leg.destination != null) { lineDestination.text = getLocationName(leg.destination!!) @@ -175,7 +173,7 @@ internal class LegViewHolder(v: View, private val listener: LegClickListener, pr // Optional message var hasText = false - if (!Strings.isNullOrEmpty(leg.message)) { + if (!leg.message.isNullOrEmpty()) { message.visibility = VISIBLE @Suppress("DEPRECATION") message.text = fromHtml(leg.message) diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/StopAdapter.kt b/app/src/main/java/de/grobox/transportr/trips/detail/StopAdapter.kt index 233c36022..32d81f712 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/StopAdapter.kt +++ b/app/src/main/java/de/grobox/transportr/trips/detail/StopAdapter.kt @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.RecyclerView.Adapter import android.view.LayoutInflater import android.view.ViewGroup import de.grobox.transportr.R +import de.grobox.transportr.databinding.ListItemStopBinding import de.grobox.transportr.trips.detail.LegViewHolder.Companion.DEFAULT_LINE_COLOR import de.schildbach.pte.dto.Stop @@ -39,8 +40,8 @@ internal class StopAdapter internal constructor(private val listener: LegClickLi } override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): StopViewHolder { - val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.list_item_stop, viewGroup, false) - return StopViewHolder(v, listener) + val binding = ListItemStopBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) + return StopViewHolder(binding, listener) } override fun onBindViewHolder(ui: StopViewHolder, i: Int) { diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/StopViewHolder.kt b/app/src/main/java/de/grobox/transportr/trips/detail/StopViewHolder.kt index b7e4bab0a..a5138a12d 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/StopViewHolder.kt +++ b/app/src/main/java/de/grobox/transportr/trips/detail/StopViewHolder.kt @@ -25,20 +25,20 @@ import android.view.View.* import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView +import de.grobox.transportr.databinding.ListItemStopBinding import de.grobox.transportr.trips.BaseViewHolder import de.grobox.transportr.utils.DateUtils.formatTime import de.grobox.transportr.utils.TransportrUtils.getLocationName import de.schildbach.pte.dto.Stop -import kotlinx.android.synthetic.main.list_item_stop.view.* import java.util.Date -internal class StopViewHolder(v: View, private val listener : LegClickListener) : BaseViewHolder(v) { +internal class StopViewHolder(binding: ListItemStopBinding, private val listener : LegClickListener) : BaseViewHolder(binding.root) { - private val circle: ImageView = v.circle - private val stopLocation: TextView = v.stopLocation - private val stopPlatform: TextView = v.stopPlatform - private val stopButton: ImageButton = v.stopButton + private val circle: ImageView = binding.circle + private val stopLocation: TextView = binding.stopLocation + private val stopPlatform: TextView = binding.stopPlatform + private val stopButton: ImageButton = binding.stopButton fun bind(stop: Stop, color: Int) { if (stop.arrivalTime != null) { diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailActivity.java b/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailActivity.java index 9d066cde1..9fc0163ec 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailActivity.java +++ b/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailActivity.java @@ -26,7 +26,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import javax.inject.Inject; import androidx.annotation.NonNull; @@ -50,7 +50,7 @@ import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED; import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FOCAL_PRESSED; -@ParametersAreNonnullByDefault +@NullMarked public class TripDetailActivity extends TransportrActivity { public static final String TRIP = "de.schildbach.pte.dto.Trip"; diff --git a/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailFragment.kt b/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailFragment.kt index c6270feb0..c8d6e033b 100644 --- a/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailFragment.kt +++ b/app/src/main/java/de/grobox/transportr/trips/detail/TripDetailFragment.kt @@ -32,6 +32,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import de.grobox.transportr.R import de.grobox.transportr.TransportrFragment +import de.grobox.transportr.databinding.FragmentTripDetailBinding import de.grobox.transportr.trips.detail.TripDetailViewModel.SheetState import de.grobox.transportr.trips.detail.TripDetailViewModel.SheetState.* import de.grobox.transportr.trips.detail.TripUtils.getStandardFare @@ -43,11 +44,15 @@ import de.grobox.transportr.utils.DateUtils.formatTime import de.grobox.transportr.utils.DateUtils.formatRelativeTime import de.grobox.transportr.utils.TransportrUtils.getColorFromAttr import de.schildbach.pte.dto.Trip -import kotlinx.android.synthetic.main.fragment_trip_detail.* import javax.inject.Inject class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener { + private var _binding: FragmentTripDetailBinding? = null + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + companion object { val TAG = TripDetailFragment::class.java.simpleName } @@ -60,8 +65,8 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener private val timeUpdater: CountDownTimer = object : CountDownTimer(Long.MAX_VALUE, 1000 * 30) { override fun onTick(millisUntilFinished: Long) { viewModel.getTrip().value?.let { - formatRelativeTime(fromTimeRel.context, it.firstDepartureTime).let { - fromTimeRel.apply { + formatRelativeTime(binding.fromTimeRel.context, it.firstDepartureTime).let { + binding.fromTimeRel.apply { text = it.relativeTime visibility = it.visibility } @@ -73,7 +78,14 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_trip_detail, container, false) + _binding = FragmentTripDetailBinding.inflate(inflater, container, false) + val view = binding.root + return view + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -82,10 +94,10 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener setHasOptionsMenu(true) component.inject(this) - toolbar.setNavigationOnClickListener { _ -> onToolbarClose() } - toolbar.setOnMenuItemClickListener(this) - list.layoutManager = LinearLayoutManager(context) - bottomBar.setOnClickListener { _ -> onBottomBarClick() } + binding.toolbar.setNavigationOnClickListener { _ -> onToolbarClose() } + binding.toolbar.setOnMenuItemClickListener(this) + binding.list.layoutManager = LinearLayoutManager(context) + binding.bottomBar.setOnClickListener { _ -> onBottomBarClick() } viewModel = ViewModelProvider(activity!!, viewModelFactory).get(TripDetailViewModel::class.java) viewModel.getTrip().observe(viewLifecycleOwner, Observer { this.onTripChanged(it) }) @@ -103,7 +115,7 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - val toolbarMenu = toolbar.menu + val toolbarMenu = binding.toolbar.menu inflater.inflate(R.menu.trip_details, toolbarMenu) viewModel.tripReloadError.observe(this, Observer { this.onTripReloadError(it) }) super.onCreateOptionsMenu(menu, inflater) @@ -131,30 +143,30 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener private fun onTripChanged(trip: Trip?) { if (trip == null) return - val reloadMenuItem = toolbar.menu.findItem(R.id.action_reload) + val reloadMenuItem = binding.toolbar.menu.findItem(R.id.action_reload) if (reloadMenuItem != null) reloadMenuItem.actionView = null val network = viewModel.transportNetwork.value val showLineName = network != null && network.hasGoodLineNames() val adapter = LegAdapter(trip.legs, viewModel, showLineName) - list.adapter = adapter + binding.list.adapter = adapter - fromTime.text = formatTime(context, trip.firstDepartureTime) - formatRelativeTime(fromTimeRel.context, trip.firstDepartureTime).let { - fromTimeRel.apply { + binding.fromTime.text = formatTime(context, trip.firstDepartureTime) + formatRelativeTime(binding.fromTimeRel.context, trip.firstDepartureTime).let { + binding.fromTimeRel.apply { text = it.relativeTime visibility = it.visibility } } - from.text = trip.from.uniqueShortName() - toTime.text = formatTime(context, trip.lastArrivalTime) - to.text = trip.to.uniqueShortName() - duration.text = formatDuration(trip.duration) - durationTop.text = getString(R.string.total_time, formatDuration(trip.duration)) - price.visibility = if (trip.hasFare()) VISIBLE else GONE - price.text = trip.getStandardFare() - priceTop.visibility = if (trip.hasFare()) VISIBLE else GONE - priceTop.text = trip.getStandardFare() + binding.from.text = trip.from.uniqueShortName() + binding.toTime.text = formatTime(context, trip.lastArrivalTime) + binding.to.text = trip.to.uniqueShortName() + binding.duration.text = formatDuration(trip.duration) + binding.durationTop.text = getString(R.string.total_time, formatDuration(trip.duration)) + binding.price.visibility = if (trip.hasFare()) VISIBLE else GONE + binding.price.text = trip.getStandardFare() + binding.priceTop.visibility = if (trip.hasFare()) VISIBLE else GONE + binding.priceTop.text = trip.getStandardFare() } private fun onToolbarClose() { @@ -169,33 +181,33 @@ class TripDetailFragment : TransportrFragment(), Toolbar.OnMenuItemClickListener when (sheetState) { null -> return BOTTOM -> { - toolbar.visibility = GONE - topBar.visibility = GONE - bottomBar.visibility = VISIBLE + binding.toolbar.visibility = GONE + binding.topBar.visibility = GONE + binding.bottomBar.visibility = VISIBLE } MIDDLE -> { - toolbar.visibility = GONE - topBar.visibility = VISIBLE - topBar.setBackgroundColor(context.getColorFromAttr(R.attr.colorPrimary)) - fromTimeRel.setTextColor(getColor(context, R.color.md_white_1000)) - durationTop.setTextColor(getColor(context, R.color.md_white_1000)) - priceTop.setTextColor(getColor(context, R.color.md_white_1000)) - bottomBar.visibility = GONE + binding.toolbar.visibility = GONE + binding.topBar.visibility = VISIBLE + binding.topBar.setBackgroundColor(context.getColorFromAttr(R.attr.colorPrimary)) + binding.fromTimeRel.setTextColor(getColor(context, R.color.md_white_1000)) + binding.durationTop.setTextColor(getColor(context, R.color.md_white_1000)) + binding.priceTop.setTextColor(getColor(context, R.color.md_white_1000)) + binding.bottomBar.visibility = GONE } EXPANDED -> { - toolbar.visibility = VISIBLE - topBar.visibility = VISIBLE - topBar.setBackgroundColor(context.getColorFromAttr(android.R.attr.colorBackground)) - fromTimeRel.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary)) - durationTop.setTextColor(context.getColorFromAttr(android.R.attr.textColorSecondary)) - priceTop.setTextColor(context.getColorFromAttr(android.R.attr.textColorSecondary)) - bottomBar.visibility = GONE + binding.toolbar.visibility = VISIBLE + binding.topBar.visibility = VISIBLE + binding.topBar.setBackgroundColor(context.getColorFromAttr(android.R.attr.colorBackground)) + binding.fromTimeRel.setTextColor(context.getColorFromAttr(android.R.attr.textColorPrimary)) + binding.durationTop.setTextColor(context.getColorFromAttr(android.R.attr.textColorSecondary)) + binding.priceTop.setTextColor(context.getColorFromAttr(android.R.attr.textColorSecondary)) + binding.bottomBar.visibility = GONE } } } private fun onTripReloadError(error: String?) { - toolbar.menu.findItem(R.id.action_reload).actionView = null + binding.toolbar.menu.findItem(R.id.action_reload).actionView = null Toast.makeText(context, error, Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsActivity.kt b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsActivity.kt index 8716db6a6..6ec181a4c 100644 --- a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsActivity.kt +++ b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsActivity.kt @@ -30,12 +30,12 @@ import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener import de.grobox.transportr.R import de.grobox.transportr.TransportrActivity import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType +import de.grobox.transportr.databinding.ActivityDirectionsBinding import de.grobox.transportr.locations.WrapLocation import de.grobox.transportr.locations.WrapLocation.WrapType.GPS import de.grobox.transportr.trips.search.SavedSearchesFragment.HomePickerFragment import de.grobox.transportr.trips.search.SavedSearchesFragment.WorkPickerFragment import de.grobox.transportr.utils.Constants.* -import kotlinx.android.synthetic.main.activity_directions.* import javax.inject.Inject class DirectionsActivity : TransportrActivity(), OnOffsetChangedListener { @@ -49,6 +49,8 @@ class DirectionsActivity : TransportrActivity(), OnOffsetChangedListener { const val INTENT_URI_FAVORITE = "transportr://favorite" } + private lateinit var binding: ActivityDirectionsBinding + @Inject internal lateinit var viewModelFactory: ViewModelProvider.Factory @@ -64,16 +66,19 @@ class DirectionsActivity : TransportrActivity(), OnOffsetChangedListener { override fun onFinish() {} } - public override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + component.inject(this) - setContentView(R.layout.activity_directions) + binding = ActivityDirectionsBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) // get view model and observe data viewModel = ViewModelProvider(this, viewModelFactory).get(DirectionsViewModel::class.java) viewModel.showTrips.observe(this, Observer { showTrips() }) - appBarLayout.addOnOffsetChangedListener(this) + binding.appBarLayout.addOnOffsetChangedListener(this) if (savedInstanceState == null) { showFavorites() @@ -127,7 +132,7 @@ class DirectionsActivity : TransportrActivity(), OnOffsetChangedListener { supportFragmentManager.beginTransaction() .replace(R.id.fragmentContainer, TripsFragment(), TripsFragment.TAG) .commit() - fragmentContainer.requestFocus() + binding.fragmentContainer.requestFocus() } private fun processIntent(intent: Intent?) { diff --git a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt index 397adcec2..ab8eb0475 100644 --- a/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt +++ b/app/src/main/java/de/grobox/transportr/trips/search/DirectionsFragment.kt @@ -43,6 +43,7 @@ import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.FROM import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.TO import de.grobox.transportr.data.locations.FavoriteLocation.FavLocationType.VIA +import de.grobox.transportr.databinding.FragmentDirectionsFormBinding import de.grobox.transportr.settings.SettingsManager import de.grobox.transportr.ui.TimeDateFragment import de.grobox.transportr.utils.Constants.DATE @@ -54,15 +55,18 @@ import de.grobox.transportr.utils.DateUtils.formatTime import de.grobox.transportr.utils.DateUtils.isNow import de.grobox.transportr.utils.DateUtils.isToday import de.schildbach.pte.dto.Product -import kotlinx.android.synthetic.main.fragment_directions_form.* -import kotlinx.android.synthetic.main.location_view.view.gpsButton import java.util.* -import javax.annotation.ParametersAreNonnullByDefault +import org.jspecify.annotations.NullMarked import javax.inject.Inject -@ParametersAreNonnullByDefault +@NullMarked class DirectionsFragment : TransportrFragment() { + private var _binding: FragmentDirectionsFormBinding? = null + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + @Inject internal lateinit var settingsManager: SettingsManager @Inject @@ -71,59 +75,67 @@ class DirectionsFragment : TransportrFragment() { private lateinit var viewModel: DirectionsViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val v = inflater.inflate(R.layout.fragment_directions_form, container, false) + _binding = FragmentDirectionsFormBinding.inflate(inflater, container, false) component.inject(this) viewModel = ViewModelProvider(activity!!, viewModelFactory).get(DirectionsViewModel::class.java) - return v + val view = binding.root + return view + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setUpToolbar(toolbar) + setUpToolbar(binding.toolbar) val network = viewModel.transportNetwork.value ?: throw IllegalStateException() - fromLocation.setTransportNetwork(network) - viaLocation.setTransportNetwork(network) - toLocation.setTransportNetwork(network) + binding.fromLocation.setTransportNetwork(network) + binding.viaLocation.setTransportNetwork(network) + binding.toLocation.setTransportNetwork(network) - fromLocation.type = FROM - viaLocation.type = VIA - toLocation.type = TO + binding.fromLocation.type = FROM + binding.viaLocation.type = VIA + binding.toLocation.type = TO - fromLocation.setLocationViewListener(viewModel) - viaLocation.setLocationViewListener(viewModel) - toLocation.setLocationViewListener(viewModel) + binding.fromLocation.setLocationViewListener(viewModel) + binding.viaLocation.setLocationViewListener(viewModel) + binding.toLocation.setLocationViewListener(viewModel) viewModel.home.observe(viewLifecycleOwner, { - fromLocation.setHomeLocation(it) - viaLocation.setHomeLocation(it) - toLocation.setHomeLocation(it) + binding.fromLocation.setHomeLocation(it) + binding.viaLocation.setHomeLocation(it) + binding.toLocation.setHomeLocation(it) }) viewModel.work.observe(viewLifecycleOwner, { - fromLocation.setWorkLocation(it) - viaLocation.setWorkLocation(it) - toLocation.setWorkLocation(it) + binding.fromLocation.setWorkLocation(it) + binding.viaLocation.setWorkLocation(it) + binding.toLocation.setWorkLocation(it) }) viewModel.locations.observe(viewLifecycleOwner, { if (it == null) return@observe - fromLocation.setFavoriteLocations(it) - viaLocation.setFavoriteLocations(it) - toLocation.setFavoriteLocations(it) + binding.fromLocation.setFavoriteLocations(it) + binding.viaLocation.setFavoriteLocations(it) + binding.toLocation.setFavoriteLocations(it) }) viewModel.fromLocation.observe(viewLifecycleOwner, { - fromLocation.setLocation(it) - if (it != null) toLocation.requestFocus() + binding.fromLocation.setLocation(it) + if (it != null) binding.toLocation.requestFocus() onLocationsChanged() }) - viewModel.viaLocation.observe(viewLifecycleOwner, { viaLocation.setLocation(it) }) + viewModel.viaLocation.observe(viewLifecycleOwner, { + binding.viaLocation.setLocation(it) + }) viewModel.toLocation.observe(viewLifecycleOwner, { - toLocation.setLocation(it) + binding.toLocation.setLocation(it) onLocationsChanged() }) - viewModel.viaSupported.observe(viewLifecycleOwner, { viaIcon.visibility = if (it) VISIBLE else GONE }) + viewModel.viaSupported.observe(viewLifecycleOwner, { binding.viaIcon.visibility = if (it) VISIBLE else GONE }) viewModel.isDeparture.observe(viewLifecycleOwner, { onIsDepartureChanged(it) }) viewModel.isExpanded.observe(viewLifecycleOwner, { onViaVisibleChanged(it) }) viewModel.lastQueryCalendar.observe(viewLifecycleOwner, { onCalendarUpdated(it) }) @@ -132,27 +144,28 @@ class DirectionsFragment : TransportrFragment() { viewModel.isFavTrip.observe(viewLifecycleOwner, { onFavStatusChanged(it) }) viewModel.products.observe(viewLifecycleOwner, { onProductsChanged(it) }) - favIcon.setOnClickListener { viewModel.toggleFavTrip() } + binding.favIcon.setOnClickListener { viewModel.toggleFavTrip() } - timeBackground.setOnClickListener { + binding.timeBackground.setOnClickListener { if (viewModel.lastQueryCalendar.value == null) throw IllegalStateException() val fragment = TimeDateFragment.newInstance(viewModel.lastQueryCalendar.value!!, viewModel.isDeparture.value!!) fragment.setTimeDateListener(viewModel) fragment.show(activity!!.supportFragmentManager, TimeDateFragment.TAG) } - timeBackground.setOnLongClickListener { + binding.timeBackground.setOnLongClickListener { viewModel.resetCalender() true } - productsIcon.setOnClickListener { + binding.productsIcon.setOnClickListener { activity?.let { a -> ProductDialogFragment().show(a.supportFragmentManager, ProductDialogFragment.TAG) } } - swapIcon.setOnClickListener { swapLocations() } + binding.swapIcon.setOnClickListener { swapLocations() } - fromLocation.gpsButton.setOnClickListener { + // todo: how to access gpsButton here? + binding.fromLocation.ui.gps.setOnClickListener { if (ActivityCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) != PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PERMISSION_GRANTED ) { @@ -162,19 +175,19 @@ class DirectionsFragment : TransportrFragment() { } } - viaIcon.setOnClickListener { viewModel.toggleIsExpanded() } + binding.viaIcon.setOnClickListener { viewModel.toggleIsExpanded() } - TooltipCompat.setTooltipText(productsIcon, getString(R.string.action_choose_products)) - TooltipCompat.setTooltipText(swapIcon, getString(R.string.action_switch_locations)) - TooltipCompat.setTooltipText(viaIcon, getString(R.string.action_navigation_expand)) + TooltipCompat.setTooltipText(binding.productsIcon, getString(R.string.action_choose_products)) + TooltipCompat.setTooltipText(binding.swapIcon, getString(R.string.action_switch_locations)) + TooltipCompat.setTooltipText(binding.viaIcon, getString(R.string.action_navigation_expand)) } private fun onLocationsChanged() { val fromNotEmpty = this.viewModel.fromLocation.value != null val toNotEmpty = this.viewModel.toLocation.value != null - swapIcon.isEnabled = fromNotEmpty || toNotEmpty + binding.swapIcon.isEnabled = fromNotEmpty || toNotEmpty // If icon disabled, grey it out - swapIcon.alpha = if (swapIcon.isEnabled) 1.0f else 0.5f + binding.swapIcon.alpha = if (binding.swapIcon.isEnabled) 1.0f else 0.5f } override fun onSaveInstanceState(outState: Bundle) { @@ -189,9 +202,9 @@ class DirectionsFragment : TransportrFragment() { if (savedInstanceState != null && viewModel.trips.value == null) { viewModel.setIsExpanded(savedInstanceState.getBoolean(EXPANDED, false)) viewModel.setIsDeparture(savedInstanceState.getBoolean(DEPARTURE, true)) - viewModel.setFromLocation(fromLocation.getLocation()) - viewModel.setViaLocation(viaLocation.getLocation()) - viewModel.setToLocation(toLocation.getLocation()) + viewModel.setFromLocation(binding.fromLocation.getLocation()) + viewModel.setViaLocation(binding.viaLocation.getLocation()) + viewModel.setToLocation(binding.toLocation.getLocation()) viewModel.onTimeAndDateSet(savedInstanceState.getSerializable(DATE) as Calendar) } (activity!!.supportFragmentManager.findFragmentByTag(TimeDateFragment.TAG) as? TimeDateFragment)?.setTimeDateListener(viewModel) @@ -201,24 +214,24 @@ class DirectionsFragment : TransportrFragment() { if (calendar == null) return when { isNow(calendar) -> { - time.setText(R.string.now_small) - date.visibility = GONE + binding.time.setText(R.string.now_small) + binding.date.visibility = GONE } isToday(calendar) -> { val relTime = formatRelativeTime(context, calendar.time, 30) - time.text = if (relTime.visibility == VISIBLE) relTime.relativeTime else formatTime(context, calendar.time) - date.visibility = GONE + binding.time.text = if (relTime.visibility == VISIBLE) relTime.relativeTime else formatTime(context, calendar.time) + binding.date.visibility = GONE } else -> { - time.text = formatTime(context, calendar.time) - date.text = formatDate(context, calendar.time) - date.visibility = VISIBLE + binding.time.text = formatTime(context, calendar.time) + binding.date.text = formatDate(context, calendar.time) + binding.date.visibility = VISIBLE } } } private fun swapLocations() { - val toToY = fromCard.y - toCard.y + val toToY = binding.fromCard.y - binding.toCard.y val slideUp = TranslateAnimation( RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, Animation.ABSOLUTE, toToY @@ -228,7 +241,7 @@ class DirectionsFragment : TransportrFragment() { isFillEnabled = true } - val fromToY = toCard.y - fromCard.y + val fromToY = binding.toCard.y - binding.fromCard.y val slideDown = TranslateAnimation( RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, RELATIVE_TO_SELF, 0.0f, Animation.ABSOLUTE, fromToY @@ -238,8 +251,8 @@ class DirectionsFragment : TransportrFragment() { isFillEnabled = true } - fromCard.startAnimation(slideDown) - toCard.startAnimation(slideUp) + binding.fromCard.startAnimation(slideDown) + binding.toCard.startAnimation(slideUp) slideUp.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) {} @@ -249,8 +262,8 @@ class DirectionsFragment : TransportrFragment() { override fun onAnimationEnd(animation: Animation) { viewModel.swapFromAndToLocations() - fromCard.clearAnimation() - toCard.clearAnimation() + binding.fromCard.clearAnimation() + binding.toCard.clearAnimation() viewModel.search() } @@ -258,25 +271,25 @@ class DirectionsFragment : TransportrFragment() { } private fun onIsDepartureChanged(isDeparture: Boolean) { - departure.text = getString(if (isDeparture) R.string.trip_dep else R.string.trip_arr) + binding.departure.text = getString(if (isDeparture) R.string.trip_dep else R.string.trip_arr) } private fun onViaVisibleChanged(viaVisible: Boolean) { - viaIcon?.setImageResource(if (viaVisible) R.drawable.ic_action_navigation_unfold_less_white else R.drawable.ic_action_navigation_unfold_more_white) - viaCard.visibility = if (viaVisible) VISIBLE else GONE + binding.viaIcon?.setImageResource(if (viaVisible) R.drawable.ic_action_navigation_unfold_less_white else R.drawable.ic_action_navigation_unfold_more_white) + binding.viaCard.visibility = if (viaVisible) VISIBLE else GONE } private fun updateGpsLocation(type: FavLocationType?, refresh: Boolean) { if (type == null) { viewModel.locationLiveData.removeObservers(viewLifecycleOwner) - fromLocation.clearSearching() + binding.fromLocation.clearSearching() return } if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) { return } - fromLocation.setSearching() - if (!refresh) toLocation.requestFocus() + binding.fromLocation.setSearching() + if (!refresh) binding.toLocation.requestFocus() var counter = 0 viewModel.locationLiveData.observe(viewLifecycleOwner) { location -> counter ++ @@ -292,18 +305,18 @@ class DirectionsFragment : TransportrFragment() { private fun onFavStatusChanged(isFav: Boolean?) { if (isFav == null) { - favIcon.visibility = INVISIBLE + binding.favIcon.visibility = INVISIBLE } else { - favIcon.visibility = VISIBLE - favIcon.setImageResource(if (isFav) R.drawable.ic_action_star else R.drawable.ic_action_star_empty) + binding.favIcon.visibility = VISIBLE + binding.favIcon.setImageResource(if (isFav) R.drawable.ic_action_star else R.drawable.ic_action_star_empty) val tooltip = getString(if (isFav) R.string.action_unfav_trip else R.string.action_fav_trip) - favIcon.contentDescription = tooltip - TooltipCompat.setTooltipText(favIcon, tooltip) + binding.favIcon.contentDescription = tooltip + TooltipCompat.setTooltipText(binding.favIcon, tooltip) } } private fun onProductsChanged(products: EnumSet) { - productsMarked.visibility = if (Product.ALL == products) GONE else VISIBLE + binding.productsMarked.visibility = if (Product.ALL == products) GONE else VISIBLE } } diff --git a/app/src/main/java/de/grobox/transportr/trips/search/ProductDialogFragment.java b/app/src/main/java/de/grobox/transportr/trips/search/ProductDialogFragment.java index 5d1329f01..7556d6e20 100755 --- a/app/src/main/java/de/grobox/transportr/trips/search/ProductDialogFragment.java +++ b/app/src/main/java/de/grobox/transportr/trips/search/ProductDialogFragment.java @@ -20,6 +20,8 @@ package de.grobox.transportr.trips.search; import android.app.Dialog; + +import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; import android.content.Context; import android.os.Bundle; @@ -42,8 +44,8 @@ import java.util.List; import java.util.Set; -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; + import javax.inject.Inject; import de.grobox.transportr.R; @@ -51,7 +53,7 @@ import static de.grobox.transportr.utils.TransportrUtils.getDrawableForProduct; -@ParametersAreNonnullByDefault +@NullMarked public class ProductDialogFragment extends DialogFragment { public static final String TAG = ProductDialogFragment.class.getSimpleName(); diff --git a/app/src/main/java/de/grobox/transportr/trips/search/TripViewHolder.kt b/app/src/main/java/de/grobox/transportr/trips/search/TripViewHolder.kt index f5a5ee740..328a2cc8a 100644 --- a/app/src/main/java/de/grobox/transportr/trips/search/TripViewHolder.kt +++ b/app/src/main/java/de/grobox/transportr/trips/search/TripViewHolder.kt @@ -25,7 +25,6 @@ import android.view.View.GONE import android.view.View.VISIBLE import android.view.ViewGroup import android.widget.TextView -import com.google.common.base.Strings.isNullOrEmpty import de.grobox.transportr.R import de.grobox.transportr.trips.BaseViewHolder import de.grobox.transportr.trips.detail.TripUtils.getStandardFare @@ -116,8 +115,8 @@ internal class TripViewHolder(private val v: View) : BaseViewHolder(v) { if (!isTravelable) return true for (leg in legs) { if (leg !is Public) continue - if (!isNullOrEmpty(leg.message)) return true - if (!isNullOrEmpty(leg.line?.message)) return true + if (!leg.message.isNullOrEmpty()) return true + if (!leg.line?.message.isNullOrEmpty()) return true } return false } diff --git a/app/src/main/java/de/grobox/transportr/trips/search/TripsFragment.kt b/app/src/main/java/de/grobox/transportr/trips/search/TripsFragment.kt index 73515cc2e..ff8891c67 100644 --- a/app/src/main/java/de/grobox/transportr/trips/search/TripsFragment.kt +++ b/app/src/main/java/de/grobox/transportr/trips/search/TripsFragment.kt @@ -21,12 +21,10 @@ package de.grobox.transportr.trips.search import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle -import android.os.CountDownTimer import android.util.Pair import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button import android.widget.Toast import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager @@ -34,6 +32,8 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout.OnRe import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection import de.grobox.transportr.R import de.grobox.transportr.TransportrFragment +import de.grobox.transportr.databinding.FragmentDirectionsFormBinding +import de.grobox.transportr.databinding.FragmentTripsBinding import de.grobox.transportr.trips.detail.TripDetailActivity import de.grobox.transportr.trips.search.TripAdapter.OnTripClickListener import de.grobox.transportr.trips.search.TripsRepository.QueryMoreState @@ -41,12 +41,15 @@ import de.grobox.transportr.ui.LceAnimator import de.grobox.transportr.utils.Linkify import de.grobox.transportr.utils.TransportrUtils.getDragDistance import de.schildbach.pte.dto.Trip -import kotlinx.android.synthetic.main.fragment_trips.* import java.util.regex.Pattern -import javax.annotation.ParametersAreNonnullByDefault import javax.inject.Inject class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListener { + + private var _binding: FragmentTripsBinding? = null + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! @Inject internal lateinit var viewModelFactory: ViewModelProvider.Factory @@ -58,30 +61,36 @@ class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListen private var queryMoreDirection = SwipyRefreshLayoutDirection.BOTH override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val v = inflater.inflate(R.layout.fragment_trips, container, false) + _binding = FragmentTripsBinding.inflate(inflater, container, false) component.inject(this) viewModel = ViewModelProvider(activity!!, viewModelFactory).get(DirectionsViewModel::class.java) - return v + val view = binding.root + return view + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Progress Bar and Error View - errorButton.setOnClickListener { viewModel.search() } + binding.errorButton.setOnClickListener { viewModel.search() } // Swipe to Refresh - swipe.let { + binding.swipe.let { it.setColorSchemeColors(R.color.accent) it.setDistanceToTriggerSync(getDragDistance(context)) it.setOnRefreshListener(this) } val layoutManager = LinearLayoutManager(context) - list.layoutManager = layoutManager - list.setHasFixedSize(false) + binding.list.layoutManager = layoutManager + binding.list.setHasFixedSize(false) viewModel.topSwipeEnabled.observe(viewLifecycleOwner, { enabled -> onSwipeEnabledChanged(enabled) }) viewModel.queryMoreState.observe(viewLifecycleOwner, { state -> updateSwipeState(state) }) viewModel.trips.observe(viewLifecycleOwner, { trips -> onTripsLoaded(trips) }) @@ -90,8 +99,8 @@ class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListen viewModel.queryMoreError.observe(viewLifecycleOwner, { error -> onMoreError(error) }) viewModel.timeUpdate.observe(viewLifecycleOwner, { adapter.notifyDataSetChanged() }) adapter.setHasStableIds(false) - list.adapter = adapter - LceAnimator.showLoading(progressBar, list, errorLayout) + binding.list.adapter = adapter + LceAnimator.showLoading(binding.progressBar, binding.list, binding.errorLayout) } override fun onRefresh(direction: SwipyRefreshLayoutDirection) { @@ -101,7 +110,7 @@ class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListen } private fun onSwipeEnabledChanged(enabled: Boolean) { - if (!swipe.isRefreshing && enabled != topSwipingEnabled) { + if (!binding.swipe.isRefreshing && enabled != topSwipingEnabled) { updateSwipeState(viewModel.queryMoreState.value) } topSwipingEnabled = enabled @@ -111,10 +120,10 @@ class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListen val topEnabled = viewModel.topSwipeEnabled.value if (topEnabled == null || state == null) return if (state === QueryMoreState.NONE || (!topEnabled && state === QueryMoreState.EARLIER)) { - swipe.isEnabled = false + binding.swipe.isEnabled = false } else { - swipe.isEnabled = true - swipe.direction = when { + binding.swipe.isEnabled = true + binding.swipe.direction = when { state === QueryMoreState.EARLIER -> SwipyRefreshLayoutDirection.TOP state === QueryMoreState.LATER -> SwipyRefreshLayoutDirection.BOTTOM !topEnabled && state === QueryMoreState.BOTH -> SwipyRefreshLayoutDirection.BOTTOM @@ -128,31 +137,31 @@ class TripsFragment : TransportrFragment(), OnRefreshListener, OnTripClickListen val oldCount = adapter.itemCount adapter.addAll(trips) if (oldCount > 0) { - swipe.isRefreshing = false - list.smoothScrollBy(0, if (queryMoreDirection == SwipyRefreshLayoutDirection.BOTTOM) 200 else -200) + binding.swipe.isRefreshing = false + binding.list.smoothScrollBy(0, if (queryMoreDirection == SwipyRefreshLayoutDirection.BOTTOM) 200 else -200) } else { - LceAnimator.showContent(progressBar, list, errorLayout) + LceAnimator.showContent(binding.progressBar, binding.list, binding.errorLayout) } } private fun onError(error: String?) { if (error == null) return - errorText.text = error - LceAnimator.showErrorView(progressBar, list, errorLayout) + binding.errorText.text = error + LceAnimator.showErrorView(binding.progressBar, binding.list, binding.errorLayout) } @SuppressLint("SetTextI18n") private fun onPTEError(error: Pair?) { if (error == null) return - errorText.text = "${error.first}\n\n${getString(R.string.trip_error_pte, "public-transport-enabler")}" + binding.errorText.text = "${error.first}\n\n${getString(R.string.trip_error_pte, "public-transport-enabler")}" val pteMatcher = Pattern.compile("public-transport-enabler") - Linkify.addLinks(errorText, pteMatcher, error.second) - LceAnimator.showErrorView(progressBar, list, errorLayout) + Linkify.addLinks(binding.errorText, pteMatcher, error.second) + LceAnimator.showErrorView(binding.progressBar, binding.list, binding.errorLayout) } private fun onMoreError(error: String?) { if (error == null) return - swipe.isRefreshing = false + binding.swipe.isRefreshing = false Toast.makeText(context, error, Toast.LENGTH_LONG).show() } diff --git a/app/src/main/java/de/grobox/transportr/ui/TimeDateFragment.kt b/app/src/main/java/de/grobox/transportr/ui/TimeDateFragment.kt index a4e28a218..5a412e655 100755 --- a/app/src/main/java/de/grobox/transportr/ui/TimeDateFragment.kt +++ b/app/src/main/java/de/grobox/transportr/ui/TimeDateFragment.kt @@ -33,12 +33,17 @@ import android.widget.TimePicker import android.widget.TimePicker.OnTimeChangedListener import androidx.fragment.app.DialogFragment import de.grobox.transportr.R -import kotlinx.android.synthetic.main.fragment_time_date.* +import de.grobox.transportr.databinding.FragmentTimeDateBinding import java.util.* import java.util.Calendar.* class TimeDateFragment : DialogFragment(), OnDateSetListener, OnTimeChangedListener { + private var _binding: FragmentTimeDateBinding? = null + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + private var listener: TimeDateListener? = null private var departure: Boolean? = null // null means no departure/arrival selection will be possible private lateinit var calendar: Calendar @@ -76,65 +81,73 @@ class TimeDateFragment : DialogFragment(), OnDateSetListener, OnTimeChangedListe } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.fragment_time_date, container) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + _binding = FragmentTimeDateBinding.inflate(inflater, container, false) + val view = binding.root + return view + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Time - timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(context)) - timePicker.setOnTimeChangedListener(this) + binding.timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(context)) + binding.timePicker.setOnTimeChangedListener(this) showTime(calendar) // Date - dateView.setOnClickListener { + binding.dateView.setOnClickListener { DatePickerDialog(context!!, this@TimeDateFragment, calendar.get(YEAR), calendar.get(MONTH), calendar.get(DAY_OF_MONTH)) .show() } showDate(calendar) // Previous and Next Date - prevDateButton.setOnClickListener { + binding.prevDateButton.setOnClickListener { calendar.add(DAY_OF_MONTH, -1) showDate(calendar) } - nextDateButton.setOnClickListener { + binding.nextDateButton.setOnClickListener { calendar.add(DAY_OF_MONTH, 1) showDate(calendar) } // Departure or Arrival departure?.let { - departureButton.isChecked = it - arrivalButton.isChecked = !it + binding.departureButton.isChecked = it + binding.arrivalButton.isChecked = !it - departureButton.setOnClickListener { - departure = departureButton.isChecked - arrivalButton.isChecked = !departure!! + binding.departureButton.setOnClickListener { + departure = binding.departureButton.isChecked + binding.arrivalButton.isChecked = !departure!! } - arrivalButton.setOnClickListener { - departure = !arrivalButton.isChecked - departureButton.isChecked = departure!! + binding.arrivalButton.setOnClickListener { + departure = !binding.arrivalButton.isChecked + binding.departureButton.isChecked = departure!! } } ?: run { - departureButton.visibility = GONE - arrivalButton.visibility = GONE + binding.departureButton.visibility = GONE + binding.arrivalButton.visibility = GONE } // Buttons - okButton.setOnClickListener { + binding.okButton.setOnClickListener { listener?.onTimeAndDateSet(calendar) departure?.let { listener?.onDepartureOrArrivalSet(it) } dismiss() } - nowButton.setOnClickListener { + binding.nowButton.setOnClickListener { listener?.onTimeAndDateSet(Calendar.getInstance()) departure?.let { listener?.onDepartureOrArrivalSet(it) } dismiss() } - cancelButton.setOnClickListener { + binding.cancelButton.setOnClickListener { dismiss() } } @@ -166,17 +179,17 @@ class TimeDateFragment : DialogFragment(), OnDateSetListener, OnTimeChangedListe val hour = c.get(HOUR_OF_DAY) val min = c.get(MINUTE) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - timePicker.hour = hour - timePicker.minute = min + binding.timePicker.hour = hour + binding.timePicker.minute = min } else { - timePicker.currentHour = hour - timePicker.currentMinute = min + binding.timePicker.currentHour = hour + binding.timePicker.currentMinute = min } } private fun showDate(c: Calendar) { val now = Calendar.getInstance() - dateView.text = when { + binding.dateView.text = when { c.isYesterday(now) -> getString(R.string.yesterday) c.isToday(now) -> getString(R.string.today) c.isTomorrow(now) -> getString(R.string.tomorrow) diff --git a/app/src/main/java/de/grobox/transportr/utils/NotifyingLiveData.kt b/app/src/main/java/de/grobox/transportr/utils/NotifyingLiveData.kt index 96101f7b2..275c14425 100644 --- a/app/src/main/java/de/grobox/transportr/utils/NotifyingLiveData.kt +++ b/app/src/main/java/de/grobox/transportr/utils/NotifyingLiveData.kt @@ -16,7 +16,7 @@ package de.grobox.transportr.utils import androidx.annotation.MainThread -import javax.annotation.ParametersAreNonnullByDefault +import org.jspecify.annotations.NullMarked import androidx.lifecycle.MutableLiveData import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer @@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicBoolean * * Note that only one observer is going to be notified of changes. */ -@ParametersAreNonnullByDefault +@NullMarked class NotifyingLiveData(private val callback: OnActivationCallback) : MutableLiveData() { @MainThread diff --git a/app/src/main/java/de/grobox/transportr/utils/SingleLiveEvent.java b/app/src/main/java/de/grobox/transportr/utils/SingleLiveEvent.java index 74ca0f58d..8b586d6e1 100644 --- a/app/src/main/java/de/grobox/transportr/utils/SingleLiveEvent.java +++ b/app/src/main/java/de/grobox/transportr/utils/SingleLiveEvent.java @@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.ParametersAreNonnullByDefault; +import org.jspecify.annotations.NullMarked; import androidx.annotation.MainThread; import androidx.annotation.NonNull; @@ -37,7 +37,7 @@ *

* Note that only one observer is going to be notified of changes. */ -@ParametersAreNonnullByDefault +@NullMarked public class SingleLiveEvent extends MutableLiveData { private static final String TAG = SingleLiveEvent.class.getSimpleName(); diff --git a/app/witness.gradle b/app/witness.gradle deleted file mode 100644 index 88aa0aa0b..000000000 --- a/app/witness.gradle +++ /dev/null @@ -1,188 +0,0 @@ -dependencyVerification { - verify = [ - 'androidx.activity:activity:1.2.4:activity-1.2.4.aar:ae8e9c7de57e387d2ad90e73f3a5a5dfd502bd4f034c1dccfdb3506d1d2df81a', - 'androidx.annotation:annotation-experimental:1.0.0:annotation-experimental-1.0.0.aar:b219d2b568e7e4ba534e09f8c2fd242343df6ccbdfbbe938846f5d740e6b0b11', - 'androidx.annotation:annotation-experimental:1.1.0:annotation-experimental-1.1.0.aar:0157de61a2064047896a058080f3fd67ba57ad9a94857b3f7a363660243e3f90', - 'androidx.annotation:annotation:1.1.0:annotation-1.1.0.jar:d38d63edb30f1467818d50aaf05f8a692dea8b31392a049bfa991b159ad5b692', - 'androidx.annotation:annotation:1.2.0:annotation-1.2.0.jar:9029262bddce116e6d02be499e4afdba21f24c239087b76b3b57d7e98b490a36', - 'androidx.annotation:annotation:1.5.0:annotation-1.5.0.jar:261fb7c0210858500bab66d34354972a75166ab4182add283780b05513d6ec4a', - 'androidx.appcompat:appcompat-resources:1.3.1:appcompat-resources-1.3.1.aar:e3306cd3e9a19a28a5de5ec3b379580f237c4d81c15c3d795404be9291890a75', - 'androidx.appcompat:appcompat:1.0.0:appcompat-1.0.0.aar:994254e12036cbd3326b2819a4d8bc3bef139f45022cfb0b1086dc58d36d56ce', - 'androidx.appcompat:appcompat:1.3.1:appcompat-1.3.1.aar:959b1daefe40d5e7eed1022f97730b22bc5fd52e6a6083eba284fa86c2971303', - 'androidx.arch.core:core-common:2.1.0:core-common-2.1.0.jar:fe1237bf029d063e7f29fe39aeaf73ef74c8b0a3658486fc29d3c54326653889', - 'androidx.arch.core:core-runtime:2.1.0:core-runtime-2.1.0.aar:dd77615bd3dd275afb11b62df25bae46b10b4a117cd37943af45bdcbf8755852', - 'androidx.arch.core:core-testing:2.1.0:core-testing-2.1.0.aar:c57ffade2a9a844bd62b4f4c3916fad5e09e9f24cceba27e932c25bb7a6d1d8f', - 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0:asynclayoutinflater-1.0.0.aar:f7eab60c57addd94bb06275832fe7600611beaaae1a1ec597c231956faf96c8b', - 'androidx.cardview:cardview:1.0.0:cardview-1.0.0.aar:1193c04c22a3d6b5946dae9f4e8c59d6adde6a71b6bd5d87fb99d82dda1afec7', - 'androidx.collection:collection:1.0.0:collection-1.0.0.jar:9c8d117b5c2bc120a1cdfeb857e05b495b16c36013570372a708f7827e3ac9f9', - 'androidx.collection:collection:1.1.0:collection-1.1.0.jar:632a0e5407461de774409352940e292a291037724207a787820c77daf7d33b72', - 'androidx.constraintlayout:constraintlayout-solver:2.0.4:constraintlayout-solver-2.0.4.jar:9ca19f5448709301c7563488ef941be9dfa55c83538ca7a059b2113e83527b46', - 'androidx.constraintlayout:constraintlayout:2.0.4:constraintlayout-2.0.4.aar:307a79a4a1ccff44249c72a2bf7f47da09fa1b6b1fab2a25808ca889382b738e', - 'androidx.coordinatorlayout:coordinatorlayout:1.0.0:coordinatorlayout-1.0.0.aar:e508c695489493374d942bf7b4ee02abf7571d25aac4c622e57d6cd5cd29eb73', - 'androidx.coordinatorlayout:coordinatorlayout:1.1.0:coordinatorlayout-1.1.0.aar:44a9e30abf56af1025c52a0af506fee9c4131aa55efda52f9fd9451211c5e8cb', - 'androidx.core:core:1.0.0:core-1.0.0.aar:d7672358fc0d46de678968bcddfd3bdfe1618574299a753477b16116cfec74f5', - 'androidx.core:core:1.5.0:core-1.5.0.aar:2b279712795689069cfb63e48b3ab63c32a5649bdda44c482eb8f81ca1a72161', - 'androidx.cursoradapter:cursoradapter:1.0.0:cursoradapter-1.0.0.aar:a81c8fe78815fa47df5b749deb52727ad11f9397da58b16017f4eb2c11e28564', - 'androidx.customview:customview:1.0.0:customview-1.0.0.aar:20e5b8f6526a34595a604f56718da81167c0b40a7a94a57daa355663f2594df2', - 'androidx.customview:customview:1.1.0:customview-1.1.0.aar:01f76ab043770a97b054046f9815717b82ce0355c02967d16c61981359dc189a', - 'androidx.documentfile:documentfile:1.0.0:documentfile-1.0.0.aar:865a061ef2fad16522f8433536b8d47208c46ff7c7745197dfa1eeb481869487', - 'androidx.drawerlayout:drawerlayout:1.0.0:drawerlayout-1.0.0.aar:9402442cdc5a43cf62fb14f8cf98c63342d4d9d9b805c8033c6cf7e802749ac1', - 'androidx.drawerlayout:drawerlayout:1.1.1:drawerlayout-1.1.1.aar:2c5f0dca378eb78ca2c4403f9889c77daa3059302260f26a07fe9f63c08926fe', - 'androidx.dynamicanimation:dynamicanimation:1.0.0:dynamicanimation-1.0.0.aar:ce005162c229bf308d2d5b12fb6cad0874069cbbeaccee63a8193bd08d40de04', - 'androidx.fragment:fragment:1.0.0:fragment-1.0.0.aar:65dd32d71fe65a32e77989a6cfb1ad09307038927f82a740c7611162d0b518f8', - 'androidx.fragment:fragment:1.1.0:fragment-1.1.0.aar:a14c8b8f2153f128e800fbd266a6beab1c283982a29ec570d2cc05d307d81496', - 'androidx.interpolator:interpolator:1.0.0:interpolator-1.0.0.aar:33193135a64fe21fa2c35eec6688f1a76e512606c0fc83dc1b689e37add7732a', - 'androidx.legacy:legacy-preference-v14:1.0.0:legacy-preference-v14-1.0.0.aar:d6d11913e56b8f2d14fd560bd1ad6d7fd5624a15dd4ec073b2d9188205f86280', - 'androidx.legacy:legacy-support-core-ui:1.0.0:legacy-support-core-ui-1.0.0.aar:0d1260c6e7e6a337f875df71b516931e703f716e90889817cd3a20fa5ac3d947', - 'androidx.legacy:legacy-support-core-utils:1.0.0:legacy-support-core-utils-1.0.0.aar:a7edcf01d5b52b3034073027bc4775b78a4764bb6202bb91d61c829add8dd1c7', - 'androidx.lifecycle:lifecycle-common-java8:2.3.1:lifecycle-common-java8-2.3.1.jar:a1ec63c1bb973443cb731d78ec336c5e20e7ee35c89cbb32d36f92c55bb02542', - 'androidx.lifecycle:lifecycle-common:2.0.0:lifecycle-common-2.0.0.jar:7bad7a188804adea6fa1f35d5ef99b705f20bd93ecadde484760ff86b535fefc', - 'androidx.lifecycle:lifecycle-common:2.3.1:lifecycle-common-2.3.1.jar:15848fb56db32f4c7cdc72b324003183d52a4884d6bf09be708ac7f587d139b5', - 'androidx.lifecycle:lifecycle-livedata-core:2.0.0:lifecycle-livedata-core-2.0.0.aar:fde334ec7e22744c0f5bfe7caf1a84c9d717327044400577bdf9bd921ec4f7bc', - 'androidx.lifecycle:lifecycle-livedata-core:2.3.1:lifecycle-livedata-core-2.3.1.aar:e55d38c372460f0a03997ddc950c67227511340fd74f8634d99d29653cd81ab1', - 'androidx.lifecycle:lifecycle-livedata:2.0.0:lifecycle-livedata-2.0.0.aar:c82609ced8c498f0a701a30fb6771bb7480860daee84d82e0a81ee86edf7ba39', - 'androidx.lifecycle:lifecycle-livedata:2.3.1:lifecycle-livedata-2.3.1.aar:b1e061139126f883d4010f23fe7ba460adea432d453c88a00b868cbf9ac037ce', - 'androidx.lifecycle:lifecycle-runtime:2.0.0:lifecycle-runtime-2.0.0.aar:e4afc9e636183f6f3e0edf1cf46121a492ffd2c673075bb07f55c7a99dd43cfb', - 'androidx.lifecycle:lifecycle-runtime:2.3.1:lifecycle-runtime-2.3.1.aar:dd294f4a689c71ff877fd41f3b67a3a62f7760d44ce420e6130f1fc3569d8f00', - 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1:lifecycle-viewmodel-savedstate-2.3.1.aar:97137a8af6a31776a14e4866ab808c7c0a791b484bdbc788bbd83e66407564c0', - 'androidx.lifecycle:lifecycle-viewmodel:2.0.0:lifecycle-viewmodel-2.0.0.aar:d6460aea1b6bad80ab14cf88297e9e43bfde8d87c3e5c28f2c508233ffbcc062', - 'androidx.lifecycle:lifecycle-viewmodel:2.3.1:lifecycle-viewmodel-2.3.1.aar:b6db4c274a12ff85a4747e1e6669c7e98aefa2571ace9d1f1a6fa6be417ce838', - 'androidx.loader:loader:1.0.0:loader-1.0.0.aar:11f735cb3b55c458d470bed9e25254375b518b4b1bad6926783a7026db0f5025', - 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0:localbroadcastmanager-1.0.0.aar:e71c328ceef5c4a7d76f2d86df1b65d65fe2acf868b1a4efd84a3f34336186d8', - 'androidx.preference:preference:1.1.0:preference-1.1.0.aar:6cf1a099b03b3254041b04701841865b2708c0b546b9036c8b0dada0aa59de57', - 'androidx.print:print:1.0.0:print-1.0.0.aar:1d5c7f3135a1bba661fc373fd72e11eb0a4adbb3396787826dd8e4190d5d9edd', - 'androidx.recyclerview:recyclerview:1.0.0:recyclerview-1.0.0.aar:06956fb1ac014027ca9d2b40469a4b42aa61b4957bb11848e1ff352701ab4548', - 'androidx.recyclerview:recyclerview:1.2.0:recyclerview-1.2.0.aar:f68c432db998efac90b9e7f41c1510f097b82220766524d45d04f9b64c6e4d87', - 'androidx.room:room-common:2.3.0:room-common-2.3.0.jar:3492dd60e57c51880ff867a18ed94f28412a84af0830c4bd6d38d5579072ab66', - 'androidx.room:room-compiler-processing:2.3.0:room-compiler-processing-2.3.0.jar:b7ee51fdab8bb3c594f50ac874078259e64552efa54b80ba3d24eeedd419dcfd', - 'androidx.room:room-compiler:2.3.0:room-compiler-2.3.0.jar:360c2bbb65a81a4e6bf7bf170c7735a5b0250c0a38ea00fe8de5678e6d1be0d3', - 'androidx.room:room-migration:2.3.0:room-migration-2.3.0.jar:fee2a8a87c22e82e4154e63b7b57939ebc3ed03ba27cf95d64f8235e19e6f17c', - 'androidx.room:room-runtime:2.3.0:room-runtime-2.3.0.aar:3296970e92d85f098f26e776911da3bd9bb084acd37440bd1705fd163f4a93f9', - 'androidx.savedstate:savedstate:1.1.0:savedstate-1.1.0.aar:d60bbe44c2c08083a17c5dc678a6d6b4d0a2d664858016ab5c049cbea90a63b7', - 'androidx.slidingpanelayout:slidingpanelayout:1.0.0:slidingpanelayout-1.0.0.aar:76bffb7cefbf780794d8817002dad1562f3e27c0a9f746d62401c8edb30aeede', - 'androidx.sqlite:sqlite-framework:2.1.0:sqlite-framework-2.1.0.aar:8673737fdb2efbad91aeaeed1927ebb29212d36a867d93b9639c8069019f8a1e', - 'androidx.sqlite:sqlite:2.1.0:sqlite-2.1.0.aar:8341ff092d6060d62a07227f29237155fff36fb16f96c95fbd9a884e375db912', - 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0:swiperefreshlayout-1.0.0.aar:9761b3a809c9b093fd06a3c4bbc645756dec0e95b5c9da419bc9f2a3f3026e8d', - 'androidx.test.espresso:espresso-contrib:3.3.0:espresso-contrib-3.3.0.aar:f400cabdc181356acf6b210e4509dcb9649d9e2b6b6e218c60fcfc15e8a756d1', - 'androidx.test.espresso:espresso-core:3.3.0:espresso-core-3.3.0.aar:23ebf6014645e0c60aec7d1ed924d4d4c848ae8c3673b7d8d06b2ec6a56cafee', - 'androidx.test.espresso:espresso-idling-resource:3.3.0:espresso-idling-resource-3.3.0.aar:29519b112731f289cc6e2f9b2eccc5ea72c754b04272bb93370f45d7e170a7c6', - 'androidx.test.ext:junit:1.1.2:junit-1.1.2.aar:6c6ab120c640bf16fcaae69cb83c144d0ed6b6298562be0ac35e37ed969c0409', - 'androidx.test.uiautomator:uiautomator:2.2.0:uiautomator-2.2.0.aar:2838e9d961dbffefbbd229a2bd4f6f82ac4fb2462975862a9e75e9ed325a3197', - 'androidx.test:core:1.4.0:core-1.4.0.aar:671284e62e393f16ceae1a99a3a9a07bf1aacda29f8fe7b6b884355ef34c09cf', - 'androidx.test:monitor:1.4.0:monitor-1.4.0.aar:46a912a1e175f27a97521af3f50e5af87c22c49275dd2c57c043740012806325', - 'androidx.test:rules:1.3.0:rules-1.3.0.aar:c1753946c498b0d5d7cf341cfed661f66915c4c9deb4ed10462a08ae33b2429a', - 'androidx.test:runner:1.3.0:runner-1.3.0.aar:61d13f5a9fcbbd73ba18fa84e1d6a0111c6e1c665a89b418126966e61fffd93b', - 'androidx.tracing:tracing:1.0.0:tracing-1.0.0.aar:07b8b6139665b884a162eccf97891ca50f7f56831233bf25168ae04f7b568612', - 'androidx.transition:transition:1.0.0:transition-1.0.0.aar:a00a0f763f401abcecda9b0eafcb738929c5801b111a9a414b81a193d0f4008d', - 'androidx.transition:transition:1.2.0:transition-1.2.0.aar:a1e059b3bc0b43a58dec0efecdcaa89c82d2bca552ea5bacf6656c46e853157e', - 'androidx.vectordrawable:vectordrawable-animated:1.0.0:vectordrawable-animated-1.0.0.aar:26c3a0cf0a9a9a7d235a0b00f2f37e431d52d9952751e3eb7c90b4b52c236cf1', - 'androidx.vectordrawable:vectordrawable-animated:1.1.0:vectordrawable-animated-1.1.0.aar:76da2c502371d9c38054df5e2b248d00da87809ed058f3363eae87ce5e2403f8', - 'androidx.vectordrawable:vectordrawable:1.0.0:vectordrawable-1.0.0.aar:507591926583875e3a0e6c46272235f323b4574759b5c02f0ab7a51d2ae7320d', - 'androidx.vectordrawable:vectordrawable:1.1.0:vectordrawable-1.1.0.aar:46fd633ac01b49b7fcabc263bf098c5a8b9e9a69774d234edcca04fb02df8e26', - 'androidx.versionedparcelable:versionedparcelable:1.0.0:versionedparcelable-1.0.0.aar:f6438a93ed8016ccddca0e140a70be0b0110e0424edaa1472f84f98fed2e1ce3', - 'androidx.versionedparcelable:versionedparcelable:1.1.1:versionedparcelable-1.1.1.aar:57e8d93260d18d5b9007c9eed3c64ad159de90c8609ebfc74a347cbd514535a4', - 'androidx.viewpager2:viewpager2:1.0.0:viewpager2-1.0.0.aar:e95c0031d4cc247cd48196c6287e58d2cee54d9c79b85afea7c90920330275af', - 'androidx.viewpager:viewpager:1.0.0:viewpager-1.0.0.aar:147af4e14a1984010d8f155e5e19d781f03c1d70dfed02a8e0d18428b8fc8682', - 'com.github.omadahealth:swipy:1.2.3:swipy-1.2.3.aar:63bff6e181742e3e243c29b595062ca65b4274bf7033c65460924f64f65c01e0', - 'com.github.tony19:logback-android:1.1.1-12:logback-android-1.1.1-12.aar:3102228f0e408e3c003b34e96a604e9b9f59d314dcf8f03aa78d9d3648198932', - 'com.gitlab.opentransitmap:public-transport-enabler:09b90d37bfe452f7845f73aac256fd7eb2ae978a:public-transport-enabler-09b90d37bfe452f7845f73aac256fd7eb2ae978a.jar:7b5a87b91902d0c877357f68be92ffccf971599e2ef529d89bf600febfa87542', - 'com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.0:accessibility-test-framework-2.0.jar:cdf16ef8f5b8023d003ce3cc1b0d51bda737762e2dab2fedf43d1c4292353f7f', - 'com.google.android.flexbox:flexbox:3.0.0:flexbox-3.0.0.aar:5e19500486fd7c8e2e8c7aad6bbba9c8d0ada7057c6b32b9b5c61439814e7574', - 'com.google.android.material:material:1.0.0:material-1.0.0.aar:7680e381a3c03798d999b2e441caadd8a56a0a808e108024a67af9fe26c11adc', - 'com.google.android.material:material:1.5.0:material-1.5.0.aar:b14dc96f95085f26f36aab703b2f791d136b71e91d5e80f0a0364531074a69c7', - 'com.google.auto.value:auto-value-annotations:1.6.3:auto-value-annotations-1.6.3.jar:0e951fee8c31f60270bc46553a8586001b7b93dbb12aec06373aa99a150392c0', - 'com.google.auto:auto-common:0.10:auto-common-0.10.jar:b876b5fddaceeba7d359667f6c4fb8c6f8658da1ab902ffb79ec9a415deede5f', - 'com.google.code.findbugs:jsr305:2.0.1:jsr305-2.0.1.jar:1e7f53fa5b8b5c807e986ba335665da03f18d660802d8bf061823089d1bee468', - 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', - 'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825', - 'com.google.code.gson:gson:2.8.6:gson-2.8.6.jar:c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f', - 'com.google.dagger:dagger-compiler:2.22.1:dagger-compiler-2.22.1.jar:e5f28302cbe70a79d3620cddebfb8ec0736814f3980ffe1e673bfe3342f507d3', - 'com.google.dagger:dagger-producers:2.22.1:dagger-producers-2.22.1.jar:f834a0082014213a68ff06a0f048d750178d02196c58b0b15beb367d32b97e35', - 'com.google.dagger:dagger-spi:2.22.1:dagger-spi-2.22.1.jar:4b0b922793b3bcb91b99fabb75dba77c68afd7ae4c5f0c4fd6ba681f0a291c7d', - 'com.google.dagger:dagger:2.22.1:dagger-2.22.1.jar:329d4340f24c4f5717af016c097e90668bfea2a5376e6aa9964b01cef3fd241a', - 'com.google.devtools.ksp:symbol-processing-api:1.4.30-1.0.0-alpha04:symbol-processing-api-1.4.30-1.0.0-alpha04.jar:6c319c718ebf4b76e05e4e4f156b276d1f7e420a31f62bcb3ce47b4117b8fe6f', - 'com.google.errorprone:error_prone_annotations:2.3.4:error_prone_annotations-2.3.4.jar:baf7d6ea97ce606c53e11b6854ba5f2ce7ef5c24dddf0afa18d1260bd25b002c', - 'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30', - 'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e', - 'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26', - 'com.google.guava:guava:29.0-android:guava-29.0-android.jar:00ba22cb0e32610db7cf8ab4c20017c85d11788600734ff1d86995345eb5bc3b', - 'com.google.guava:guava:29.0-jre:guava-29.0-jre.jar:b22c5fb66d61e7b9522531d04b2f915b5158e80aa0b40ee7282c8bfb07b0da25', - 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99', - 'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b', - 'com.intellij:annotations:12.0:annotations-12.0.jar:f8ab13b14be080fe2f617f90e55599760e4a1b4deeea5c595df63d0d6375ed6d', - 'com.jakewharton.timber:timber:4.7.0:timber-4.7.0.aar:0a0c00e23cae78dd1790e4dfd8b6d1a500f4eaa358c37f6e2a43fa43c8909fe7', - 'com.jakewharton.timber:timber:5.0.1:timber-5.0.1.aar:c6edddfcc8eff42a1604c8577fcfa4b4ffd9f252122c52ea36cfe7967f512f71', - 'com.jraska:falcon:2.2.0:falcon-2.2.0.aar:8b016c6e016ef99fb493b8614b2362cfba540a68ac16a9bb6da310ae10e30b81', - 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.7.0:mapbox-android-gestures-0.7.0.aar:7f1c0e22a1f1c23879dc7faf08fd91b4ca7a8251e08263dbba73ee5a4ebe8ae1', - 'com.mikepenz:aboutlibraries:6.2.0:aboutlibraries-6.2.0.aar:12f8a49ec0fd859bc7ae9e62582d1198cf3f88a200a7115f34906f53284907f6', - 'com.mikepenz:fastadapter-commons:3.3.0:fastadapter-commons-3.3.0.aar:bd6d9d9b3222ad8e8d8ad86e1ec63d3a2ecc44d1684d1ea549563c1357e60c3c', - 'com.mikepenz:fastadapter-extensions-expandable:3.3.0:fastadapter-extensions-expandable-3.3.0.aar:2effaa42a3b82fd92a37317ebf833b9118e8e176426f11250ba903496aa50db7', - 'com.mikepenz:fastadapter:3.3.0:fastadapter-3.3.0.aar:afc2658ee45df47a66615d1a1a2744cb226e11ddf6cc5f0115e07f0620a4fb7c', - 'com.mikepenz:iconics-core:3.1.0:iconics-core-3.1.0.aar:eac6d9a2983412dba7e7e9df82206e0d55c9708149d35d21a72479a8b32a8998', - 'com.mikepenz:materialdrawer:6.1.1:materialdrawer-6.1.1.aar:01d2c1e3b9bb4dbeb9546630afb1494179ed5437443560e2a5159e0f7ed2765b', - 'com.mikepenz:materialize:1.2.0:materialize-1.2.0.aar:9f676d602932398d2d79ef35127d1777baa91a042b8ad3068a0d647463dec1a7', - 'com.squareup.okhttp3:logging-interceptor:3.12.13:logging-interceptor-3.12.13.jar:ee3cd10a2d667621143156f995d4d0fce1dca2b1f3280dd48d821f92afac580a', - 'com.squareup.okhttp3:okhttp:3.12.13:okhttp-3.12.13.jar:508234e024ef7e270ab1a6d5b356f5b98e786511239ca986d684fd1e2cf7bc82', - 'com.squareup.okhttp3:okhttp:4.10.0:okhttp-4.10.0.jar:7580f14fa1691206e37081ad3f92063b1603b328da0bb316f2fef02e0562e7ec', - 'com.squareup.okio:okio-jvm:3.0.0:okio-jvm-3.0.0.jar:be64a0cc1f28ea9cd5c970dd7e7557af72c808d738c495b397bf897c9921e907', - 'com.squareup.okio:okio:1.15.0:okio-1.15.0.jar:693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2', - 'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291', - 'com.squareup:javawriter:2.1.1:javawriter-2.1.1.jar:f699823d0081f69cbb676c1845ea222e0ada79bc88a53e5d22d8bd02d328f57e', - 'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569', - 'de.cketti.library.changelog:ckchangelog:1.2.2:ckchangelog-1.2.2.aar:e113de0f4bc42b983dd6b690b67d76f29975167c2204e3792831961740889d78', - 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', - 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', - 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', - 'junit:junit:4.13.1:junit-4.13.1.jar:c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122', - 'net.bytebuddy:byte-buddy-agent:1.14.6:byte-buddy-agent-1.14.6.jar:aed93d1b77c87494f03c7c420f6c9861560dfc55dc8ad914192fcc1c57307f0b', - 'net.bytebuddy:byte-buddy:1.14.6:byte-buddy-1.14.6.jar:6eaf0190ee02731820e9925a544e7cfb48f6dfc3bf29e6dd87d267ad59862df0', - 'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf', - 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', - 'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a', - 'org.checkerframework:checker-qual:2.11.1:checker-qual-2.11.1.jar:015224a4b1dc6de6da053273d4da7d39cfea20e63038169fc45ac0d1dc9c5938', - 'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', - 'org.hamcrest:hamcrest-integration:1.3:hamcrest-integration-1.3.jar:70f418efbb506c5155da5f9a5a33262ea08a9e4d7fea186aa9015c41a7224ac2', - 'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c', - 'org.jacoco:org.jacoco.agent:0.8.8:org.jacoco.agent-0.8.8.jar:072ecbd496896623899a696fff12c01c1615f737616d2792e6d0e10cdf8a610d', - 'org.jacoco:org.jacoco.ant:0.8.8:org.jacoco.ant-0.8.8.jar:02e33bd2c48dc0be67c2fea84d43beececfd400da6797c58153253d4c30aca15', - 'org.jacoco:org.jacoco.core:0.8.8:org.jacoco.core-0.8.8.jar:474c782f809d88924713dfdbf0acb79d330f904be576484803463d0465611643', - 'org.jacoco:org.jacoco.report:0.8.8:org.jacoco.report-0.8.8.jar:2c129110f3e3fcaa1f8179578ea3894586199cb0826be5c7790278084c9622a9', - 'org.jetbrains.intellij.deps:trove4j:1.0.20200330:trove4j-1.0.20200330.jar:c5fd725bffab51846bf3c77db1383c60aaaebfe1b7fe2f00d23fe1b7df0a439d', - 'org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.7.10:kotlin-android-extensions-runtime-1.7.10.jar:7be8747f085a8e10588bb5a49b760e0e9d23ac9b6470632e93fffac469fb1990', - 'org.jetbrains.kotlin:kotlin-android-extensions:1.7.10:kotlin-android-extensions-1.7.10.jar:8848ab3627e888adce1ca54d0e0f348f269928f327b1a305a9450cc41f599729', - 'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.7.10:kotlin-annotation-processing-gradle-1.7.10.jar:5351105490f668a4582966ee149ccd5eaf286f7a0b4cf7a301268b8b8910dfd1', - 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10:kotlin-compiler-embeddable-1.7.10.jar:470ba8941794f818a34b0a8f387ee27e44268e95a108322d18d9749ae345e22b', - 'org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10:kotlin-daemon-embeddable-1.7.10.jar:77c5f3ab1ed653a899e96835937a9daf3a46e496fdfa6915ff6d20b2953619a4', - 'org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10:kotlin-klib-commonizer-embeddable-1.7.10.jar:1c2550f1e7ec4d1590aacddd7852b90a4cf05de6e66cee31ad747c8dc0834e33', - 'org.jetbrains.kotlin:kotlin-reflect:1.7.10:kotlin-reflect-1.7.10.jar:187c5e5a588a6ed18c3a41b54df138a5944121bdb396be1c3fa4abee67397955', - 'org.jetbrains.kotlin:kotlin-script-runtime:1.7.10:kotlin-script-runtime-1.7.10.jar:84bfc2aa4eec6768113930cdaef8b5b9f59ac4138fbca3b11300fff4d076950c', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31:kotlin-stdlib-common-1.4.31.jar:57962f44371a746b678218a0802a8712c6255206de9a69ede215e3aa4b044708', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10:kotlin-stdlib-common-1.7.10.jar:19f102efe9629f8eabc63853ad15c533e47c47f91fca09285c5bde86e59f91d4', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.20:kotlin-stdlib-common-1.7.20.jar:e0e91962bc0007338bf5b1739f62927ac32d14ba3d827fa608ab4e5351729d5d', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31:kotlin-stdlib-jdk7-1.4.31.jar:1f966e54e86cf4b7d7014afdce04e0f3ee4625084cda3494edccc7b84af52664', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20:kotlin-stdlib-jdk7-1.7.20.jar:524da3c1a2ad56fd52c4ae2272ef3de421de8d2047ab1c51fc306d351243f2f5', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31:kotlin-stdlib-jdk8-1.4.31.jar:b2f8364435ebcb0106ff9d4415a11ffdef8ec7786ee6e5ed465a01556cbd1683', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20:kotlin-stdlib-jdk8-1.7.20.jar:1da0d306c995945e1f807240ef64b5cd2dd5ac58612afb1a8596143d10b7ded5', - 'org.jetbrains.kotlin:kotlin-stdlib:1.4.31:kotlin-stdlib-1.4.31.jar:76a599d88b167e8ac90879b6daa722c6ad3452ba714c9aba19bd196544b97f1c', - 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10:kotlin-stdlib-1.7.10.jar:e771fe74250a943e8f6346713201ff1d8cb95c3a5d1a91a22b65a9e04f6a8901', - 'org.jetbrains.kotlin:kotlin-stdlib:1.7.20:kotlin-stdlib-1.7.20.jar:7779ec96b9acbf92ca023858ac04543f9d2c3bdf1722425fff42f25ff3acfc9b', - 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.2.0:kotlinx-metadata-jvm-0.2.0.jar:a973efbc4571dcf5b02462b79f92f384e428886b287f12a9a2b41601ef971a5c', - 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', - 'org.jetbrains:annotations:20.1.0:annotations-20.1.0.jar:edc8e3ec9796a5f41c1ae44b2d318507ee6ac1212f121d93d33699b3d0aff638', - 'org.maplibre.gl:android-sdk-geojson:5.9.0:android-sdk-geojson-5.9.0.jar:54a54bf7fc853d2eec36b97a2979ec0904aea83762e41ebfadac21c8b1cdc838', - 'org.maplibre.gl:android-sdk-turf:5.9.0:android-sdk-turf-5.9.0.jar:b593fd4de144efa8a4c7cbafef7789c4d69c45372ec7bf01a14f973444c7d214', - 'org.maplibre.gl:android-sdk:10.2.0:android-sdk-10.2.0.aar:e45fcc7f6a195114be1df22cb9f5d8d0fde00252925b984ded4a3ce5edd46a4a', - 'org.mockito:mockito-core:2.19.0:mockito-core-2.19.0.jar:d6ac2e04164c5d5c89e73838dc1c8b3856ca6582d3f2daf91816fd9d7ba3c9a9', - 'org.mockito:mockito-core:5.5.0:mockito-core-5.5.0.jar:ebfa1aa7f5acd96f4fdf04576d56c1c9f5146574a2bb3dd1faccf74d72bc9230', - 'org.objenesis:objenesis:2.6:objenesis-2.6.jar:5e168368fbc250af3c79aa5fef0c3467a2d64e5a7bd74005f25d8399aeb0708d', - 'org.objenesis:objenesis:3.3:objenesis-3.3.jar:02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb', - 'org.ow2.asm:asm-analysis:9.2:asm-analysis-9.2.jar:878fbe521731c072d14d2d65b983b1beae6ad06fda0007b6a8bae81f73f433c4', - 'org.ow2.asm:asm-commons:9.2:asm-commons-9.2.jar:be4ce53138a238bb522cd781cf91f3ba5ce2f6ca93ec62d46a162a127225e0a6', - 'org.ow2.asm:asm-tree:9.2:asm-tree-9.2.jar:aabf9bd23091a4ebfc109c1f3ee7cf3e4b89f6ba2d3f51c5243f16b3cffae011', - 'org.ow2.asm:asm:9.2:asm-9.2.jar:b9d4fe4d71938df38839f0eca42aaaa64cf8b313d678da036f0cb3ca199b47f5', - 'org.slf4j:slf4j-api:2.0.9:slf4j-api-2.0.9.jar:0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c', - 'org.xerial:sqlite-jdbc:3.25.2:sqlite-jdbc-3.25.2.jar:a45da61abed61568a533fdece125093180828edeb0d4b6f6d572e0cf457465f6', - 'tools.fastlane:screengrab:2.1.1:screengrab-2.1.1.aar:5a02781c0986e71ddbc691263115c2db70bdebb4b48d5b6dcf06ab1cb547d62d', - 'uk.co.samuelwall:material-tap-target-prompt:2.14.0:material-tap-target-prompt-2.14.0.aar:12ab447ba97019adbecb20e048921ca30ed7a9f72a37b83f39a4333bd759b518', - ] -} diff --git a/build.gradle b/build.gradle index 7e0d5b991..d02f3fe26 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,8 @@ buildscript { ext { - kotlinVersion = '1.7.10' + kotlinVersion = '2.3.21' + agpVersion = '9.0.0' daggerVersion = '2.22.1' fastadapterVersion = '3.2.4@aar' } @@ -12,9 +13,10 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath "com.android.tools.build:gradle:$agpVersion" + // todo: migrate to KSP instead, see https://developer.android.com/build/migrate-to-ksp + classpath "com.android.legacy-kapt:com.android.legacy-kapt.gradle.plugin:$agpVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - classpath files('app/libs/gradle-witness.jar') } } diff --git a/gradle.properties b/gradle.properties index 0cdab843a..7ff15e97c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,11 @@ org.gradle.jvmargs=-Xmx2g android.enableJetifier=true -android.useAndroidX=true -noWitness=androidApis \ No newline at end of file +android.nonFinalResIds=false +android.nonTransitiveRClass=false +android.defaults.buildfeatures.resvalues=true +# todo: migrate switch cases to chained if-statements +android.enableAppCompileTimeRClass=false +android.usesSdkInManifest.disallowed=false +# todo: remove, then test with release build +android.r8.strictFullModeForKeepRules=false +android.r8.optimizedResourceShrinking=false \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml new file mode 100644 index 000000000..587812155 --- /dev/null +++ b/gradle/verification-metadata.xml @@ -0,0 +1,3100 @@ + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ef80eb505..db822449b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=97a52d145762adc241bad7fd18289bf7f6801e08ece6badf80402fe2b9f250b1 -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionSha256Sum=f86344275d1b194688dd330abf9f6f2344cd02872ffee035f2d1ea2fd60cf7f3 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/update-dependency-pinning.sh b/update-dependency-pinning.sh index c922650a2..c90134773 100755 --- a/update-dependency-pinning.sh +++ b/update-dependency-pinning.sh @@ -1,7 +1,3 @@ #!/bin/bash -WITNESS=app/witness.gradle - -echo "" > $WITNESS -./gradlew -q calculateChecksums | grep -Ev "^(Skipping|Verifying)" | grep -Ev "files-2.1:|caches:transforms-3:|:build-tools:core-lambda-stubs.jar:|:platforms:core-for-system-modules.jar:|-linux.jar:" > $WITNESS - +./gradlew --write-verification-metadata sha256,pgp