diff --git a/app/build.gradle b/app/build.gradle
index 022ab585..222667ed 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -36,8 +36,8 @@ android {
compileSdk 34
minSdk 26
targetSdk 34
- versionCode 84
- versionName "14.7.0"
+ versionCode 85
+ versionName "15.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
diff --git a/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ExampleInstrumentationTest.kt b/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ExampleInstrumentationTest.kt
index 93ec7949..e0c8a9ed 100644
--- a/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ExampleInstrumentationTest.kt
+++ b/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ExampleInstrumentationTest.kt
@@ -1,23 +1,20 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
+package de.bahnhoefe.deutschlands.bahnhofsfotos
-import static org.assertj.core.api.Assertions.assertThat;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.jupiter.api.Test;
+import androidx.test.platform.app.InstrumentationRegistry
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.Test
/**
* Instrumentation test, which will execute on an Android device.
*
- * @see Testing documentation
+ * @see [Testing documentation](http://d.android.com/tools/testing)
*/
-public class ExampleInstrumentationTest {
-
+class ExampleInstrumentationTest {
@Test
- public void useAppContext() {
+ fun useAppContext() {
// Context of the app under test.
- var appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- assertThat(appContext.getPackageName()).isEqualTo("de.bahnhoefe.deutschlands.bahnhofsfotos.debug");
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertThat(appContext.packageName)
+ .isEqualTo("de.bahnhoefe.deutschlands.bahnhofsfotos.debug")
}
}
\ No newline at end of file
diff --git a/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/util/TimetableTest.kt b/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/util/TimetableTest.kt
index f3278529..d7399b62 100644
--- a/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/util/TimetableTest.kt
+++ b/app/src/androidTest/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/util/TimetableTest.kt
@@ -1,44 +1,47 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos.util;
+package de.bahnhoefe.deutschlands.bahnhofsfotos.util
-import static org.assertj.core.api.Assertions.assertThat;
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-
-public class TimetableTest {
-
- private Station station;
+class TimetableTest {
+ private var station: Station? = null
@BeforeEach
- public void setUp() {
- station = new Station(
- "de",
- "4711",
- "Some Famous Station",
- 0.0,
- 0.0,
- "LOL");
+ fun setUp() {
+ station = Station(
+ "de",
+ "4711",
+ "Some Famous Station",
+ 0.0,
+ 0.0,
+ "LOL"
+ )
}
@Test
- public void createTimetableIntentWithId() {
- var country = new Country("de", "Deutschland", null, "https://example.com/{id}/blah");
- assertThat(new Timetable().createTimetableIntent(country, station).getData().toString()).isEqualTo("https://example.com/4711/blah");
+ fun createTimetableIntentWithId() {
+ val country = Country("de", "Deutschland", null, "https://example.com/{id}/blah")
+ assertThat(
+ Timetable().createTimetableIntent(country, station)!!.data.toString()
+ ).isEqualTo("https://example.com/4711/blah")
}
@Test
- public void createTimetableIntentWithTitle() {
- var country = new Country("de", "Deutschland", null, "https://example.com/{title}/blah");
- assertThat(new Timetable().createTimetableIntent(country, station).getData().toString()).isEqualTo("https://example.com/Some Famous Station/blah");
+ fun createTimetableIntentWithTitle() {
+ val country = Country("de", "Deutschland", null, "https://example.com/{title}/blah")
+ assertThat(
+ Timetable().createTimetableIntent(country, station)!!.data.toString()
+ ).isEqualTo("https://example.com/Some Famous Station/blah")
}
@Test
- public void createTimetableIntentWithDS100() {
- var country = new Country("de", "Deutschland", null, "https://example.com/{DS100}/blah");
- assertThat(new Timetable().createTimetableIntent(country, station).getData().toString()).isEqualTo("https://example.com/LOL/blah");
+ fun createTimetableIntentWithDS100() {
+ val country = Country("de", "Deutschland", null, "https://example.com/{DS100}/blah")
+ assertThat(
+ Timetable().createTimetableIntent(country, station)!!.data.toString()
+ ).isEqualTo("https://example.com/LOL/blah")
}
-
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/BaseApplication.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/BaseApplication.kt
index 269ea138..c3df1dfa 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/BaseApplication.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/BaseApplication.kt
@@ -1,444 +1,400 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.annotation.SuppressLint;
-import android.app.Application;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.location.Location;
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.multidex.MultiDex;
-import androidx.security.crypto.EncryptedSharedPreferences;
-import androidx.security.crypto.MasterKey;
-
-import org.apache.commons.lang3.StringUtils;
-import org.mapsforge.core.model.LatLong;
-import org.mapsforge.core.model.MapPosition;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.License;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Profile;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UpdatePolicy;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.ExceptionHandler;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter;
-
-public class BaseApplication extends Application {
-
- private static final String TAG = BaseApplication.class.getSimpleName();
- private static final Boolean DEFAULT_FIRSTAPPSTART = false;
- private static final String DEFAULT = "";
- private static BaseApplication instance;
-
- public static final String DEFAULT_COUNTRY = "de";
- public static final String PREF_FILE = "APP_PREF_FILE";
-
- private DbAdapter dbAdapter;
- private RSAPIClient rsapiClient;
- private SharedPreferences preferences;
- private SharedPreferences encryptedPreferences;
-
- public BaseApplication() {
- setInstance(this);
- }
-
- public DbAdapter getDbAdapter() {
- return dbAdapter;
- }
-
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- MultiDex.install(this);
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import android.content.SharedPreferences
+import android.location.Location
+import android.net.Uri
+import android.os.Build
+import android.util.Log
+import androidx.multidex.MultiDex
+import androidx.security.crypto.EncryptedSharedPreferences
+import androidx.security.crypto.MasterKey
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.License
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Profile
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UpdatePolicy
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.ExceptionHandler
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter
+import org.apache.commons.lang3.StringUtils
+import org.mapsforge.core.model.LatLong
+import org.mapsforge.core.model.MapPosition
+import java.util.Optional
+
+class BaseApplication : Application() {
+ lateinit var dbAdapter: DbAdapter
+ lateinit var rsapiClient: RSAPIClient
+ private lateinit var preferences: SharedPreferences
+ private lateinit var encryptedPreferences: SharedPreferences
+
+ init {
+ instance = this
+ }
+
+ override fun attachBaseContext(base: Context) {
+ super.attachBaseContext(base)
+ MultiDex.install(this)
// handle crashes only outside the crash reporter activity/process
- if (!isCrashReportingProcess()) {
+ if (!isCrashReportingProcess) {
Thread.setDefaultUncaughtExceptionHandler(
- new ExceptionHandler(this, Thread.getDefaultUncaughtExceptionHandler()));
+ Thread.getDefaultUncaughtExceptionHandler()?.let { ExceptionHandler(this, it) }
+ )
}
}
- private boolean isCrashReportingProcess() {
- var processName = "";
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
- // Using the same technique as Application.getProcessName() for older devices
- // Using reflection since ActivityThread is an internal API
- try {
- @SuppressLint("PrivateApi")
- var activityThread = Class.forName("android.app.ActivityThread");
- @SuppressLint("DiscouragedPrivateApi")
- var getProcessName = activityThread.getDeclaredMethod("currentProcessName");
- processName = (String) getProcessName.invoke(null);
- } catch (Exception ignored) {
+ private val isCrashReportingProcess: Boolean
+ get() {
+ var processName: String? = ""
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
+ // Using the same technique as Application.getProcessName() for older devices
+ // Using reflection since ActivityThread is an internal API
+ try {
+ @SuppressLint("PrivateApi") val activityThread =
+ Class.forName("android.app.ActivityThread")
+ @SuppressLint("DiscouragedPrivateApi") val getProcessName =
+ activityThread.getDeclaredMethod("currentProcessName")
+ processName = getProcessName.invoke(null) as String
+ } catch (ignored: Exception) {
+ }
+ } else {
+ processName = getProcessName()
}
- } else {
- processName = Application.getProcessName();
+ return processName != null && processName.endsWith(":crash")
}
- return processName != null && processName.endsWith(":crash");
- }
-
- private static void setInstance(@NonNull BaseApplication application) {
- instance = application;
- }
- public static BaseApplication getInstance() {
- return instance;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- dbAdapter = new DbAdapter(this);
- dbAdapter.open();
-
- preferences = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
+ override fun onCreate() {
+ super.onCreate()
+ dbAdapter = DbAdapter(this)
+ dbAdapter.open()
+ preferences = getSharedPreferences(PREF_FILE, MODE_PRIVATE)
// Creates the instance for the encrypted preferences.
- encryptedPreferences = null;
- try {
- var masterKey = new MasterKey.Builder(this)
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
- .build();
-
- encryptedPreferences = EncryptedSharedPreferences.create(
- this,
- "secret_shared_prefs",
- masterKey,
- EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
- EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
- );
-
- // migrate access token from unencrypted to encrypted preferences
- if (!encryptedPreferences.contains(getString(R.string.ACCESS_TOKEN))
- && preferences.contains(getString(R.string.ACCESS_TOKEN))) {
- setAccessToken(preferences.getString(getString(R.string.ACCESS_TOKEN), null));
- preferences.edit().remove(getString(R.string.ACCESS_TOKEN)).apply();
- }
- } catch (GeneralSecurityException | IOException e) {
- Log.w("Unable to create EncryptedSharedPreferences, fallback to unencrypted preferences", e);
+ encryptedPreferences = try {
+ val masterKey = MasterKey.Builder(this)
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
+ .build()
+ EncryptedSharedPreferences.create(
+ this,
+ "secret_shared_prefs",
+ masterKey,
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
+ )
+ } catch (e: Exception) {
+ Log.w(
+ TAG,
+ "Unable to create EncryptedSharedPreferences, fallback to unencrypted preferences",
+ e
+ )
+ preferences
+ }
+ // migrate access token from unencrypted to encrypted preferences
+ if (encryptedPreferences != preferences
+ && !encryptedPreferences.contains(getString(R.string.ACCESS_TOKEN))
+ && preferences.contains(getString(R.string.ACCESS_TOKEN))
+ ) {
+ accessToken = preferences.getString(getString(R.string.ACCESS_TOKEN), null)
+ preferences.edit().remove(getString(R.string.ACCESS_TOKEN)).apply()
}
// migrate photo owner preference to boolean
- var photoOwner = preferences.getAll().get(getString(R.string.PHOTO_OWNER));
- if ("YES".equals(photoOwner)) {
- setPhotoOwner(true);
+ val photoOwner = preferences.all[getString(R.string.PHOTO_OWNER)]
+ if ("YES" == photoOwner) {
+ this.photoOwner = true
}
-
- rsapiClient = new RSAPIClient(getApiUrl(), getString(R.string.rsapiClientId), getAccessToken(), getString(R.string.rsapiRedirectScheme) + "://" + getString(R.string.rsapiRedirectHost));
- }
-
- public String getApiUrl() {
- var apiUri = preferences.getString(getString(R.string.API_URL), null);
- return getValidatedApiUrlString(apiUri);
+ rsapiClient = RSAPIClient(
+ apiUrl!!, getString(R.string.rsapiClientId), accessToken, getString(
+ R.string.rsapiRedirectScheme
+ ) + "://" + getString(R.string.rsapiRedirectHost)
+ )
}
- private static String getValidatedApiUrlString(final String apiUrl) {
- var uri = toUri(apiUrl);
- if (uri.isPresent()) {
- var scheme = uri.get().getScheme();
- if (scheme != null && scheme.matches("https?")) {
- return apiUrl + (apiUrl.endsWith("/") ? "" : "/");
- }
+ var apiUrl: String?
+ get() {
+ val apiUri = preferences.getString(getString(R.string.API_URL), null)
+ return getValidatedApiUrlString(apiUri)
+ }
+ set(apiUrl) {
+ val validatedUrl = getValidatedApiUrlString(apiUrl)
+ putString(R.string.API_URL, validatedUrl)
+ rsapiClient.setBaseUrl(validatedUrl)
}
- return "https://api.railway-stations.org/";
- }
-
- public void setApiUrl(String apiUrl) {
- var validatedUrl = getValidatedApiUrlString(apiUrl);
- putString(R.string.API_URL, validatedUrl);
- rsapiClient.setBaseUrl(validatedUrl);
+ private fun putBoolean(key: Int, value: Boolean) {
+ val editor = preferences.edit()
+ editor.putBoolean(getString(key), value)
+ editor.apply()
}
- private void putBoolean(int key, boolean value) {
- var editor = preferences.edit();
- editor.putBoolean(getString(key), value);
- editor.apply();
+ private fun putString(key: Int, value: String?) {
+ val editor = preferences.edit()
+ editor.putString(getString(key), StringUtils.trimToNull(value))
+ editor.apply()
}
- private void putString(int key, String value) {
- var editor = preferences.edit();
- editor.putString(getString(key), StringUtils.trimToNull(value));
- editor.apply();
+ private fun putStringSet(key: Int, value: Set?) {
+ val editor = preferences.edit()
+ editor.putStringSet(getString(key), value)
+ editor.apply()
}
- private void putStringSet(int key, Set value) {
- var editor = preferences.edit();
- editor.putStringSet(getString(key), value);
- editor.apply();
+ private fun putLong(key: Int, value: Long) {
+ val editor = preferences.edit()
+ editor.putLong(getString(key), value)
+ editor.apply()
}
- private void putLong(int key, long value) {
- var editor = preferences.edit();
- editor.putLong(getString(key), value);
- editor.apply();
+ private fun putDouble(key: Int, value: Double) {
+ val editor = preferences.edit()
+ editor.putLong(getString(key), java.lang.Double.doubleToRawLongBits(value))
+ editor.apply()
}
- private void putDouble(int key, double value) {
- var editor = preferences.edit();
- editor.putLong(getString(key), Double.doubleToRawLongBits(value));
- editor.apply();
+ private fun getDouble(key: Int): Double {
+ return if (!preferences.contains(getString(key))) {
+ 0.0
+ } else java.lang.Double.longBitsToDouble(preferences.getLong(getString(key), 0))
}
- private double getDouble(int key) {
- if (!preferences.contains(getString(key))) {
- return 0.0;
+ var countryCodes: Set
+ get() {
+ val oldCountryCode =
+ preferences.getString(getString(R.string.COUNTRY), DEFAULT_COUNTRY)
+ var stringSet = preferences.getStringSet(
+ getString(R.string.COUNTRIES),
+ HashSet(setOf(oldCountryCode))
+ )
+ if (stringSet!!.isEmpty()) {
+ stringSet = HashSet(setOf(DEFAULT_COUNTRY))
+ }
+ return stringSet
}
-
- return Double.longBitsToDouble(preferences.getLong(getString(key), 0));
- }
-
- public void setCountryCodes(Set countryCodes) {
- putStringSet(R.string.COUNTRIES, countryCodes);
- }
-
- public Set getCountryCodes() {
- var oldCountryCode = preferences.getString(getString(R.string.COUNTRY), DEFAULT_COUNTRY);
- var stringSet = preferences.getStringSet(getString(R.string.COUNTRIES), new HashSet<>(Collections.singleton(oldCountryCode)));
- if (stringSet.isEmpty()) {
- stringSet = new HashSet<>(Collections.singleton(DEFAULT_COUNTRY));
+ set(countryCodes) {
+ putStringSet(R.string.COUNTRIES, countryCodes)
}
- return stringSet;
- }
-
- public void setFirstAppStart(boolean firstAppStart) {
- putBoolean(R.string.FIRSTAPPSTART, firstAppStart);
- }
-
- public boolean getFirstAppStart() {
- return preferences.getBoolean(getString(R.string.FIRSTAPPSTART), DEFAULT_FIRSTAPPSTART);
- }
-
- public License getLicense() {
- return License.byName(preferences.getString(getString(R.string.LICENCE), License.UNKNOWN.toString()));
- }
-
- public void setLicense(License license) {
- putString(R.string.LICENCE, license != null ? license.toString() : License.UNKNOWN.toString());
- }
-
- public UpdatePolicy getUpdatePolicy() {
- return UpdatePolicy.byName(preferences.getString(getString(R.string.UPDATE_POLICY), License.UNKNOWN.toString()));
- }
-
- public void setUpdatePolicy(UpdatePolicy updatePolicy) {
- putString(R.string.UPDATE_POLICY, updatePolicy.toString());
- }
-
- public boolean getPhotoOwner() {
- return preferences.getBoolean(getString(R.string.PHOTO_OWNER), false);
- }
-
- public void setPhotoOwner(boolean photoOwner) {
- putBoolean(R.string.PHOTO_OWNER, photoOwner);
- }
-
- public String getPhotographerLink() {
- return preferences.getString(getString(R.string.LINK_TO_PHOTOGRAPHER), DEFAULT);
- }
-
- public void setPhotographerLink(String photographerLink) {
- putString(R.string.LINK_TO_PHOTOGRAPHER, photographerLink);
- }
-
- public String getNickname() {
- return preferences.getString(getString(R.string.NICKNAME), DEFAULT);
- }
-
- public void setNickname(String nickname) {
- putString(R.string.NICKNAME, nickname);
- }
-
- public String getEmail() {
- return preferences.getString(getString(R.string.EMAIL), DEFAULT);
- }
-
- public void setEmail(String email) {
- putString(R.string.EMAIL, email);
- }
-
- public boolean isEmailVerified() {
- return preferences.getBoolean(getString(R.string.PHOTO_OWNER), false);
- }
-
- public void setEmailVerified(boolean emailVerified) {
- putBoolean(R.string.PHOTO_OWNER, emailVerified);
- }
-
- public String getAccessToken() {
- return encryptedPreferences.getString(getString(R.string.ACCESS_TOKEN), null);
- }
-
- public void setAccessToken(String apiToken) {
- var editor = encryptedPreferences.edit();
- editor.putString(getString(R.string.ACCESS_TOKEN), StringUtils.trimToNull(apiToken));
- editor.apply();
- }
-
- public StationFilter getStationFilter() {
- var photoFilter = getOptionalBoolean(R.string.STATION_FILTER_PHOTO);
- var activeFilter = getOptionalBoolean(R.string.STATION_FILTER_ACTIVE);
- var nicknameFilter = preferences.getString(getString(R.string.STATION_FILTER_NICKNAME), null);
- return new StationFilter(photoFilter, activeFilter, nicknameFilter);
- }
-
- private Boolean getOptionalBoolean(int key) {
- if (preferences.contains(getString(key))) {
- return Boolean.valueOf(preferences.getString(getString(key), "false"));
+ var firstAppStart: Boolean
+ get() = preferences.getBoolean(getString(R.string.FIRSTAPPSTART), DEFAULT_FIRSTAPPSTART)
+ set(firstAppStart) {
+ putBoolean(R.string.FIRSTAPPSTART, firstAppStart)
+ }
+ var license: License?
+ get() = License.byName(
+ preferences.getString(
+ getString(R.string.LICENCE),
+ License.UNKNOWN.toString()
+ )!!
+ )
+ set(license) {
+ putString(R.string.LICENCE, license?.toString() ?: License.UNKNOWN.toString())
+ }
+ var updatePolicy: UpdatePolicy
+ get() = UpdatePolicy.byName(
+ preferences.getString(
+ getString(R.string.UPDATE_POLICY),
+ License.UNKNOWN.toString()
+ )!!
+ )
+ set(updatePolicy) {
+ putString(R.string.UPDATE_POLICY, updatePolicy.toString())
+ }
+ private var photoOwner: Boolean
+ get() = preferences.getBoolean(getString(R.string.PHOTO_OWNER), false)
+ set(photoOwner) {
+ putBoolean(R.string.PHOTO_OWNER, photoOwner)
+ }
+ private var photographerLink: String?
+ get() = preferences.getString(getString(R.string.LINK_TO_PHOTOGRAPHER), DEFAULT)
+ set(photographerLink) {
+ putString(R.string.LINK_TO_PHOTOGRAPHER, photographerLink)
+ }
+ var nickname: String?
+ get() = preferences.getString(getString(R.string.NICKNAME), DEFAULT)
+ set(nickname) {
+ putString(R.string.NICKNAME, nickname)
+ }
+ var email: String?
+ get() = preferences.getString(getString(R.string.EMAIL), DEFAULT)
+ set(email) {
+ putString(R.string.EMAIL, email)
+ }
+ private var isEmailVerified: Boolean
+ get() = preferences.getBoolean(getString(R.string.PHOTO_OWNER), false)
+ set(emailVerified) {
+ putBoolean(R.string.PHOTO_OWNER, emailVerified)
+ }
+ var accessToken: String?
+ get() = encryptedPreferences.getString(getString(R.string.ACCESS_TOKEN), null)
+ set(apiToken) {
+ val editor = encryptedPreferences.edit()
+ editor.putString(getString(R.string.ACCESS_TOKEN), StringUtils.trimToNull(apiToken))
+ editor.apply()
+ }
+ var stationFilter: StationFilter
+ get() {
+ val photoFilter = getOptionalBoolean(R.string.STATION_FILTER_PHOTO)
+ val activeFilter = getOptionalBoolean(R.string.STATION_FILTER_ACTIVE)
+ val nicknameFilter =
+ preferences.getString(getString(R.string.STATION_FILTER_NICKNAME), null)
+ return StationFilter(photoFilter, activeFilter, nicknameFilter)
+ }
+ set(stationFilter) {
+ putString(
+ R.string.STATION_FILTER_PHOTO,
+ if (stationFilter.hasPhoto() == null) null else stationFilter.hasPhoto()
+ .toString()
+ )
+ putString(
+ R.string.STATION_FILTER_ACTIVE,
+ if (stationFilter.isActive == null) null else stationFilter.isActive.toString()
+ )
+ putString(R.string.STATION_FILTER_NICKNAME, stationFilter.nickname)
}
- return null;
- }
-
- public void setStationFilter(StationFilter stationFilter) {
- putString(R.string.STATION_FILTER_PHOTO, stationFilter.hasPhoto() == null ? null : stationFilter.hasPhoto().toString());
- putString(R.string.STATION_FILTER_ACTIVE, stationFilter.isActive() == null ? null : stationFilter.isActive().toString());
- putString(R.string.STATION_FILTER_NICKNAME, stationFilter.getNickname());
- }
-
- public long getLastUpdate() {
- return preferences.getLong(getString(R.string.LAST_UPDATE), 0L);
- }
-
- public void setLastUpdate(long lastUpdate) {
- putLong(R.string.LAST_UPDATE, lastUpdate);
- }
-
- public void setLocationUpdates(boolean locationUpdates) {
- putBoolean(R.string.LOCATION_UPDATES, locationUpdates);
- }
-
- public boolean isLocationUpdates() {
- return preferences.getBoolean(getString(R.string.LOCATION_UPDATES), true);
- }
-
- public void setLastMapPosition(MapPosition lastMapPosition) {
- putDouble(R.string.LAST_POSITION_LAT, lastMapPosition.latLong.latitude);
- putDouble(R.string.LAST_POSITION_LON, lastMapPosition.latLong.longitude);
- putLong(R.string.LAST_POSITION_ZOOM, lastMapPosition.zoomLevel);
- }
-
- public MapPosition getLastMapPosition() {
- var latLong = new LatLong(getDouble(R.string.LAST_POSITION_LAT), getDouble(R.string.LAST_POSITION_LON));
- return new MapPosition(latLong, (byte) preferences.getLong(getString(R.string.LAST_POSITION_ZOOM), getZoomLevelDefault()));
- }
-
- public Location getLastLocation() {
- var location = new Location("");
- location.setLatitude(getDouble(R.string.LAST_POSITION_LAT));
- location.setLongitude(getDouble(R.string.LAST_POSITION_LON));
- return location;
- }
-
- /**
- * @return the default starting zoom level if nothing is encoded in the map file.
- */
- public byte getZoomLevelDefault() {
- return (byte) 12;
- }
- public boolean getAnonymous() {
- return preferences.getBoolean(getString(R.string.ANONYMOUS), false);
+ private fun getOptionalBoolean(key: Int): Boolean? {
+ return if (preferences.contains(getString(key))) {
+ java.lang.Boolean.valueOf(preferences.getString(getString(key), "false"))
+ } else null
}
- public void setAnonymous(boolean anonymous) {
- putBoolean(R.string.ANONYMOUS, anonymous);
- }
+ var lastUpdate: Long
+ get() = preferences.getLong(getString(R.string.LAST_UPDATE), 0L)
+ set(lastUpdate) {
+ putLong(R.string.LAST_UPDATE, lastUpdate)
+ }
+ var isLocationUpdates: Boolean
+ get() = preferences.getBoolean(getString(R.string.LOCATION_UPDATES), true)
+ set(locationUpdates) {
+ putBoolean(R.string.LOCATION_UPDATES, locationUpdates)
+ }
+ var lastMapPosition: MapPosition
+ get() {
+ val latLong = LatLong(
+ getDouble(R.string.LAST_POSITION_LAT),
+ getDouble(R.string.LAST_POSITION_LON)
+ )
+ return MapPosition(
+ latLong,
+ preferences.getLong(
+ getString(R.string.LAST_POSITION_ZOOM),
+ zoomLevelDefault.toLong()
+ ).toByte()
+ )
+ }
+ set(lastMapPosition) {
+ putDouble(R.string.LAST_POSITION_LAT, lastMapPosition.latLong.latitude)
+ putDouble(R.string.LAST_POSITION_LON, lastMapPosition.latLong.longitude)
+ putLong(R.string.LAST_POSITION_ZOOM, lastMapPosition.zoomLevel.toLong())
+ }
+ val lastLocation: Location
+ get() {
+ val location = Location("")
+ location.latitude = getDouble(R.string.LAST_POSITION_LAT)
+ location.longitude = getDouble(R.string.LAST_POSITION_LON)
+ return location
+ }
+ val zoomLevelDefault: Byte
+ /**
+ * @return the default starting zoom level if nothing is encoded in the map file.
+ */
+ get() = 12.toByte()
+ var anonymous: Boolean
+ get() = preferences.getBoolean(getString(R.string.ANONYMOUS), false)
+ set(anonymous) {
+ putBoolean(R.string.ANONYMOUS, anonymous)
+ }
+ var profile: Profile?
+ get() = Profile(
+ nickname,
+ license,
+ photoOwner,
+ anonymous,
+ photographerLink,
+ email,
+ isEmailVerified
+ )
+ set(profile) {
+ license = profile!!.license
+ photoOwner = profile.photoOwner
+ anonymous = profile.anonymous
+ photographerLink = profile.link
+ nickname = profile.nickname
+ email = profile.email
+ isEmailVerified = profile.emailVerified
+ }
+ var map: String?
+ get() = preferences.getString(getString(R.string.MAP_FILE), null)
+ set(map) {
+ putString(R.string.MAP_FILE, map)
+ }
- public void setProfile(Profile profile) {
- setLicense(profile.getLicense());
- setPhotoOwner(profile.getPhotoOwner());
- setAnonymous(profile.getAnonymous());
- setPhotographerLink(profile.getLink());
- setNickname(profile.getNickname());
- setEmail(profile.getEmail());
- setEmailVerified(profile.getEmailVerified());
+ private fun putUri(key: Int, uri: Uri?) {
+ putString(key, uri?.toString())
}
- public Profile getProfile() {
- return new Profile(
- getNickname(),
- getLicense(),
- getPhotoOwner(),
- getAnonymous(),
- getPhotographerLink(),
- getEmail(),
- isEmailVerified());
- }
+ val mapDirectoryUri: Optional
+ get() = getUri(getString(R.string.MAP_DIRECTORY))
- public RSAPIClient getRsapiClient() {
- return rsapiClient;
+ private fun getUri(key: String): Optional {
+ return toUri(preferences.getString(key, null))
}
- public String getMap() {
- return preferences.getString(getString(R.string.MAP_FILE), null);
+ fun setMapDirectoryUri(mapDirectory: Uri?) {
+ putUri(R.string.MAP_DIRECTORY, mapDirectory)
}
- public void setMap(String map) {
- putString(R.string.MAP_FILE, map);
- }
+ val mapThemeDirectoryUri: Optional
+ get() = getUri(getString(R.string.MAP_THEME_DIRECTORY))
- private void putUri(int key, Uri uri) {
- putString(key, uri != null ? uri.toString() : null);
+ fun setMapThemeDirectoryUri(mapThemeDirectory: Uri?) {
+ putUri(R.string.MAP_THEME_DIRECTORY, mapThemeDirectory)
}
- public Optional getMapDirectoryUri() {
- return getUri(getString(R.string.MAP_DIRECTORY));
- }
+ val mapThemeUri: Optional
+ get() = getUri(getString(R.string.MAP_THEME))
- private Optional getUri(String key) {
- return toUri(preferences.getString(key, null));
+ fun setMapThemeUri(mapTheme: Uri?) {
+ putUri(R.string.MAP_THEME, mapTheme)
}
- public static Optional toUri(String uriString) {
- try {
- return Optional.ofNullable(Uri.parse(uriString));
- } catch (Exception ignored) {
- Log.e(TAG, "can't read Uri string " + uriString);
+ var sortByDistance: Boolean
+ get() = preferences.getBoolean(getString(R.string.SORT_BY_DISTANCE), false)
+ set(sortByDistance) {
+ putBoolean(R.string.SORT_BY_DISTANCE, sortByDistance)
+ }
+ val isLoggedIn: Boolean
+ get() = rsapiClient.hasToken()
+
+ companion object {
+ private val TAG = BaseApplication::class.java.simpleName
+ private const val DEFAULT_FIRSTAPPSTART = false
+ private const val DEFAULT = ""
+ lateinit var instance: BaseApplication
+ private set
+ const val DEFAULT_COUNTRY = "de"
+ const val PREF_FILE = "APP_PREF_FILE"
+
+ private fun getValidatedApiUrlString(apiUrl: String?): String {
+ val uri = toUri(apiUrl)
+ if (uri.isPresent) {
+ val scheme = uri.get().scheme
+ if (scheme != null && scheme.matches("https?".toRegex())) {
+ return apiUrl + if (apiUrl!!.endsWith("/")) "" else "/"
+ }
+ }
+ return "https://api.railway-stations.org/"
}
- return Optional.empty();
- }
-
- public void setMapDirectoryUri(Uri mapDirectory) {
- putUri(R.string.MAP_DIRECTORY, mapDirectory);
- }
-
- public Optional getMapThemeDirectoryUri() {
- return getUri(getString(R.string.MAP_THEME_DIRECTORY));
- }
-
- public void setMapThemeDirectoryUri(Uri mapThemeDirectory) {
- putUri(R.string.MAP_THEME_DIRECTORY, mapThemeDirectory);
- }
-
- public Optional getMapThemeUri() {
- return getUri(getString(R.string.MAP_THEME));
- }
-
- public void setMapThemeUri(Uri mapTheme) {
- putUri(R.string.MAP_THEME, mapTheme);
- }
-
- public boolean getSortByDistance() {
- return preferences.getBoolean(getString(R.string.SORT_BY_DISTANCE), false);
- }
-
- public void setSortByDistance(boolean sortByDistance) {
- putBoolean(R.string.SORT_BY_DISTANCE, sortByDistance);
- }
- public boolean isLoggedIn() {
- return rsapiClient.hasToken();
+ fun toUri(uriString: String?): Optional {
+ try {
+ return Optional.ofNullable(Uri.parse(uriString))
+ } catch (ignored: Exception) {
+ Log.e(TAG, "can't read Uri string $uriString")
+ }
+ return Optional.empty()
+ }
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/CountryActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/CountryActivity.kt
index ce223d83..54e24c98 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/CountryActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/CountryActivity.kt
@@ -1,48 +1,52 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.os.Bundle;
-import android.view.MenuItem;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityCountryBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.CountryAdapter;
-
-public class CountryActivity extends AppCompatActivity {
-
- private CountryAdapter countryAdapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- var binding = ActivityCountryBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- var cursor = ((BaseApplication) getApplication()).getDbAdapter().getCountryList();
- countryAdapter = new CountryAdapter(this, cursor, 0);
- binding.lstCountries.setAdapter(countryAdapter);
- binding.lstCountries.setOnItemClickListener((listview, view, position, id) -> countryAdapter.getView(position, view, binding.lstCountries, cursor));
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.R
+import android.os.Bundle
+import android.view.MenuItem
+import android.view.View
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemClickListener
+import androidx.appcompat.app.AppCompatActivity
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityCountryBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.CountryAdapter
+
+class CountryActivity : AppCompatActivity() {
+ private var countryAdapter: CountryAdapter? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val binding = ActivityCountryBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding.root)
+ val cursor = (application as BaseApplication).dbAdapter.countryList
+ countryAdapter = CountryAdapter(this, cursor, 0)
+ binding.lstCountries.adapter = countryAdapter
+ binding.lstCountries.onItemClickListener =
+ OnItemClickListener { listview: AdapterView<*>?, view: View?, position: Int, id: Long ->
+ countryAdapter!!.getView(
+ position,
+ view,
+ binding.lstCountries,
+ cursor
+ )
+ }
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- return true;
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == R.id.home) {
+ onBackPressed()
+ return true
}
- return false;
+ return false
}
- @Override
- public void onBackPressed() {
- var baseApplication = BaseApplication.getInstance();
- var selectedCountries = countryAdapter.getSelectedCountries();
-
- if (!baseApplication.getCountryCodes().equals(selectedCountries)) {
- baseApplication.setCountryCodes(selectedCountries);
- baseApplication.setLastUpdate(0L);
+ override fun onBackPressed() {
+ val baseApplication: BaseApplication = BaseApplication.Companion.getInstance()
+ val selectedCountries = countryAdapter!!.selectedCountries
+ if (baseApplication.countryCodes != selectedCountries) {
+ baseApplication.countryCodes = selectedCountries
+ baseApplication.lastUpdate = 0L
}
- super.onBackPressed();
+ super.onBackPressed()
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/DetailsActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/DetailsActivity.kt
index 04529175..72d5e3e3 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/DetailsActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/DetailsActivity.kt
@@ -1,362 +1,351 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import static android.content.Intent.ACTION_VIEW;
-import static android.content.Intent.createChooser;
-
-import android.app.TaskStackBuilder;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.Html;
-import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.activity.OnBackPressedCallback;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.app.NavUtils;
-import androidx.core.content.ContextCompat;
-import androidx.core.content.FileProvider;
-import androidx.viewpager2.widget.ViewPager2;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityDetailsBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.StationInfoBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PageablePhoto;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Photo;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStations;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProviderApp;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.BitmapCache;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.ConnectionUtil;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.NavItem;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Timetable;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class DetailsActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
-
- private static final String TAG = DetailsActivity.class.getSimpleName();
-
- // Names of Extras that this class reacts to
- public static final String EXTRA_STATION = "EXTRA_STATION";
-
- private static final String LINK_FORMAT = "%s";
-
- private BaseApplication baseApplication;
- private RSAPIClient rsapiClient;
- private ActivityDetailsBinding binding;
- private Station station;
- private Set countries;
- private String nickname;
- private PhotoPagerAdapter photoPagerAdapter;
- private final Map photoBitmaps = new HashMap<>();
- private PageablePhoto selectedPhoto;
- private final List carouselPageIndicators = new ArrayList<>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ActivityDetailsBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- baseApplication = (BaseApplication) getApplication();
- rsapiClient = baseApplication.getRsapiClient();
- countries = baseApplication.getDbAdapter().fetchCountriesWithProviderApps(baseApplication.getCountryCodes());
-
- Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
-
- photoPagerAdapter = new PhotoPagerAdapter(this);
- binding.details.viewPager.setAdapter(photoPagerAdapter);
- binding.details.viewPager.setCurrentItem(0, false);
- binding.details.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
- @Override
- public void onPageSelected(int position) {
- var pageablePhoto = photoPagerAdapter.getPageablePhotoAtPosition(position);
- onPageablePhotoSelected(pageablePhoto, position);
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.app.TaskStackBuilder
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.net.Uri
+import android.os.Bundle
+import android.text.Html
+import android.text.TextUtils
+import android.text.method.LinkMovementMethod
+import android.util.Log
+import android.view.ContextThemeWrapper
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.OnBackPressedDispatcher.addCallback
+import androidx.activity.result.ActivityResult
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback
+import androidx.core.app.NavUtils
+import androidx.core.content.ContextCompat
+import androidx.core.content.FileProvider
+import androidx.viewpager2.widget.ViewPager2
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityDetailsBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.StationInfoBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country.Companion.getCountryByCode
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PageablePhoto
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Photo
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStation
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStations
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProviderApp
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.BitmapAvailableHandler
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.BitmapCache
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.ConnectionUtil
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.NavItem
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Timetable
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.io.FileNotFoundException
+import java.io.FileOutputStream
+import java.util.Locale
+import java.util.Objects
+import java.util.function.Consumer
+
+class DetailsActivity : AppCompatActivity(), OnRequestPermissionsResultCallback {
+ private var baseApplication: BaseApplication? = null
+ private var rsapiClient: RSAPIClient? = null
+ private var binding: ActivityDetailsBinding? = null
+ private var station: Station? = null
+ private var countries: Set? = null
+ private var nickname: String? = null
+ private var photoPagerAdapter: PhotoPagerAdapter? = null
+ private val photoBitmaps: MutableMap = HashMap()
+ private var selectedPhoto: PageablePhoto? = null
+ private val carouselPageIndicators: MutableList? = ArrayList()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityDetailsBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ baseApplication = application as BaseApplication
+ rsapiClient = baseApplication.getRsapiClient()
+ countries = baseApplication.getDbAdapter()
+ .fetchCountriesWithProviderApps(baseApplication.getCountryCodes())
+ Objects.requireNonNull(supportActionBar).setDisplayHomeAsUpEnabled(true)
+ photoPagerAdapter = PhotoPagerAdapter(this)
+ binding!!.details.viewPager.adapter = photoPagerAdapter
+ binding!!.details.viewPager.setCurrentItem(0, false)
+ binding!!.details.viewPager.registerOnPageChangeCallback(object :
+ ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ val pageablePhoto = photoPagerAdapter!!.getPageablePhotoAtPosition(position)
+ onPageablePhotoSelected(pageablePhoto, position)
}
- });
+ })
// switch off image and license view until we actually have a foto
- binding.details.licenseTag.setVisibility(View.INVISIBLE);
- binding.details.licenseTag.setMovementMethod(LinkMovementMethod.getInstance());
-
- getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
- @Override
- public void handleOnBackPressed() {
- navigateUp();
+ binding!!.details.licenseTag.visibility = View.INVISIBLE
+ binding!!.details.licenseTag.movementMethod = LinkMovementMethod.getInstance()
+ getOnBackPressedDispatcher().addCallback(this, object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ navigateUp()
}
- });
-
- readPreferences();
- onNewIntent(getIntent());
+ })
+ readPreferences()
+ onNewIntent(intent)
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
if (intent != null) {
- station = (Station) intent.getSerializableExtra(EXTRA_STATION);
-
+ station = intent.getSerializableExtra(EXTRA_STATION) as Station?
if (station == null) {
- Log.w(TAG, "EXTRA_STATION in intent data missing");
- Toast.makeText(this, R.string.station_not_found, Toast.LENGTH_LONG).show();
- finish();
- return;
+ Log.w(TAG, "EXTRA_STATION in intent data missing")
+ Toast.makeText(this, R.string.station_not_found, Toast.LENGTH_LONG).show()
+ finish()
+ return
}
-
- binding.details.marker.setImageDrawable(ContextCompat.getDrawable(this, getMarkerRes()));
-
- binding.details.tvStationTitle.setText(station.getTitle());
- binding.details.tvStationTitle.setSingleLine(false);
-
- if (station.hasPhoto()) {
+ binding!!.details.marker.setImageDrawable(ContextCompat.getDrawable(this, markerRes))
+ binding!!.details.tvStationTitle.text = station!!.title
+ binding!!.details.tvStationTitle.isSingleLine = false
+ if (station!!.hasPhoto()) {
if (ConnectionUtil.checkInternetConnection(this)) {
- photoBitmaps.put(station.getPhotoUrl(), null);
- BitmapCache.getInstance().getPhoto((bitmap) -> {
- if (bitmap != null) {
- var pageablePhoto = new PageablePhoto(station, bitmap);
- runOnUiThread(() -> {
- addIndicator();
- var position = photoPagerAdapter.addPageablePhoto(pageablePhoto);
- if (position == 0) {
- onPageablePhotoSelected(pageablePhoto, position);
+ photoBitmaps[station!!.photoUrl] = null
+ BitmapCache.Companion.getInstance()
+ .getPhoto(BitmapAvailableHandler { bitmap: Bitmap? ->
+ if (bitmap != null) {
+ val pageablePhoto = PageablePhoto(station!!, bitmap)
+ runOnUiThread {
+ addIndicator()
+ val position =
+ photoPagerAdapter!!.addPageablePhoto(pageablePhoto)
+ if (position == 0) {
+ onPageablePhotoSelected(pageablePhoto, position)
+ }
}
- });
- }
- }, station.getPhotoUrl());
+ }
+ }, station!!.photoUrl)
}
}
-
- loadAdditionalPhotos(station);
-
+ loadAdditionalPhotos(station!!)
baseApplication.getDbAdapter()
- .getPendingUploadsForStation(station)
- .forEach(this::addUploadPhoto);
+ .getPendingUploadsForStation(station)
+ .forEach(Consumer { upload: Upload? -> addUploadPhoto(upload) })
}
-
}
- private void addUploadPhoto(final Upload upload) {
- if (!upload.isPendingPhotoUpload()) {
- return;
+ private fun addUploadPhoto(upload: Upload?) {
+ if (!upload!!.isPendingPhotoUpload) {
+ return
}
- var profile = baseApplication.getProfile();
- var file = FileUtils.getStoredMediaFile(this, upload.getId());
+ val profile = baseApplication.getProfile()
+ val file = FileUtils.getStoredMediaFile(this, upload.id)
if (file != null && file.canRead()) {
- var bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
+ val bitmap = BitmapFactory.decodeFile(file.absolutePath)
if (bitmap != null) {
- var pageablePhoto = new PageablePhoto(
- upload.getId(),
- file.toURI().toString(),
- getString(R.string.new_local_photo),
- "",
- profile.getLicense() != null ? profile.getLicense().getLongName() : "",
- "",
- bitmap);
- runOnUiThread(() -> {
- addIndicator();
- var position = photoPagerAdapter.addPageablePhoto(pageablePhoto);
+ val pageablePhoto = PageablePhoto(
+ upload.id!!,
+ file.toURI().toString(),
+ getString(R.string.new_local_photo),
+ "",
+ if (profile!!.license != null) profile!!.license!!.longName else "",
+ "",
+ bitmap
+ )
+ runOnUiThread {
+ addIndicator()
+ val position = photoPagerAdapter!!.addPageablePhoto(pageablePhoto)
if (position == 0) {
- onPageablePhotoSelected(pageablePhoto, position);
+ onPageablePhotoSelected(pageablePhoto, position)
}
- });
+ }
}
}
}
- private void loadAdditionalPhotos(final Station station) {
- rsapiClient.getPhotoStationById(station.getCountry(), station.getId()).enqueue(new Callback<>() {
-
- @Override
- public void onResponse(@NonNull final Call call, @NonNull final Response response) {
- if (response.isSuccessful()) {
- var photoStations = response.body();
- if (photoStations == null) {
- return;
- }
- photoStations.getStations().stream()
- .flatMap(photoStation -> photoStation.getPhotos().stream())
- .forEach(photo -> {
- var url = photoStations.getPhotoBaseUrl() + photo.getPath();
+ private fun loadAdditionalPhotos(station: Station) {
+ rsapiClient!!.getPhotoStationById(station.country, station.id)!!
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.isSuccessful) {
+ val photoStations = response.body() ?: return
+ photoStations.stations.stream()
+ .flatMap { (_, _, _, _, _, _, _, photos): PhotoStation -> photos!!.stream() }
+ .forEach { photo: Photo ->
+ val url = photoStations.photoBaseUrl + photo.path
if (!photoBitmaps.containsKey(url)) {
- photoBitmaps.put(url, null);
- addIndicator();
- BitmapCache.getInstance().getPhoto((bitmap) -> runOnUiThread(() -> addAdditionalPhotoToPagerAdapter(
- photo,
- url,
- photoStations,
- bitmap)), url);
+ photoBitmaps[url] = null
+ addIndicator()
+ BitmapCache.Companion.getInstance()
+ .getPhoto(BitmapAvailableHandler { bitmap: Bitmap ->
+ runOnUiThread {
+ addAdditionalPhotoToPagerAdapter(
+ photo,
+ url,
+ photoStations,
+ bitmap
+ )
+ }
+ }, url)
}
- });
+ }
+ }
}
- }
- @Override
- public void onFailure(@NonNull final Call call, @NonNull final Throwable t) {
- Log.e(TAG, "Failed to load additional photos", t);
- }
- });
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Failed to load additional photos", t)
+ }
+ })
}
- private void addAdditionalPhotoToPagerAdapter(Photo photo, String url, PhotoStations photoStations, Bitmap bitmap) {
- photoPagerAdapter.addPageablePhoto(
- new PageablePhoto(
- photo.getId(),
- url,
- photo.getPhotographer(),
- photoStations.getPhotographerUrl(photo.getPhotographer()),
- photoStations.getLicenseName(photo.getLicense()),
- photoStations.getLicenseUrl(photo.getLicense()),
- bitmap)
- );
+ private fun addAdditionalPhotoToPagerAdapter(
+ photo: Photo,
+ url: String,
+ photoStations: PhotoStations,
+ bitmap: Bitmap
+ ) {
+ photoPagerAdapter!!.addPageablePhoto(
+ PageablePhoto(
+ photo.id,
+ url,
+ photo.photographer,
+ photoStations.getPhotographerUrl(photo.photographer),
+ photoStations.getLicenseName(photo.license),
+ photoStations.getLicenseUrl(photo.license),
+ bitmap
+ )
+ )
}
- private void addIndicator() {
- var indicator = new ImageView(DetailsActivity.this);
- indicator.setImageResource(R.drawable.selector_carousel_page_indicator);
- indicator.setPadding(0, 0, 5, 0); // left, top, right, bottom
- binding.details.llPageIndicatorContainer.addView(indicator);
- carouselPageIndicators.add(indicator);
+ private fun addIndicator() {
+ val indicator = ImageView(this@DetailsActivity)
+ indicator.setImageResource(R.drawable.selector_carousel_page_indicator)
+ indicator.setPadding(0, 0, 5, 0) // left, top, right, bottom
+ binding!!.details.llPageIndicatorContainer.addView(indicator)
+ carouselPageIndicators!!.add(indicator)
}
- private int getMarkerRes() {
- if (station == null) {
- return R.drawable.marker_missing;
- }
- if (station.hasPhoto()) {
- if (isOwner()) {
- return station.getActive() ? R.drawable.marker_violet : R.drawable.marker_violet_inactive;
+ private val markerRes: Int
+ private get() {
+ if (station == null) {
+ return R.drawable.marker_missing
+ }
+ return if (station!!.hasPhoto()) {
+ if (isOwner) {
+ if (station!!.active) R.drawable.marker_violet else R.drawable.marker_violet_inactive
+ } else {
+ if (station!!.active) R.drawable.marker_green else R.drawable.marker_green_inactive
+ }
} else {
- return station.getActive() ? R.drawable.marker_green : R.drawable.marker_green_inactive;
+ if (station!!.active) R.drawable.marker_red else R.drawable.marker_red_inactive
}
- } else {
- return station.getActive() ? R.drawable.marker_red : R.drawable.marker_red_inactive;
}
- }
- @Override
- protected void onResume() {
- super.onResume();
- readPreferences();
+ override fun onResume() {
+ super.onResume()
+ readPreferences()
}
- private void readPreferences() {
- nickname = baseApplication.getNickname();
+ private fun readPreferences() {
+ nickname = baseApplication.getNickname()
}
- private boolean isOwner() {
- return station != null && TextUtils.equals(nickname, station.getPhotographer());
- }
+ private val isOwner: Boolean
+ private get() = station != null && TextUtils.equals(nickname, station!!.photographer)
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.details, menu);
- return super.onCreateOptionsMenu(menu);
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.details, menu)
+ return super.onCreateOptionsMenu(menu)
}
- ActivityResultLauncher activityForResultLauncher = registerForActivityResult(
- new ActivityResultContracts.StartActivityForResult(),
- result -> recreate());
+ var activityForResultLauncher = registerForActivityResult(
+ StartActivityForResult()
+ ) { result: ActivityResult? -> recreate() }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val itemId = item.itemId
if (itemId == R.id.add_photo) {
- var intent = new Intent(DetailsActivity.this, UploadActivity.class);
- intent.putExtra(UploadActivity.EXTRA_STATION, station);
- activityForResultLauncher.launch(intent);
+ val intent = Intent(this@DetailsActivity, UploadActivity::class.java)
+ intent.putExtra(UploadActivity.Companion.EXTRA_STATION, station)
+ activityForResultLauncher.launch(intent)
} else if (itemId == R.id.report_problem) {
- var intent = new Intent(DetailsActivity.this, ProblemReportActivity.class);
- intent.putExtra(ProblemReportActivity.EXTRA_STATION, station);
- intent.putExtra(ProblemReportActivity.EXTRA_PHOTO_ID, selectedPhoto != null ? selectedPhoto.getId() : null);
- startActivity(intent);
+ val intent = Intent(this@DetailsActivity, ProblemReportActivity::class.java)
+ intent.putExtra(ProblemReportActivity.Companion.EXTRA_STATION, station)
+ intent.putExtra(
+ ProblemReportActivity.Companion.EXTRA_PHOTO_ID,
+ if (selectedPhoto != null) selectedPhoto!!.id else null
+ )
+ startActivity(intent)
} else if (itemId == R.id.nav_to_station) {
- startNavigation(DetailsActivity.this);
+ startNavigation(this@DetailsActivity)
} else if (itemId == R.id.timetable) {
- Country.getCountryByCode(countries, station.getCountry()).map(country -> {
- var timetableIntent = new Timetable().createTimetableIntent(country, station);
- if (timetableIntent != null) {
- startActivity(timetableIntent);
- }
- return null;
- });
+ getCountryByCode(countries, station!!.country).map { country: Country ->
+ val timetableIntent = Timetable().createTimetableIntent(country, station)
+ timetableIntent?.let { startActivity(it) }
+ null
+ }
} else if (itemId == R.id.share_link) {
- var stationUri = Uri.parse(String.format("https://map.railway-stations.org/station.php?countryCode=%s&stationId=%s", station.getCountry(), station.getId()));
- startActivity(new Intent(ACTION_VIEW, stationUri));
+ val stationUri = Uri.parse(
+ String.format(
+ "https://map.railway-stations.org/station.php?countryCode=%s&stationId=%s",
+ station!!.country,
+ station!!.id
+ )
+ )
+ startActivity(Intent(Intent.ACTION_VIEW, stationUri))
} else if (itemId == R.id.share_photo) {
- Country.getCountryByCode(countries, station.getCountry()).map(country -> {
- var shareIntent = createPhotoSendIntent();
- if (shareIntent == null) {
- return null;
- }
- shareIntent.putExtra(Intent.EXTRA_TEXT, binding.details.tvStationTitle.getText());
- shareIntent.setType("image/jpeg");
- startActivity(createChooser(shareIntent, "send"));
- return null;
- });
+ getCountryByCode(countries, station!!.country).map { country: Country? ->
+ val shareIntent = createPhotoSendIntent() ?: return@map null
+ shareIntent.putExtra(Intent.EXTRA_TEXT, binding!!.details.tvStationTitle.text)
+ shareIntent.type = "image/jpeg"
+ startActivity(Intent.createChooser(shareIntent, "send"))
+ null
+ }
} else if (itemId == R.id.station_info) {
- showStationInfo(null);
+ showStationInfo(null)
} else if (itemId == R.id.provider_android_app) {
- Country.getCountryByCode(countries, station.getCountry()).map(country -> {
- var providerApps = country.getCompatibleProviderApps();
- if (providerApps.size() == 1) {
- openAppOrPlayStore(providerApps.get(0), this);
- } else if (providerApps.size() > 1) {
- var appNames = providerApps.stream()
- .map(ProviderApp::getName).toArray(CharSequence[]::new);
- SimpleDialogs.simpleSelect(this, getResources().getString(R.string.choose_provider_app), appNames, (dialog, which) -> {
- if (which >= 0 && providerApps.size() > which) {
- openAppOrPlayStore(providerApps.get(which), DetailsActivity.this);
+ getCountryByCode(countries, station!!.country).map { country: Country ->
+ val providerApps = country.compatibleProviderApps
+ if (providerApps.size == 1) {
+ openAppOrPlayStore(providerApps[0], this)
+ } else if (providerApps.size > 1) {
+ val appNames = providerApps.stream()
+ .map(ProviderApp::name)
+ .toArray { _Dummy_.__Array__() }
+ SimpleDialogs.simpleSelect(
+ this,
+ resources.getString(R.string.choose_provider_app),
+ appNames
+ ) { dialog: DialogInterface?, which: Int ->
+ if (which >= 0 && providerApps.size > which) {
+ openAppOrPlayStore(providerApps[which], this@DetailsActivity)
}
- });
+ }
} else {
- Toast.makeText(this, R.string.provider_app_missing, Toast.LENGTH_LONG).show();
+ Toast.makeText(this, R.string.provider_app_missing, Toast.LENGTH_LONG).show()
}
- return null;
- });
+ null
+ }
} else if (itemId == android.R.id.home) {
- navigateUp();
+ navigateUp()
} else {
- return super.onOptionsItemSelected(item);
+ return super.onOptionsItemSelected(item)
}
-
- return true;
+ return true
}
/**
@@ -364,14 +353,14 @@ public class DetailsActivity extends AppCompatActivity implements ActivityCompat
*
* @param context activity context
*/
- public void openAppOrPlayStore(ProviderApp providerApp, Context context) {
+ fun openAppOrPlayStore(providerApp: ProviderApp, context: Context) {
// Try to open App
- boolean success = openApp(providerApp, context);
+ val success = openApp(providerApp, context)
// Could not open App, open play store instead
if (!success) {
- var intent = new Intent(ACTION_VIEW);
- intent.setData(Uri.parse(providerApp.getUrl()));
- context.startActivity(intent);
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.data = Uri.parse(providerApp.url)
+ context.startActivity(intent)
}
}
@@ -382,170 +371,190 @@ public class DetailsActivity extends AppCompatActivity implements ActivityCompat
* @return true if likely successful, false if unsuccessful
* @see https://stackoverflow.com/a/7596063/714965
*/
- @SuppressWarnings("JavadocReference")
- private boolean openApp(ProviderApp providerApp, Context context) {
- if (!providerApp.isAndroid()) {
- return false;
+ private fun openApp(providerApp: ProviderApp, context: Context): Boolean {
+ if (!providerApp.isAndroid) {
+ return false
}
- var manager = context.getPackageManager();
- try {
- String packageName = Uri.parse(providerApp.getUrl()).getQueryParameter("id");
- assert packageName != null;
- var intent = manager.getLaunchIntentForPackage(packageName);
- if (intent == null) {
- return false;
- }
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- context.startActivity(intent);
- return true;
- } catch (ActivityNotFoundException e) {
- return false;
+ val manager = context.packageManager
+ return try {
+ val packageName = Uri.parse(providerApp.url).getQueryParameter("id")!!
+ val intent = manager.getLaunchIntentForPackage(packageName) ?: return false
+ intent.addCategory(Intent.CATEGORY_LAUNCHER)
+ context.startActivity(intent)
+ true
+ } catch (e: ActivityNotFoundException) {
+ false
}
}
- public void navigateUp() {
- var callingActivity = getCallingActivity(); // if MapsActivity was calling, then we don't want to rebuild the Backstack
- var upIntent = NavUtils.getParentActivityIntent(this);
+ fun navigateUp() {
+ val callingActivity =
+ callingActivity // if MapsActivity was calling, then we don't want to rebuild the Backstack
+ val upIntent = NavUtils.getParentActivityIntent(this)
if (callingActivity == null && upIntent != null) {
- upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
- Log.v(TAG, "Recreate back stack");
- TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
+ upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot) {
+ Log.v(TAG, "Recreate back stack")
+ TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
+ .startActivities()
}
}
-
- finish();
+ finish()
}
- public void showStationInfo(View view) {
- var stationInfoBinding = StationInfoBinding.inflate(getLayoutInflater());
- stationInfoBinding.id.setText(station.getId());
- stationInfoBinding.coordinates.setText(String.format(Locale.US, getResources().getString(R.string.coordinates), station.getLat(), station.getLon()));
- stationInfoBinding.active.setText(station != null && station.getActive() ? R.string.active : R.string.inactive);
- stationInfoBinding.owner.setText(station != null && station.getPhotographer() != null ? station.getPhotographer() : "");
- if (station.getOutdated()) {
- stationInfoBinding.outdatedLabel.setVisibility(View.VISIBLE);
+ fun showStationInfo(view: View?) {
+ val stationInfoBinding = StationInfoBinding.inflate(
+ layoutInflater
+ )
+ stationInfoBinding.id.text = station!!.id
+ stationInfoBinding.coordinates.text = String.format(
+ Locale.US,
+ resources.getString(R.string.coordinates),
+ station!!.lat,
+ station!!.lon
+ )
+ stationInfoBinding.active.setText(if (station != null && station!!.active) R.string.active else R.string.inactive)
+ stationInfoBinding.owner.text =
+ if (station != null && station!!.photographer != null) station!!.photographer else ""
+ if (station!!.outdated) {
+ stationInfoBinding.outdatedLabel.visibility = View.VISIBLE
}
-
- new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom))
- .setTitle(binding.details.tvStationTitle.getText())
- .setView(stationInfoBinding.getRoot())
- .setIcon(R.mipmap.ic_launcher)
- .setPositiveButton(android.R.string.ok, null)
- .create()
- .show();
+ AlertDialog.Builder(ContextThemeWrapper(this, R.style.AlertDialogCustom))
+ .setTitle(binding!!.details.tvStationTitle.text)
+ .setView(stationInfoBinding.root)
+ .setIcon(R.mipmap.ic_launcher)
+ .setPositiveButton(android.R.string.ok, null)
+ .create()
+ .show()
}
- private Intent createPhotoSendIntent() {
+ private fun createPhotoSendIntent(): Intent? {
if (selectedPhoto != null) {
- var sendIntent = new Intent(Intent.ACTION_SEND);
- var newFile = FileUtils.getImageCacheFile(getApplicationContext(), String.valueOf(System.currentTimeMillis()));
+ val sendIntent = Intent(Intent.ACTION_SEND)
+ val newFile = FileUtils.getImageCacheFile(
+ applicationContext, System.currentTimeMillis().toString()
+ )
try {
- Log.i(TAG, "Save photo to: " + newFile);
- selectedPhoto.getBitmap().compress(Bitmap.CompressFormat.JPEG, Constants.STORED_PHOTO_QUALITY, new FileOutputStream(newFile));
- sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(DetailsActivity.this,
- BuildConfig.APPLICATION_ID + ".fileprovider", newFile));
- return sendIntent;
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Error saving cached bitmap", e);
+ Log.i(TAG, "Save photo to: $newFile")
+ selectedPhoto!!.bitmap!!.compress(
+ Bitmap.CompressFormat.JPEG,
+ Constants.STORED_PHOTO_QUALITY,
+ FileOutputStream(newFile)
+ )
+ sendIntent.putExtra(
+ Intent.EXTRA_STREAM, FileProvider.getUriForFile(
+ this@DetailsActivity,
+ BuildConfig.APPLICATION_ID + ".fileprovider", newFile!!
+ )
+ )
+ return sendIntent
+ } catch (e: FileNotFoundException) {
+ Log.e(TAG, "Error saving cached bitmap", e)
}
}
- return null;
+ return null
}
- private void startNavigation(Context context) {
- var adapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_item,
- android.R.id.text1, NavItem.values()) {
- @NonNull
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- var item = getItem(position);
- assert item != null;
-
- var view = super.getView(position, convertView, parent);
- TextView tv = view.findViewById(android.R.id.text1);
+ private fun startNavigation(context: Context) {
+ val adapter: ArrayAdapter = object : ArrayAdapter(
+ this, android.R.layout.select_dialog_item,
+ android.R.id.text1, NavItem.values()
+ ) {
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val item = getItem(position)!!
+ val view = super.getView(position, convertView, parent)
+ val tv = view.findViewById(android.R.id.text1)
//Put the image on the TextView
- tv.setCompoundDrawablesWithIntrinsicBounds(item.getIconRes(), 0, 0, 0);
- tv.setText(getString(item.getTextRes()));
+ tv.setCompoundDrawablesWithIntrinsicBounds(item.iconRes, 0, 0, 0)
+ tv.text = getString(item.textRes)
//Add margin between image and text (support various screen densities)
- int dp5 = (int) (20 * getResources().getDisplayMetrics().density + 0.5f);
- int dp7 = (int) (20 * getResources().getDisplayMetrics().density);
- tv.setCompoundDrawablePadding(dp5);
- tv.setPadding(dp7, 0, 0, 0);
-
- return view;
+ val dp5 = (20 * resources.displayMetrics.density + 0.5f).toInt()
+ val dp7 = (20 * resources.displayMetrics.density).toInt()
+ tv.compoundDrawablePadding = dp5
+ tv.setPadding(dp7, 0, 0, 0)
+ return view
}
- };
-
- new AlertDialog.Builder(this)
- .setIcon(R.mipmap.ic_launcher)
- .setTitle(R.string.navMethod)
- .setAdapter(adapter, (dialog, position) -> {
- var item = adapter.getItem(position);
- assert item != null;
- var lat = station.getLat();
- var lon = station.getLon();
- var intent = item.createIntent(DetailsActivity.this, lat, lon, binding.details.tvStationTitle.getText().toString(), getMarkerRes());
- try {
- startActivity(intent);
- } catch (Exception e) {
- Toast.makeText(context, R.string.activitynotfound, Toast.LENGTH_LONG).show();
- }
- }).show();
+ }
+ AlertDialog.Builder(this)
+ .setIcon(R.mipmap.ic_launcher)
+ .setTitle(R.string.navMethod)
+ .setAdapter(adapter) { dialog: DialogInterface?, position: Int ->
+ val item = adapter.getItem(position)!!
+ val lat = station!!.lat
+ val lon = station!!.lon
+ val intent = item.createIntent(
+ this@DetailsActivity,
+ lat,
+ lon,
+ binding!!.details.tvStationTitle.text.toString(),
+ markerRes
+ )
+ try {
+ startActivity(intent)
+ } catch (e: Exception) {
+ Toast.makeText(context, R.string.activitynotfound, Toast.LENGTH_LONG).show()
+ }
+ }.show()
}
- public void onPageablePhotoSelected(PageablePhoto pageablePhoto, int position) {
- selectedPhoto = pageablePhoto;
- binding.details.licenseTag.setVisibility(View.INVISIBLE);
-
+ fun onPageablePhotoSelected(pageablePhoto: PageablePhoto?, position: Int) {
+ selectedPhoto = pageablePhoto
+ binding!!.details.licenseTag.visibility = View.INVISIBLE
if (pageablePhoto == null) {
- return;
+ return
}
// Lizenzinfo aufbauen und einblenden
- binding.details.licenseTag.setVisibility(View.VISIBLE);
- boolean photographerUrlAvailable = pageablePhoto.getPhotographerUrl() != null && !pageablePhoto.getPhotographerUrl().isEmpty();
- boolean licenseUrlAvailable = pageablePhoto.getLicenseUrl() != null && !pageablePhoto.getLicenseUrl().isEmpty();
-
- String photographerText;
- if (photographerUrlAvailable) {
- photographerText = String.format(
- LINK_FORMAT,
- pageablePhoto.getPhotographerUrl(),
- pageablePhoto.getPhotographer());
+ binding!!.details.licenseTag.visibility = View.VISIBLE
+ val photographerUrlAvailable =
+ pageablePhoto.photographerUrl != null && !pageablePhoto.photographerUrl!!.isEmpty()
+ val licenseUrlAvailable =
+ pageablePhoto.licenseUrl != null && !pageablePhoto.licenseUrl!!.isEmpty()
+ val photographerText: String?
+ photographerText = if (photographerUrlAvailable) {
+ String.format(
+ LINK_FORMAT,
+ pageablePhoto.photographerUrl,
+ pageablePhoto.photographer
+ )
} else {
- photographerText = pageablePhoto.getPhotographer();
+ pageablePhoto.photographer
}
-
- String licenseText;
- if (licenseUrlAvailable) {
- licenseText = String.format(
- LINK_FORMAT,
- pageablePhoto.getLicenseUrl(),
- pageablePhoto.getLicense());
+ val licenseText: String?
+ licenseText = if (licenseUrlAvailable) {
+ String.format(
+ LINK_FORMAT,
+ pageablePhoto.licenseUrl,
+ pageablePhoto.license
+ )
} else {
- licenseText = pageablePhoto.getLicense();
+ pageablePhoto.license
}
-
- binding.details.licenseTag.setText(
- Html.fromHtml(
- String.format(
- getText(R.string.license_tag).toString(),
- photographerText,
- licenseText), Html.FROM_HTML_MODE_LEGACY
- )
- );
-
+ binding!!.details.licenseTag.text = Html.fromHtml(
+ String.format(
+ getText(R.string.license_tag).toString(),
+ photographerText,
+ licenseText
+ ), Html.FROM_HTML_MODE_LEGACY
+ )
if (carouselPageIndicators != null) {
- for (int i = 0; i < carouselPageIndicators.size(); i++) {
+ for (i in carouselPageIndicators.indices) {
if (i == position) {
- carouselPageIndicators.get(position).setSelected(true);
+ carouselPageIndicators[position].isSelected = true
} else {
- carouselPageIndicators.get(i).setSelected(false);
+ carouselPageIndicators[i].isSelected = false
}
}
}
}
-}
+ companion object {
+ private val TAG = DetailsActivity::class.java.simpleName
+
+ // Names of Extras that this class reacts to
+ const val EXTRA_STATION = "EXTRA_STATION"
+ private const val LINK_FORMAT = "%s"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/HighScoreActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/HighScoreActivity.kt
index b743154d..05a292bd 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/HighScoreActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/HighScoreActivity.kt
@@ -1,134 +1,145 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.app.SearchManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.SearchView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityHighScoreBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.HighScoreAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.HighScore;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.HighScoreItem;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class HighScoreActivity extends AppCompatActivity {
-
- private static final String TAG = "HighScoreActivity";
- private HighScoreAdapter adapter;
- private ActivityHighScoreBinding binding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ActivityHighScoreBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- var baseApplication = (BaseApplication) getApplication();
- var firstSelectedCountry = baseApplication.getCountryCodes().iterator().next();
- var countries = new ArrayList<>(baseApplication.getDbAdapter().getAllCountries());
- Collections.sort(countries);
- countries.add(0, new Country("", getString(R.string.all_countries)));
- int selectedItem = 0;
- for (var country : countries) {
- if (country.getCode().equals(firstSelectedCountry)) {
- selectedItem = countries.indexOf(country);
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.app.SearchManager
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.Menu
+import android.view.View
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemClickListener
+import android.widget.ArrayAdapter
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.SearchView
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityHighScoreBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.HighScoreAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.HighScore
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.HighScoreItem
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.util.Collections
+
+class HighScoreActivity : AppCompatActivity() {
+ private var adapter: HighScoreAdapter? = null
+ private var binding: ActivityHighScoreBinding? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityHighScoreBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ val baseApplication = application as BaseApplication
+ val firstSelectedCountry = baseApplication.countryCodes.iterator().next()
+ val countries = ArrayList(baseApplication.dbAdapter.allCountries)
+ Collections.sort(countries)
+ countries.add(0, Country("", getString(R.string.all_countries)))
+ var selectedItem = 0
+ for (country in countries) {
+ if (country!!.code == firstSelectedCountry) {
+ selectedItem = countries.indexOf(country)
}
}
-
- var countryAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, countries.toArray(new Country[0]));
- binding.countries.setAdapter(countryAdapter);
- binding.countries.setSelection(selectedItem);
- binding.countries.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- loadHighScore(baseApplication, (Country) parent.getSelectedItem());
+ val countryAdapter = ArrayAdapter(
+ this,
+ android.R.layout.simple_spinner_dropdown_item,
+ countries.toTypedArray()
+ )
+ binding!!.countries.adapter = countryAdapter
+ binding!!.countries.setSelection(selectedItem)
+ binding!!.countries.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>,
+ view: View,
+ position: Int,
+ id: Long
+ ) {
+ loadHighScore(baseApplication, parent.selectedItem as Country)
}
- @Override
- public void onNothingSelected(AdapterView> parent) {
- }
- });
+ override fun onNothingSelected(parent: AdapterView<*>?) {}
+ }
}
- private void loadHighScore(BaseApplication baseApplication, Country selectedCountry) {
- var rsapi = baseApplication.getRsapiClient();
- var highScoreCall = selectedCountry.getCode().isEmpty() ? rsapi.getHighScore() : rsapi.getHighScore(selectedCountry.getCode());
- highScoreCall.enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- if (response.isSuccessful()) {
- adapter = new HighScoreAdapter(HighScoreActivity.this, response.body().getItems());
- binding.highscoreList.setAdapter(adapter);
- binding.highscoreList.setOnItemClickListener((adapter, v, position, arg3) -> {
- var highScoreItem = (HighScoreItem) adapter.getItemAtPosition(position);
- var stationFilter = baseApplication.getStationFilter();
- stationFilter.setNickname(highScoreItem.getName());
- baseApplication.setStationFilter(stationFilter);
- var intent = new Intent(HighScoreActivity.this, MapsActivity.class);
- startActivity(intent);
- });
+ private fun loadHighScore(baseApplication: BaseApplication, selectedCountry: Country) {
+ val rsapi = baseApplication.rsapiClient
+ val highScoreCall =
+ if (selectedCountry.code.isEmpty()) rsapi!!.highScore else rsapi!!.getHighScore(
+ selectedCountry.code
+ )
+ highScoreCall!!.enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ if (response.isSuccessful) {
+ adapter = HighScoreAdapter(this@HighScoreActivity, response.body()!!.getItems())
+ binding!!.highscoreList.adapter = adapter
+ binding!!.highscoreList.onItemClickListener =
+ OnItemClickListener { adapter: AdapterView<*>, v: View?, position: Int, arg3: Long ->
+ val (name) = adapter.getItemAtPosition(position) as HighScoreItem
+ val stationFilter = baseApplication.stationFilter
+ stationFilter.nickname = name
+ baseApplication.stationFilter = stationFilter
+ val intent = Intent(this@HighScoreActivity, MapsActivity::class.java)
+ startActivity(intent)
+ }
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error loading highscore", t);
- Toast.makeText(getBaseContext(), getString(R.string.error_loading_highscore) + t.getMessage(), Toast.LENGTH_LONG).show();
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error loading highscore", t)
+ Toast.makeText(
+ baseContext,
+ getString(R.string.error_loading_highscore) + t.message,
+ Toast.LENGTH_LONG
+ ).show()
}
- });
+ })
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_high_score, menu);
-
- var manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- var search = (SearchView) menu.findItem(R.id.search).getActionView();
- search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
- search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
-
- @Override
- public boolean onQueryTextSubmit(String s) {
- Log.d(TAG, "onQueryTextSubmit ");
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_high_score, menu)
+ val manager = getSystemService(SEARCH_SERVICE) as SearchManager
+ val search = menu.findItem(R.id.search).actionView as SearchView?
+ search!!.setSearchableInfo(manager.getSearchableInfo(componentName))
+ search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(s: String): Boolean {
+ Log.d(TAG, "onQueryTextSubmit ")
if (adapter != null) {
- adapter.getFilter().filter(s);
- if (adapter.isEmpty()) {
- Toast.makeText(HighScoreActivity.this, R.string.no_records_found, Toast.LENGTH_LONG).show();
+ adapter!!.filter.filter(s)
+ if (adapter!!.isEmpty) {
+ Toast.makeText(
+ this@HighScoreActivity,
+ R.string.no_records_found,
+ Toast.LENGTH_LONG
+ ).show()
} else {
- Toast.makeText(HighScoreActivity.this, getResources().getQuantityString(R.plurals.records_found, adapter.getCount(), adapter.getCount()), Toast.LENGTH_LONG).show();
+ Toast.makeText(
+ this@HighScoreActivity,
+ resources.getQuantityString(
+ R.plurals.records_found,
+ adapter!!.count,
+ adapter!!.count
+ ),
+ Toast.LENGTH_LONG
+ ).show()
}
}
- return false;
+ return false
}
- @Override
- public boolean onQueryTextChange(String s) {
- Log.d(TAG, "onQueryTextChange ");
+ override fun onQueryTextChange(s: String): Boolean {
+ Log.d(TAG, "onQueryTextChange ")
if (adapter != null) {
- adapter.getFilter().filter(s);
+ adapter!!.filter.filter(s)
}
- return false;
+ return false
}
-
- });
-
- return true;
+ })
+ return true
}
-}
+ companion object {
+ private const val TAG = "HighScoreActivity"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/InboxActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/InboxActivity.kt
index 47b62c03..5ba94d6a 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/InboxActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/InboxActivity.kt
@@ -1,59 +1,65 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
+package de.bahnhoefe.deutschlands.bahnhofsfotos
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Toast;
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemClickListener
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityInboxBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.InboxAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PublicInbox
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-
-import java.util.List;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityInboxBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.InboxAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PublicInbox;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class InboxActivity extends AppCompatActivity {
-
- private static final String TAG = InboxActivity.class.getSimpleName();
-
- private InboxAdapter adapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- var binding = ActivityInboxBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- Call> inboxCall = ((BaseApplication)getApplication()).getRsapiClient().getPublicInbox();
- inboxCall.enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call> call, @NonNull Response> response) {
- var body = response.body();
- if (response.isSuccessful() && body != null) {
- adapter = new InboxAdapter(InboxActivity.this, body);
- binding.inboxList.setAdapter(adapter);
- binding.inboxList.setOnItemClickListener((parent, view, position, id) -> {
- var inboxItem = body.get(position);
- var intent = new Intent(InboxActivity.this, MapsActivity.class);
- intent.putExtra(MapsActivity.EXTRAS_LATITUDE, inboxItem.getLat());
- intent.putExtra(MapsActivity.EXTRAS_LONGITUDE, inboxItem.getLon());
- intent.putExtra(MapsActivity.EXTRAS_MARKER, inboxItem.getStationId() == null ? R.drawable.marker_missing : R.drawable.marker_red);
- startActivity(intent);
- });
+class InboxActivity : AppCompatActivity() {
+ private var adapter: InboxAdapter? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val binding = ActivityInboxBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding.root)
+ val inboxCall = (application as BaseApplication).rsapiClient.publicInbox
+ inboxCall!!.enqueue(object : Callback?> {
+ override fun onResponse(
+ call: Call?>,
+ response: Response?>
+ ) {
+ val body = response.body()
+ if (response.isSuccessful && body != null) {
+ adapter = InboxAdapter(this@InboxActivity, body)
+ binding.inboxList.adapter = adapter
+ binding.inboxList.onItemClickListener =
+ OnItemClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
+ val (_, _, stationId, lat, lon) = body[position]
+ val intent = Intent(this@InboxActivity, MapsActivity::class.java)
+ intent.putExtra(MapsActivity.Companion.EXTRAS_LATITUDE, lat)
+ intent.putExtra(MapsActivity.Companion.EXTRAS_LONGITUDE, lon)
+ intent.putExtra(
+ MapsActivity.Companion.EXTRAS_MARKER,
+ if (stationId == null) R.drawable.marker_missing else R.drawable.marker_red
+ )
+ startActivity(intent)
+ }
}
}
- @Override
- public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
- Log.e(TAG, "Error loading public inbox", t);
- Toast.makeText(getBaseContext(), getString(R.string.error_loading_inbox) + t.getMessage(), Toast.LENGTH_LONG).show();
+ override fun onFailure(call: Call?>, t: Throwable) {
+ Log.e(TAG, "Error loading public inbox", t)
+ Toast.makeText(
+ baseContext,
+ getString(R.string.error_loading_inbox) + t.message,
+ Toast.LENGTH_LONG
+ ).show()
}
- });
+ })
}
+ companion object {
+ private val TAG = InboxActivity::class.java.simpleName
+ }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/IntroSliderActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/IntroSliderActivity.kt
index 08ab5855..89861f99 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/IntroSliderActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/IntroSliderActivity.kt
@@ -1,155 +1,129 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.text.Html;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.viewpager.widget.PagerAdapter;
-import androidx.viewpager.widget.ViewPager;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityIntroSliderBinding;
-
-public class IntroSliderActivity extends AppCompatActivity {
-
- private ActivityIntroSliderBinding binding;
- private int[] layouts;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- BaseApplication baseApplication = (BaseApplication) getApplication();
-
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
-
- binding = ActivityIntroSliderBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- layouts = new int[]{R.layout.intro_slider1, R.layout.intro_slider2};
-
- addBottomDots(0);
- changeStatusBarColor();
- var viewPagerAdapter = new ViewPagerAdapter();
- binding.viewPager.setAdapter(viewPagerAdapter);
- binding.viewPager.addOnPageChangeListener(viewListener);
-
- binding.btnSliderSkip.setOnClickListener(v -> {
- baseApplication.setFirstAppStart(true);
- openMainActivity();
- });
-
- binding.btnSliderNext.setOnClickListener(v -> {
- int current = getNextItem();
- if (current < layouts.length) {
- binding.viewPager.setCurrentItem(current);
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.text.Html
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.viewpager.widget.PagerAdapter
+import androidx.viewpager.widget.ViewPager.OnPageChangeListener
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityIntroSliderBinding
+
+class IntroSliderActivity : AppCompatActivity() {
+ private var binding: ActivityIntroSliderBinding? = null
+ private var layouts: IntArray
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val baseApplication = application as BaseApplication
+ window.decorView.systemUiVisibility =
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ binding = ActivityIntroSliderBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ layouts = intArrayOf(R.layout.intro_slider1, R.layout.intro_slider2)
+ addBottomDots(0)
+ changeStatusBarColor()
+ val viewPagerAdapter = ViewPagerAdapter()
+ binding!!.viewPager.adapter = viewPagerAdapter
+ binding!!.viewPager.addOnPageChangeListener(viewListener)
+ binding!!.btnSliderSkip.setOnClickListener { v: View? ->
+ baseApplication.firstAppStart = true
+ openMainActivity()
+ }
+ binding!!.btnSliderNext.setOnClickListener { v: View? ->
+ val current = nextItem
+ if (current < layouts.size) {
+ binding!!.viewPager.currentItem = current
} else {
- openMainActivity();
+ openMainActivity()
}
- });
+ }
}
- private void openMainActivity() {
- var intent = new Intent(IntroSliderActivity.this, MainActivity.class);
- startActivity(intent);
- finish();
+ private fun openMainActivity() {
+ val intent = Intent(this@IntroSliderActivity, MainActivity::class.java)
+ startActivity(intent)
+ finish()
}
- @Override
- public void onBackPressed() {
- openMainActivity();
+ override fun onBackPressed() {
+ openMainActivity()
}
- private void addBottomDots(int position) {
- var dots = new TextView[layouts.length];
- var colorActive = getResources().getIntArray(R.array.dot_active);
- var colorInactive = getResources().getIntArray(R.array.dot_inactive);
- binding.layoutDots.removeAllViews();
-
- for (int i = 0; i < dots.length; i++) {
- dots[i] = new TextView(this);
- dots[i].setText(Html.fromHtml("•", Html.FROM_HTML_MODE_LEGACY));
- dots[i].setTextSize(35);
- dots[i].setTextColor(colorInactive[position]);
- binding.layoutDots.addView(dots[i]);
+ private fun addBottomDots(position: Int) {
+ val dots = arrayOfNulls(layouts.size)
+ val colorActive = resources.getIntArray(R.array.dot_active)
+ val colorInactive = resources.getIntArray(R.array.dot_inactive)
+ binding!!.layoutDots.removeAllViews()
+ for (i in dots.indices) {
+ dots[i] = TextView(this)
+ dots[i]!!.text = Html.fromHtml("•", Html.FROM_HTML_MODE_LEGACY)
+ dots[i]!!.textSize = 35f
+ dots[i]!!.setTextColor(colorInactive[position])
+ binding!!.layoutDots.addView(dots[i])
}
-
- if (dots.length > 0) {
- dots[position].setTextColor(colorActive[position]);
+ if (dots.size > 0) {
+ dots[position]!!.setTextColor(colorActive[position])
}
}
- private int getNextItem() {
- return binding.viewPager.getCurrentItem() + 1;
- }
-
- final ViewPager.OnPageChangeListener viewListener = new ViewPager.OnPageChangeListener() {
-
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-
+ private val nextItem: Int
+ private get() = binding!!.viewPager.currentItem + 1
+ val viewListener: OnPageChangeListener = object : OnPageChangeListener {
+ override fun onPageScrolled(
+ position: Int,
+ positionOffset: Float,
+ positionOffsetPixels: Int
+ ) {
}
- @Override
- public void onPageSelected(int position) {
- var baseApplication = (BaseApplication) getApplication();
- addBottomDots(position);
-
- if (position == layouts.length - 1) {
- binding.btnSliderNext.setText(R.string.proceed);
- binding.btnSliderSkip.setVisibility(View.INVISIBLE);
- baseApplication.setFirstAppStart(true);
+ override fun onPageSelected(position: Int) {
+ val baseApplication = application as BaseApplication
+ addBottomDots(position)
+ if (position == layouts.size - 1) {
+ binding!!.btnSliderNext.setText(R.string.proceed)
+ binding!!.btnSliderSkip.visibility = View.INVISIBLE
+ baseApplication.firstAppStart = true
} else {
- binding.btnSliderNext.setText(R.string.next);
- binding.btnSliderSkip.setVisibility(View.VISIBLE);
+ binding!!.btnSliderNext.setText(R.string.next)
+ binding!!.btnSliderSkip.visibility = View.VISIBLE
}
}
- @Override
- public void onPageScrollStateChanged(int state) {
-
- }
- };
-
- private void changeStatusBarColor() {
- var window = getWindow();
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- window.setStatusBarColor(Color.TRANSPARENT);
+ override fun onPageScrollStateChanged(state: Int) {}
}
- public class ViewPagerAdapter extends PagerAdapter {
+ private fun changeStatusBarColor() {
+ val window = window
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+ window.statusBarColor = Color.TRANSPARENT
+ }
- @Override
- @NonNull
- public Object instantiateItem(@NonNull ViewGroup container, int position) {
- var layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- var view = layoutInflater.inflate(layouts[position], container, false);
- container.addView(view);
- return view;
+ inner class ViewPagerAdapter : PagerAdapter() {
+ override fun instantiateItem(container: ViewGroup, position: Int): Any {
+ val layoutInflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
+ val view = layoutInflater.inflate(layouts[position], container, false)
+ container.addView(view)
+ return view
}
- @Override
- public void destroyItem(ViewGroup container, int position, @NonNull Object object) {
- var view = (View) object;
- container.removeView(view);
+ override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
+ val view = `object` as View
+ container.removeView(view)
}
- @Override
- public int getCount() {
- return layouts.length;
+ override fun getCount(): Int {
+ return layouts.size
}
- @Override
- public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
- return view == object;
+ override fun isViewFromObject(view: View, `object`: Any): Boolean {
+ return view === `object`
}
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MainActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MainActivity.kt
index b822ae45..2bc22eae 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MainActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MainActivity.kt
@@ -1,500 +1,556 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.Manifest;
-import android.app.AlertDialog;
-import android.app.SearchManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBarDrawerToggle;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.SearchView;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.GravityCompat;
-
-import com.google.android.material.navigation.NavigationView;
-
-import java.text.SimpleDateFormat;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMainBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.StationListAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.AppInfoFragment;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.StationFilterBar;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Statistic;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UpdatePolicy;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class MainActivity extends AppCompatActivity implements LocationListener, NavigationView.OnNavigationItemSelectedListener, StationFilterBar.OnChangeListener {
-
- private static final String DIALOG_TAG = "App Info Dialog";
- private static final long CHECK_UPDATE_INTERVAL = 10 * 60 * 1000; // 10 minutes
- private static final String TAG = MainActivity.class.getSimpleName();
- private static final int REQUEST_FINE_LOCATION = 1;
-
- // The minimum distance to change Updates in meters
- private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1000;
- // The minimum time between updates in milliseconds
- private static final long MIN_TIME_BW_UPDATES = 500; // minute
-
- private BaseApplication baseApplication;
- private DbAdapter dbAdapter;
-
- private ActivityMainBinding binding;
-
- private StationListAdapter stationListAdapter;
- private String searchString;
-
- private NearbyNotificationService.StatusBinder statusBinder;
- private RSAPIClient rsapiClient;
- private Location myPos;
- private LocationManager locationManager;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ActivityMainBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
- setSupportActionBar(binding.appBarMain.toolbar);
-
- baseApplication = (BaseApplication) getApplication();
- dbAdapter = baseApplication.getDbAdapter();
- rsapiClient = baseApplication.getRsapiClient();
-
- var toggle = new ActionBarDrawerToggle(
- this, binding.drawerLayout, binding.appBarMain.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
- binding.drawerLayout.addDrawerListener(toggle);
- toggle.syncState();
-
- binding.navView.setNavigationItemSelectedListener(this);
-
- var header = binding.navView.getHeaderView(0);
- TextView tvUpdate = header.findViewById(R.id.tvUpdate);
-
- if (!baseApplication.getFirstAppStart()) {
- startActivity(new Intent(this, IntroSliderActivity.class));
- finish();
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.Manifest
+import android.app.AlertDialog
+import android.app.SearchManager
+import android.content.ComponentName
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.ServiceConnection
+import android.content.pm.PackageManager
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.net.Uri
+import android.os.Build
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+import android.view.ContextThemeWrapper
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.AdapterView.OnItemClickListener
+import android.widget.TextView
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.ActionBarDrawerToggle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.SearchView
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.view.GravityCompat
+import com.google.android.material.navigation.NavigationView
+import de.bahnhoefe.deutschlands.bahnhofsfotos.NearbyNotificationService.StatusBinder
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMainBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.StationListAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.AppInfoFragment
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.StationFilterBar
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Statistic
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UpdatePolicy
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.text.SimpleDateFormat
+
+class MainActivity : AppCompatActivity(), LocationListener,
+ NavigationView.OnNavigationItemSelectedListener, StationFilterBar.OnChangeListener {
+ private lateinit var baseApplication: BaseApplication
+ private lateinit var dbAdapter: DbAdapter
+ private lateinit var binding: ActivityMainBinding
+ private var stationListAdapter: StationListAdapter? = null
+ private var searchString: String? = null
+ private var statusBinder: StatusBinder? = null
+ private lateinit var rsapiClient: RSAPIClient
+ private var myPos: Location? = null
+ private var locationManager: LocationManager? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding.root)
+ setSupportActionBar(binding.appBarMain.toolbar)
+ baseApplication = application as BaseApplication
+ dbAdapter = baseApplication.dbAdapter
+ rsapiClient = baseApplication.rsapiClient
+ val toggle = ActionBarDrawerToggle(
+ this,
+ binding.drawerLayout,
+ binding.appBarMain.toolbar,
+ R.string.navigation_drawer_open,
+ R.string.navigation_drawer_close
+ )
+ binding.drawerLayout.addDrawerListener(toggle)
+ toggle.syncState()
+ binding.navView.setNavigationItemSelectedListener(this)
+ val header = binding.navView.getHeaderView(0)
+ val tvUpdate = header.findViewById(R.id.tvUpdate)
+ if (!baseApplication.firstAppStart) {
+ startActivity(Intent(this, IntroSliderActivity::class.java))
+ finish()
}
-
- var lastUpdateDate = baseApplication.getLastUpdate();
+ val lastUpdateDate = baseApplication.lastUpdate
if (lastUpdateDate > 0) {
- tvUpdate.setText(getString(R.string.last_update_at, SimpleDateFormat.getDateTimeInstance().format(lastUpdateDate)));
+ tvUpdate.text = getString(
+ R.string.last_update_at,
+ SimpleDateFormat.getDateTimeInstance().format(lastUpdateDate)
+ )
} else {
- tvUpdate.setText(R.string.no_stations_in_database);
+ tvUpdate.setText(R.string.no_stations_in_database)
}
-
- var searchIntent = getIntent();
- if (Intent.ACTION_SEARCH.equals(searchIntent.getAction())) {
- searchString = searchIntent.getStringExtra(SearchManager.QUERY);
+ val searchIntent = intent
+ if (Intent.ACTION_SEARCH == searchIntent.action) {
+ searchString = searchIntent.getStringExtra(SearchManager.QUERY)
+ }
+ myPos = baseApplication.lastLocation
+ bindToStatus()
+ binding.appBarMain.main.pullToRefresh.setOnRefreshListener {
+ runUpdateCountriesAndStations()
+ binding.appBarMain.main.pullToRefresh.isRefreshing = false
}
-
- myPos = baseApplication.getLastLocation();
- bindToStatus();
-
- binding.appBarMain.main.pullToRefresh.setOnRefreshListener(() -> {
- runUpdateCountriesAndStations();
- binding.appBarMain.main.pullToRefresh.setRefreshing(false);
- });
}
- @Override
- public void onBackPressed() {
+ @Deprecated("Deprecated in Java")
+ override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
- binding.drawerLayout.closeDrawer(GravityCompat.START);
+ binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
- super.onBackPressed();
+ super.onBackPressed()
}
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main, menu);
-
- var manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- var searchMenu = menu.findItem(R.id.search);
- var search = (SearchView) searchMenu.getActionView();
- search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
- search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
-
- @Override
- public boolean onQueryTextSubmit(String s) {
- Log.d(TAG, "onQueryTextSubmit: " + s);
- searchString = s;
- updateStationList();
- return false;
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.main, menu)
+ val manager = getSystemService(SEARCH_SERVICE) as SearchManager
+ val searchMenu = menu.findItem(R.id.search)
+ val search = searchMenu.actionView as SearchView?
+ search!!.setSearchableInfo(manager.getSearchableInfo(componentName))
+ search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(s: String): Boolean {
+ Log.d(TAG, "onQueryTextSubmit: $s")
+ searchString = s
+ updateStationList()
+ return false
}
- @Override
- public boolean onQueryTextChange(String s) {
- Log.d(TAG, "onQueryTextChange: " + s);
- searchString = s;
- updateStationList();
- return false;
+ override fun onQueryTextChange(s: String): Boolean {
+ Log.d(TAG, "onQueryTextChange: $s")
+ searchString = s
+ updateStationList()
+ return false
}
-
- });
-
- var updatePolicy = baseApplication.getUpdatePolicy();
- menu.findItem(updatePolicy.getId()).setChecked(true);
-
- return true;
+ })
+ val updatePolicy = baseApplication.updatePolicy
+ menu.findItem(updatePolicy.id).isChecked = true
+ return true
}
- private void updateStationList() {
+ private fun updateStationList() {
try {
- var sortByDistance = baseApplication.getSortByDistance() && myPos != null;
- var stationCount = dbAdapter.countStations(baseApplication.getCountryCodes());
- var cursor = dbAdapter.getStationsListByKeyword(searchString, baseApplication.getStationFilter(), baseApplication.getCountryCodes(), sortByDistance, myPos);
+ val sortByDistance = baseApplication.sortByDistance && myPos != null
+ val stationCount = dbAdapter.countStations(baseApplication.countryCodes)
+ val cursor = dbAdapter.getStationsListByKeyword(
+ searchString,
+ baseApplication.stationFilter,
+ baseApplication.countryCodes,
+ sortByDistance,
+ myPos
+ )
if (stationListAdapter != null) {
- stationListAdapter.swapCursor(cursor);
+ stationListAdapter!!.swapCursor(cursor)
} else {
- stationListAdapter = new StationListAdapter(this, cursor, 0);
- binding.appBarMain.main.lstStations.setAdapter(stationListAdapter);
-
- binding.appBarMain.main.lstStations.setOnItemClickListener((listview, view, position, id) -> {
- var intentDetails = new Intent(MainActivity.this, DetailsActivity.class);
- intentDetails.putExtra(DetailsActivity.EXTRA_STATION, dbAdapter.fetchStationByRowId(id));
- startActivity(intentDetails);
- });
+ stationListAdapter = StationListAdapter(this, cursor, 0)
+ binding.appBarMain.main.lstStations.adapter = stationListAdapter
+ binding.appBarMain.main.lstStations.onItemClickListener =
+ OnItemClickListener { _, _, _, id ->
+ val intentDetails = Intent(this@MainActivity, DetailsActivity::class.java)
+ intentDetails.putExtra(
+ DetailsActivity.EXTRA_STATION,
+ dbAdapter.fetchStationByRowId(id)
+ )
+ startActivity(intentDetails)
+ }
}
- binding.appBarMain.main.filterResult.setText(getString(R.string.filter_result, stationListAdapter.getCount(), stationCount));
- } catch (Exception e) {
- Log.e(TAG, "Unhandled Exception in onQueryTextSubmit", e);
+ binding.appBarMain.main.filterResult.text =
+ getString(R.string.filter_result, stationListAdapter!!.count, stationCount)
+ } catch (e: Exception) {
+ Log.e(TAG, "Unhandled Exception in onQueryTextSubmit", e)
}
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val id = item.itemId
// necessary for the update policy submenu
- item.setChecked(!item.isChecked());
-
- if (id == R.id.rb_update_manual) {
- baseApplication.setUpdatePolicy(UpdatePolicy.MANUAL);
- } else if (id == R.id.rb_update_automatic) {
- baseApplication.setUpdatePolicy(UpdatePolicy.AUTOMATIC);
- } else if (id == R.id.rb_update_notify) {
- baseApplication.setUpdatePolicy(UpdatePolicy.NOTIFY);
- } else if (id == R.id.apiUrl) {
- showApiUrlDialog();
- }
+ item.isChecked = !item.isChecked
+ when (id) {
+ R.id.rb_update_manual -> {
+ baseApplication.updatePolicy = UpdatePolicy.MANUAL
+ }
- return super.onOptionsItemSelected(item);
- }
+ R.id.rb_update_automatic -> {
+ baseApplication.updatePolicy = UpdatePolicy.AUTOMATIC
+ }
- private void showApiUrlDialog() {
- SimpleDialogs.prompt(this, R.string.apiUrl, EditorInfo.TYPE_TEXT_VARIATION_URI, R.string.api_url_hint, baseApplication.getApiUrl(), v -> {
- baseApplication.setApiUrl(v);
- baseApplication.setLastUpdate(0);
- recreate();
- });
- }
+ R.id.rb_update_notify -> {
+ baseApplication.updatePolicy = UpdatePolicy.NOTIFY
+ }
- private void setNotificationIcon(boolean active) {
- var item = binding.navView.getMenu().findItem(R.id.nav_notification);
- item.setIcon(ContextCompat.getDrawable(this, active ? R.drawable.ic_notifications_active_gray_24px : R.drawable.ic_notifications_off_gray_24px));
+ R.id.apiUrl -> {
+ showApiUrlDialog()
+ }
+ }
+ return super.onOptionsItemSelected(item)
}
- @Override
- public boolean onNavigationItemSelected(MenuItem item) {
- // Handle navigation view item clicks here.
- int id = item.getItemId();
- if (id == R.id.nav_slideshow) {
- startActivity(new Intent(this, IntroSliderActivity.class));
- finish();
- } else if (id == R.id.nav_your_data) {
- startActivity(new Intent(this, MyDataActivity.class));
- } else if (id == R.id.nav_update_photos) {
- runUpdateCountriesAndStations();
- } else if (id == R.id.nav_notification) {
- toggleNotification();
- } else if (id == R.id.nav_highscore) {
- startActivity(new Intent(this, HighScoreActivity.class));
- } else if (id == R.id.nav_outbox) {
- startActivity(new Intent(this, OutboxActivity.class));
- } else if (id == R.id.nav_inbox) {
- startActivity(new Intent(this, InboxActivity.class));
- } else if (id == R.id.nav_stations_map) {
- startActivity(new Intent(this, MapsActivity.class));
- } else if (id == R.id.nav_web_site) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://railway-stations.org")));
- } else if (id == R.id.nav_email) {
- var emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + getString(R.string.fab_email)));
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.fab_subject));
- startActivity(Intent.createChooser(emailIntent, getString(R.string.fab_chooser_title)));
- } else if (id == R.id.nav_app_info) {
- new AppInfoFragment().show(getSupportFragmentManager(), DIALOG_TAG);
+ private fun showApiUrlDialog() {
+ SimpleDialogs.prompt(
+ this,
+ R.string.apiUrl,
+ EditorInfo.TYPE_TEXT_VARIATION_URI,
+ R.string.api_url_hint,
+ baseApplication.apiUrl
+ ) { v: String? ->
+ baseApplication.apiUrl = v
+ baseApplication.lastUpdate = 0
+ recreate()
}
+ }
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- return true;
+ private fun setNotificationIcon(active: Boolean) {
+ val item = binding.navView.menu.findItem(R.id.nav_notification)
+ item.icon = ContextCompat.getDrawable(
+ this,
+ if (active) R.drawable.ic_notifications_active_gray_24px else R.drawable.ic_notifications_off_gray_24px
+ )
}
- private void runUpdateCountriesAndStations() {
- binding.appBarMain.main.progressBar.setVisibility(View.VISIBLE);
+ override fun onNavigationItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.nav_slideshow -> {
+ startActivity(Intent(this, IntroSliderActivity::class.java))
+ finish()
+ }
+
+ R.id.nav_your_data -> {
+ startActivity(Intent(this, MyDataActivity::class.java))
+ }
- rsapiClient.runUpdateCountriesAndStations(this, baseApplication, success -> {
- if (success) {
- TextView tvUpdate = findViewById(R.id.tvUpdate);
- tvUpdate.setText(getString(R.string.last_update_at, SimpleDateFormat.getDateTimeInstance().format(baseApplication.getLastUpdate())));
- updateStationList();
+ R.id.nav_update_photos -> {
+ runUpdateCountriesAndStations()
+ }
+
+ R.id.nav_notification -> {
+ toggleNotification()
+ }
+
+ R.id.nav_highscore -> {
+ startActivity(Intent(this, HighScoreActivity::class.java))
+ }
+
+ R.id.nav_outbox -> {
+ startActivity(Intent(this, OutboxActivity::class.java))
+ }
+
+ R.id.nav_inbox -> {
+ startActivity(Intent(this, InboxActivity::class.java))
}
- binding.appBarMain.main.progressBar.setVisibility(View.GONE);
- });
+ R.id.nav_stations_map -> {
+ startActivity(Intent(this, MapsActivity::class.java))
+ }
+
+ R.id.nav_web_site -> {
+ startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://railway-stations.org")))
+ }
+
+ R.id.nav_email -> {
+ val emailIntent =
+ Intent(
+ Intent.ACTION_SENDTO,
+ Uri.parse("mailto:" + getString(R.string.fab_email))
+ )
+ emailIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.fab_subject))
+ startActivity(
+ Intent.createChooser(
+ emailIntent,
+ getString(R.string.fab_chooser_title)
+ )
+ )
+ }
+
+ R.id.nav_app_info -> {
+ AppInfoFragment().show(supportFragmentManager, DIALOG_TAG)
+ }
+ }
+ binding.drawerLayout.closeDrawer(GravityCompat.START)
+ return true
}
- @Override
- protected void onPause() {
- super.onPause();
- unregisterLocationManager();
+ private fun runUpdateCountriesAndStations() {
+ binding.appBarMain.main.progressBar.visibility = View.VISIBLE
+ rsapiClient.runUpdateCountriesAndStations(this, baseApplication) { success: Boolean ->
+ if (success) {
+ val tvUpdate = findViewById(R.id.tvUpdate)
+ tvUpdate.text = getString(
+ R.string.last_update_at,
+ SimpleDateFormat.getDateTimeInstance().format(baseApplication.lastUpdate)
+ )
+ updateStationList()
+ }
+ binding.appBarMain.main.progressBar.visibility = View.GONE
+ }
}
- @Override
- public void onResume() {
- super.onResume();
+ override fun onPause() {
+ super.onPause()
+ unregisterLocationManager()
+ }
- for (int i = 0; i < binding.navView.getMenu().size(); i++) {
- binding.navView.getMenu().getItem(i).setChecked(false);
+ public override fun onResume() {
+ super.onResume()
+ for (i in 0 until binding.navView.menu.size()) {
+ binding.navView.menu.getItem(i).isChecked = false
}
-
- if (baseApplication.getLastUpdate() == 0) {
- runUpdateCountriesAndStations();
- } else if (System.currentTimeMillis() - baseApplication.getLastUpdate() > CHECK_UPDATE_INTERVAL) {
- baseApplication.setLastUpdate(System.currentTimeMillis());
- if (baseApplication.getUpdatePolicy() != UpdatePolicy.MANUAL) {
- for (var country : baseApplication.getCountryCodes()) {
- rsapiClient.getStatistic(country).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- if (response.isSuccessful()) {
- checkForUpdates(response.body(), country);
+ if (baseApplication.lastUpdate == 0L) {
+ runUpdateCountriesAndStations()
+ } else if (System.currentTimeMillis() - baseApplication.lastUpdate > CHECK_UPDATE_INTERVAL) {
+ baseApplication.lastUpdate = System.currentTimeMillis()
+ if (baseApplication.updatePolicy !== UpdatePolicy.MANUAL) {
+ for (country in baseApplication.countryCodes) {
+ rsapiClient.getStatistic(country)!!.enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.isSuccessful) {
+ checkForUpdates(response.body(), country)
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error loading country statistic", t);
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error loading country statistic", t)
}
- });
+ })
}
}
}
-
- if (baseApplication.getSortByDistance()) {
- registerLocationManager();
+ if (baseApplication.sortByDistance) {
+ registerLocationManager()
}
-
- binding.appBarMain.main.stationFilterBar.init(baseApplication, this);
- updateStationList();
+ binding.appBarMain.main.stationFilterBar.init(baseApplication, this)
+ updateStationList()
}
- private void checkForUpdates(Statistic statistic, String country) {
+ private fun checkForUpdates(statistic: Statistic?, country: String?) {
if (statistic == null) {
- return;
+ return
}
-
- var dbStat = dbAdapter.getStatistic(country);
- Log.d(TAG, "DbStat: " + dbStat);
- if (statistic.getTotal() != dbStat.getTotal() || statistic.getWithPhoto() != dbStat.getWithPhoto() || statistic.getWithoutPhoto() != dbStat.getWithoutPhoto()) {
- if (baseApplication.getUpdatePolicy() == UpdatePolicy.AUTOMATIC) {
- runUpdateCountriesAndStations();
+ val dbStat = dbAdapter.getStatistic(country)
+ Log.d(TAG, "DbStat: $dbStat")
+ if (statistic.total != dbStat!!.total || statistic.withPhoto != dbStat.withPhoto || statistic.withoutPhoto != dbStat.withoutPhoto) {
+ if (baseApplication.updatePolicy === UpdatePolicy.AUTOMATIC) {
+ runUpdateCountriesAndStations()
} else {
- new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom))
- .setIcon(R.mipmap.ic_launcher)
- .setTitle(R.string.app_name)
- .setMessage(R.string.update_available)
- .setCancelable(true)
- .setPositiveButton(R.string.button_ok_text, (dialog, which) -> {
- runUpdateCountriesAndStations();
- dialog.dismiss();
- })
- .setNegativeButton(R.string.button_cancel_text, (dialog, which) -> dialog.dismiss())
- .create().show();
+ AlertDialog.Builder(ContextThemeWrapper(this, R.style.AlertDialogCustom))
+ .setIcon(R.mipmap.ic_launcher)
+ .setTitle(R.string.app_name)
+ .setMessage(R.string.update_available)
+ .setCancelable(true)
+ .setPositiveButton(R.string.button_ok_text) { dialog: DialogInterface, _: Int ->
+ runUpdateCountriesAndStations()
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.button_cancel_text) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
+ .create().show()
}
}
}
- private void bindToStatus() {
- var intent = new Intent(this, NearbyNotificationService.class);
- intent.setAction(NearbyNotificationService.STATUS_INTERFACE);
- if (!this.getApplicationContext().bindService(intent, new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d(TAG, "Bound to status service of NearbyNotificationService");
- statusBinder = (NearbyNotificationService.StatusBinder) service;
- invalidateOptionsMenu();
- }
+ private fun bindToStatus() {
+ val intent = Intent(this, NearbyNotificationService::class.java)
+ intent.action = NearbyNotificationService.Companion.STATUS_INTERFACE
+ if (!this.applicationContext.bindService(intent, object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ Log.d(TAG, "Bound to status service of NearbyNotificationService")
+ statusBinder = service as StatusBinder
+ invalidateOptionsMenu()
+ }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d(TAG, "Unbound from status service of NearbyNotificationService");
- statusBinder = null;
- invalidateOptionsMenu();
- }
- }, 0)) {
- Log.e(TAG, "Bind request to statistics interface failed");
+ override fun onServiceDisconnected(name: ComponentName) {
+ Log.d(TAG, "Unbound from status service of NearbyNotificationService")
+ statusBinder = null
+ invalidateOptionsMenu()
+ }
+ }, 0)) {
+ Log.e(TAG, "Bind request to statistics interface failed")
}
}
- private final ActivityResultLauncher requestNotificationPermissionLauncher =
- registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
- if (!isGranted) {
- Toast.makeText(MainActivity.this, R.string.notification_permission_needed, Toast.LENGTH_SHORT).show();
- }
- });
-
- public void toggleNotification() {
- if (statusBinder == null
- && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
- && ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
- requestNotificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
- return;
+ private val requestNotificationPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean? ->
+ if (!isGranted!!) {
+ Toast.makeText(
+ this@MainActivity,
+ R.string.notification_permission_needed,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
}
- toggleNotificationWithPermissionGranted();
+ private fun toggleNotification() {
+ if (statusBinder == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ requestNotificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
+ return
+ }
+ toggleNotificationWithPermissionGranted()
}
- private void toggleNotificationWithPermissionGranted() {
- var intent = new Intent(MainActivity.this, NearbyNotificationService.class);
+ private fun toggleNotificationWithPermissionGranted() {
+ val intent = Intent(this@MainActivity, NearbyNotificationService::class.java)
if (statusBinder == null) {
- startService(intent);
- bindToStatus();
- setNotificationIcon(true);
+ startService(intent)
+ bindToStatus()
+ setNotificationIcon(true)
} else {
- stopService(intent);
- setNotificationIcon(false);
+ stopService(intent)
+ setNotificationIcon(false)
}
}
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_FINE_LOCATION) {
- Log.i(TAG, "Received response for location permission request.");
+ Log.i(TAG, "Received response for location permission request.")
// Check if the required permission has been granted
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Location permission has been granted
- registerLocationManager();
+ registerLocationManager()
} else {
//Permission not granted
- baseApplication.setSortByDistance(false);
- binding.appBarMain.main.stationFilterBar.setSortOrder(false);
+ baseApplication.sortByDistance = false
+ binding.appBarMain.main.stationFilterBar.setSortOrder(false)
}
}
}
- public void registerLocationManager() {
+ private fun registerLocationManager() {
try {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
- && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
- return;
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED
+ && ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ REQUEST_FINE_LOCATION
+ )
+ return
}
-
- locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
+ locationManager =
+ applicationContext.getSystemService(LOCATION_SERVICE) as LocationManager
// getting GPS status
- var isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ val isGPSEnabled = locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER)
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "GPS Enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "GPS Enabled")
if (locationManager != null) {
- myPos = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ myPos = locationManager!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
}
} else {
// getting network status
- var isNetworkEnabled = locationManager
- .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ val isNetworkEnabled = locationManager!!
+ .isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// First get location from Network Provider
if (isNetworkEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "Network Location enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "Network Location enabled")
if (locationManager != null) {
- myPos = locationManager
- .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+ myPos = locationManager!!
+ .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
}
}
}
- } catch (Exception e) {
- Log.e(TAG, "Error registering LocationManager", e);
- var b = new Bundle();
- b.putString("error", "Error registering LocationManager: " + e);
- locationManager = null;
- baseApplication.setSortByDistance(false);
- binding.appBarMain.main.stationFilterBar.setSortOrder(false);
- return;
+ } catch (e: Exception) {
+ Log.e(TAG, "Error registering LocationManager", e)
+ val b = Bundle()
+ b.putString("error", "Error registering LocationManager: $e")
+ locationManager = null
+ baseApplication.sortByDistance = false
+ binding.appBarMain.main.stationFilterBar.setSortOrder(false)
+ return
}
- Log.i(TAG, "LocationManager registered");
- onLocationChanged(myPos);
+ Log.i(TAG, "LocationManager registered")
+ onLocationChanged(myPos!!)
}
- private void unregisterLocationManager() {
+ private fun unregisterLocationManager() {
if (locationManager != null) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
- locationManager.removeUpdates(this);
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ locationManager!!.removeUpdates(this)
}
- locationManager = null;
+ locationManager = null
}
- Log.i(TAG, "LocationManager unregistered");
+ Log.i(TAG, "LocationManager unregistered")
}
- @Override
- public void onLocationChanged(@NonNull Location location) {
- myPos = location;
- updateStationList();
+ override fun onLocationChanged(location: Location) {
+ myPos = location
+ updateStationList()
}
- @Override
- public void stationFilterChanged(StationFilter stationFilter) {
- baseApplication.setStationFilter(stationFilter);
- updateStationList();
+ override fun stationFilterChanged(stationFilter: StationFilter) {
+ baseApplication.stationFilter = stationFilter
+ updateStationList()
}
- @Override
- public void sortOrderChanged(boolean sortByDistance) {
+ override fun sortOrderChanged(sortByDistance: Boolean) {
if (sortByDistance) {
- registerLocationManager();
+ registerLocationManager()
}
- updateStationList();
+ updateStationList()
}
-}
+ companion object {
+ private const val DIALOG_TAG = "App Info Dialog"
+ private const val CHECK_UPDATE_INTERVAL = (10 * 60 * 1000 // 10 minutes
+ ).toLong()
+ private val TAG = MainActivity::class.java.simpleName
+ private const val REQUEST_FINE_LOCATION = 1
+
+ // The minimum distance to change Updates in meters
+ private const val MIN_DISTANCE_CHANGE_FOR_UPDATES: Long = 1000
+
+ // The minimum time between updates in milliseconds
+ private const val MIN_TIME_BW_UPDATES: Long = 500 // minute
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MapsActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MapsActivity.kt
index 1354917f..fe5dd863 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MapsActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MapsActivity.kt
@@ -1,210 +1,179 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import static android.view.Menu.NONE;
-
-import android.Manifest;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.CheckBox;
-import android.widget.Toast;
-
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-import androidx.core.content.res.ResourcesCompat;
-import androidx.documentfile.provider.DocumentFile;
-
-import org.mapsforge.core.graphics.Align;
-import org.mapsforge.core.graphics.Bitmap;
-import org.mapsforge.core.graphics.FontFamily;
-import org.mapsforge.core.graphics.FontStyle;
-import org.mapsforge.core.graphics.Style;
-import org.mapsforge.core.model.LatLong;
-import org.mapsforge.core.model.MapPosition;
-import org.mapsforge.core.model.Point;
-import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
-import org.mapsforge.map.android.input.MapZoomControls;
-import org.mapsforge.map.android.util.AndroidUtil;
-import org.mapsforge.map.datastore.MapDataStore;
-import org.mapsforge.map.layer.Layer;
-import org.mapsforge.map.layer.cache.TileCache;
-import org.mapsforge.map.layer.download.TileDownloadLayer;
-import org.mapsforge.map.layer.download.tilesource.AbstractTileSource;
-import org.mapsforge.map.layer.download.tilesource.OnlineTileSource;
-import org.mapsforge.map.layer.download.tilesource.OpenStreetMapMapnik;
-import org.mapsforge.map.layer.overlay.Marker;
-import org.mapsforge.map.layer.renderer.TileRendererLayer;
-import org.mapsforge.map.model.IMapViewPosition;
-import org.mapsforge.map.reader.MapFile;
-import org.mapsforge.map.rendertheme.InternalRenderTheme;
-import org.mapsforge.map.rendertheme.StreamRenderTheme;
-import org.mapsforge.map.rendertheme.XmlRenderTheme;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMapsBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.MapInfoFragment;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.StationFilterBar;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.ClusterManager;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.DbsTileSource;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.GeoItem;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.MarkerBitmap;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.TapHandler;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter;
-
-public class MapsActivity extends AppCompatActivity implements LocationListener, TapHandler, StationFilterBar.OnChangeListener {
-
- public static final String EXTRAS_LATITUDE = "Extras_Latitude";
- public static final String EXTRAS_LONGITUDE = "Extras_Longitude";
- public static final String EXTRAS_MARKER = "Extras_Marker";
-
- // The minimum distance to change Updates in meters
- private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // meters
-
- // The minimum time between updates in milliseconds
- private static final long MIN_TIME_BW_UPDATES = 500; // minute
-
- private static final String TAG = MapsActivity.class.getSimpleName();
- private static final int REQUEST_FINE_LOCATION = 1;
- private static final String USER_AGENT = "railway-stations.org-android";
-
- private final Map onlineTileSources = new HashMap<>();
- protected Layer layer;
- protected ClusterManager clusterer = null;
- protected final List tileCaches = new ArrayList<>();
- private LatLong myPos = null;
- private CheckBox myLocSwitch = null;
- private DbAdapter dbAdapter;
- private String nickname;
- private BaseApplication baseApplication;
- private LocationManager locationManager;
- private boolean askedForPermission = false;
- private Marker missingMarker;
-
- private ActivityMapsBinding binding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- AndroidGraphicFactory.createInstance(this.getApplication());
-
- binding = ActivityMapsBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
- var window = getWindow();
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- window.setStatusBarColor(Color.parseColor("#c71c4d"));
-
- setSupportActionBar(binding.mapsToolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- baseApplication = (BaseApplication) getApplication();
- dbAdapter = baseApplication.getDbAdapter();
- nickname = baseApplication.getNickname();
-
- var intent = getIntent();
- Marker extraMarker = null;
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.Manifest
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.Color
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.net.Uri
+import android.os.Bundle
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.WindowManager
+import android.widget.CheckBox
+import android.widget.CompoundButton
+import android.widget.Toast
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.ActivityResultLauncher
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.content.res.ResourcesCompat
+import androidx.documentfile.provider.DocumentFile
+import de.bahnhoefe.deutschlands.bahnhofsfotos.MapsActivity.BahnhofGeoItem
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMapsBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.MapInfoFragment
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.StationFilterBar
+import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.ClusterManager
+import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.DbsTileSource
+import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.GeoItem
+import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.MarkerBitmap
+import de.bahnhoefe.deutschlands.bahnhofsfotos.mapsforge.TapHandler
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter
+import org.mapsforge.core.graphics.Align
+import org.mapsforge.core.graphics.Bitmap
+import org.mapsforge.core.graphics.FontFamily
+import org.mapsforge.core.graphics.FontStyle
+import org.mapsforge.core.graphics.Style
+import org.mapsforge.core.model.LatLong
+import org.mapsforge.core.model.MapPosition
+import org.mapsforge.core.model.Point
+import org.mapsforge.map.android.graphics.AndroidGraphicFactory
+import org.mapsforge.map.android.input.MapZoomControls
+import org.mapsforge.map.android.util.AndroidUtil
+import org.mapsforge.map.datastore.MapDataStore
+import org.mapsforge.map.layer.Layer
+import org.mapsforge.map.layer.cache.TileCache
+import org.mapsforge.map.layer.download.TileDownloadLayer
+import org.mapsforge.map.layer.download.tilesource.AbstractTileSource
+import org.mapsforge.map.layer.download.tilesource.OnlineTileSource
+import org.mapsforge.map.layer.download.tilesource.OpenStreetMapMapnik
+import org.mapsforge.map.layer.overlay.Marker
+import org.mapsforge.map.layer.renderer.TileRendererLayer
+import org.mapsforge.map.model.IMapViewPosition
+import org.mapsforge.map.reader.MapFile
+import org.mapsforge.map.rendertheme.InternalRenderTheme
+import org.mapsforge.map.rendertheme.StreamRenderTheme
+import org.mapsforge.map.rendertheme.XmlRenderTheme
+import java.io.FileInputStream
+import java.io.FileNotFoundException
+import java.lang.ref.WeakReference
+import java.util.Optional
+import java.util.function.Function
+
+class MapsActivity : AppCompatActivity(), LocationListener, TapHandler,
+ StationFilterBar.OnChangeListener {
+ private val onlineTileSources: MutableMap = HashMap()
+ protected var layer: Layer? = null
+ protected var clusterer: ClusterManager? = null
+ protected val tileCaches: MutableList = ArrayList()
+ private var myPos: LatLong? = null
+ private var myLocSwitch: CheckBox? = null
+ private var dbAdapter: DbAdapter? = null
+ private var nickname: String? = null
+ private var baseApplication: BaseApplication? = null
+ private var locationManager: LocationManager? = null
+ private var askedForPermission = false
+ private var missingMarker: Marker? = null
+ private var binding: ActivityMapsBinding? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ AndroidGraphicFactory.createInstance(this.application)
+ binding = ActivityMapsBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ val window = window
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+ window.statusBarColor = Color.parseColor("#c71c4d")
+ setSupportActionBar(binding!!.mapsToolbar)
+ supportActionBar!!.setDisplayHomeAsUpEnabled(true)
+ baseApplication = application as BaseApplication
+ dbAdapter = baseApplication.getDbAdapter()
+ nickname = baseApplication.getNickname()
+ val intent = intent
+ var extraMarker: Marker? = null
if (intent != null) {
- var latitude = (Double) intent.getSerializableExtra(EXTRAS_LATITUDE);
- var longitude = (Double) intent.getSerializableExtra(EXTRAS_LONGITUDE);
- setMyLocSwitch(false);
+ val latitude = intent.getSerializableExtra(EXTRAS_LATITUDE) as Double?
+ val longitude = intent.getSerializableExtra(EXTRAS_LONGITUDE) as Double?
+ setMyLocSwitch(false)
if (latitude != null && longitude != null) {
- myPos = new LatLong(latitude, longitude);
+ myPos = LatLong(latitude, longitude)
}
-
- var markerRes = (Integer) intent.getSerializableExtra(EXTRAS_MARKER);
+ val markerRes = intent.getSerializableExtra(EXTRAS_MARKER) as Int?
if (markerRes != null) {
- extraMarker = createBitmapMarker(myPos, markerRes);
+ extraMarker = createBitmapMarker(myPos, markerRes)
}
}
-
- addDBSTileSource(R.string.dbs_osm_basic, "/styles/dbs-osm-basic/");
- addDBSTileSource(R.string.dbs_osm_railway, "/styles/dbs-osm-railway/");
-
- createMapViews();
- createTileCaches();
- checkPermissionsAndCreateLayersAndControls();
-
+ addDBSTileSource(R.string.dbs_osm_basic, "/styles/dbs-osm-basic/")
+ addDBSTileSource(R.string.dbs_osm_railway, "/styles/dbs-osm-railway/")
+ createMapViews()
+ createTileCaches()
+ checkPermissionsAndCreateLayersAndControls()
if (extraMarker != null) {
- binding.map.mapView.getLayerManager().getLayers().add(extraMarker);
+ binding!!.map.mapView.layerManager.layers.add(extraMarker)
}
}
- private void addDBSTileSource(int nameResId, String baseUrl) {
- var dbsBasic = new DbsTileSource(getString(nameResId), baseUrl);
- onlineTileSources.put(dbsBasic.getName(), dbsBasic);
+ private fun addDBSTileSource(nameResId: Int, baseUrl: String) {
+ val dbsBasic = DbsTileSource(getString(nameResId), baseUrl)
+ onlineTileSources[dbsBasic.name] = dbsBasic
}
- protected void createTileCaches() {
- this.tileCaches.add(AndroidUtil.createTileCache(this, getPersistableId(),
- this.binding.map.mapView.getModel().displayModel.getTileSize(), this.getScreenRatio(),
- this.binding.map.mapView.getModel().frameBufferModel.getOverdrawFactor(), true));
- }
-
- /**
- * The persistable ID is used to store settings information, like the center of the last view
- * and the zoomlevel. By default the simple name of the class is used. The value is not user
- * visibile.
- *
- * @return the id that is used to save this mapview.
- */
- protected String getPersistableId() {
- return this.getClass().getSimpleName();
+ protected fun createTileCaches() {
+ tileCaches.add(
+ AndroidUtil.createTileCache(
+ this, persistableId,
+ binding!!.map.mapView.model.displayModel.tileSize, screenRatio,
+ binding!!.map.mapView.model.frameBufferModel.overdrawFactor, true
+ )
+ )
}
- /**
- * Returns the relative size of a map view in relation to the screen size of the device. This
- * is used for cache size calculations.
- * By default this returns 1.0, for a full size map view.
- *
- * @return the screen ratio of the mapview
- */
- protected float getScreenRatio() {
- return 1.0f;
- }
+ protected val persistableId: String
+ /**
+ * The persistable ID is used to store settings information, like the center of the last view
+ * and the zoomlevel. By default the simple name of the class is used. The value is not user
+ * visibile.
+ *
+ * @return the id that is used to save this mapview.
+ */
+ protected get() = this.javaClass.simpleName
+ protected val screenRatio: Float
+ /**
+ * Returns the relative size of a map view in relation to the screen size of the device. This
+ * is used for cache size calculations.
+ * By default this returns 1.0, for a full size map view.
+ *
+ * @return the screen ratio of the mapview
+ */
+ protected get() = 1.0f
/**
* Hook to check for Android Runtime Permissions.
*/
- protected void checkPermissionsAndCreateLayersAndControls() {
- createLayers();
- createControls();
+ protected fun checkPermissionsAndCreateLayersAndControls() {
+ createLayers()
+ createControls()
}
/**
* Hook to create controls, such as scale bars.
* You can add more controls.
*/
- protected void createControls() {
- initializePosition(binding.map.mapView.getModel().mapViewPosition);
+ protected fun createControls() {
+ initializePosition(binding!!.map.mapView.model.mapViewPosition)
}
/**
@@ -212,801 +181,855 @@ public class MapsActivity extends AppCompatActivity implements LocationListener,
*
* @param mvp the map view position to be set
*/
- protected void initializePosition(IMapViewPosition mvp) {
+ protected fun initializePosition(mvp: IMapViewPosition) {
if (myPos != null) {
- mvp.setMapPosition(new MapPosition(myPos, baseApplication.getZoomLevelDefault()));
+ mvp.mapPosition = MapPosition(myPos, baseApplication.getZoomLevelDefault())
} else {
- mvp.setMapPosition(baseApplication.getLastMapPosition());
+ mvp.mapPosition = baseApplication.getLastMapPosition()
}
- mvp.setZoomLevelMax(getZoomLevelMax());
- mvp.setZoomLevelMin(getZoomLevelMin());
+ mvp.zoomLevelMax = zoomLevelMax
+ mvp.zoomLevelMin = zoomLevelMin
}
/**
* Template method to create the map views.
*/
- protected void createMapViews() {
- binding.map.mapView.setClickable(true);
- binding.map.mapView.setOnMapDragListener(() -> myLocSwitch.setChecked(false));
- binding.map.mapView.getMapScaleBar().setVisible(true);
- binding.map.mapView.setBuiltInZoomControls(true);
- binding.map.mapView.getMapZoomControls().setAutoHide(true);
- binding.map.mapView.getMapZoomControls().setZoomLevelMin(getZoomLevelMin());
- binding.map.mapView.getMapZoomControls().setZoomLevelMax(getZoomLevelMax());
-
- binding.map.mapView.getMapZoomControls().setZoomControlsOrientation(MapZoomControls.Orientation.VERTICAL_IN_OUT);
- binding.map.mapView.getMapZoomControls().setZoomInResource(R.drawable.zoom_control_in);
- binding.map.mapView.getMapZoomControls().setZoomOutResource(R.drawable.zoom_control_out);
- binding.map.mapView.getMapZoomControls().setMarginHorizontal(getResources().getDimensionPixelOffset(R.dimen.controls_margin));
- binding.map.mapView.getMapZoomControls().setMarginVertical(getResources().getDimensionPixelOffset(R.dimen.controls_margin));
+ protected fun createMapViews() {
+ binding!!.map.mapView.isClickable = true
+ binding!!.map.mapView.setOnMapDragListener { myLocSwitch!!.isChecked = false }
+ binding!!.map.mapView.mapScaleBar.isVisible = true
+ binding!!.map.mapView.setBuiltInZoomControls(true)
+ binding!!.map.mapView.mapZoomControls.isAutoHide = true
+ binding!!.map.mapView.mapZoomControls.zoomLevelMin = zoomLevelMin
+ binding!!.map.mapView.mapZoomControls.zoomLevelMax = zoomLevelMax
+ binding!!.map.mapView.mapZoomControls.setZoomControlsOrientation(MapZoomControls.Orientation.VERTICAL_IN_OUT)
+ binding!!.map.mapView.mapZoomControls.setZoomInResource(R.drawable.zoom_control_in)
+ binding!!.map.mapView.mapZoomControls.setZoomOutResource(R.drawable.zoom_control_out)
+ binding!!.map.mapView.mapZoomControls.setMarginHorizontal(
+ resources.getDimensionPixelOffset(
+ R.dimen.controls_margin
+ )
+ )
+ binding!!.map.mapView.mapZoomControls.setMarginVertical(resources.getDimensionPixelOffset(R.dimen.controls_margin))
}
- protected byte getZoomLevelMax() {
- return binding.map.mapView.getModel().mapViewPosition.getZoomLevelMax();
- }
-
- protected byte getZoomLevelMin() {
- return binding.map.mapView.getModel().mapViewPosition.getZoomLevelMin();
- }
+ protected val zoomLevelMax: Byte
+ protected get() = binding!!.map.mapView.model.mapViewPosition.zoomLevelMax
+ protected val zoomLevelMin: Byte
+ protected get() = binding!!.map.mapView.model.mapViewPosition.zoomLevelMin
/**
* Hook to purge tile caches.
* By default we purge every tile cache that has been added to the tileCaches list.
*/
- protected void purgeTileCaches() {
- for (TileCache tileCache : tileCaches) {
- tileCache.purge();
- }
- tileCaches.clear();
- }
-
- protected XmlRenderTheme getRenderTheme() {
- var mapTheme = baseApplication.getMapThemeUri();
- return mapTheme.map(m -> {
- try {
- var renderThemeFile = DocumentFile.fromSingleUri(getApplication(), m);
- return new StreamRenderTheme("/assets/", getContentResolver().openInputStream(renderThemeFile.getUri()));
- } catch (Exception e) {
- Log.e(TAG, "Error loading theme " + mapTheme, e);
- return InternalRenderTheme.DEFAULT;
- }
- }).orElse(InternalRenderTheme.DEFAULT);
+ protected fun purgeTileCaches() {
+ for (tileCache in tileCaches) {
+ tileCache.purge()
+ }
+ tileCaches.clear()
}
- protected Optional getMapFile() {
- var mapUri = BaseApplication.toUri(baseApplication.getMap());
- return mapUri.map(map -> {
- if (!DocumentFile.isDocumentUri(this, map)) {
- return null;
- }
- try {
- var inputStream = (FileInputStream) getContentResolver().openInputStream(map);
- return new MapFile(inputStream, 0, null);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Can't open mapFile", e);
+ protected val renderTheme: XmlRenderTheme
+ protected get() {
+ val mapTheme = baseApplication.getMapThemeUri()
+ return mapTheme!!.map { m: Uri? ->
+ try {
+ val renderThemeFile = DocumentFile.fromSingleUri(application, m!!)
+ return@map StreamRenderTheme(
+ "/assets/", contentResolver.openInputStream(
+ renderThemeFile!!.uri
+ )
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "Error loading theme $mapTheme", e)
+ return@map InternalRenderTheme.DEFAULT
+ }
+ }.orElse(InternalRenderTheme.DEFAULT)
+ }
+ protected val mapFile: Optional
+ protected get() {
+ val mapUri: Optional = BaseApplication.Companion.toUri(baseApplication.getMap())
+ return mapUri.map { map: Uri? ->
+ if (!DocumentFile.isDocumentUri(this, map)) {
+ return@map null
+ }
+ try {
+ val inputStream = contentResolver.openInputStream(map!!) as FileInputStream?
+ return@map MapFile(inputStream, 0, null)
+ } catch (e: FileNotFoundException) {
+ Log.e(TAG, "Can't open mapFile", e)
+ }
+ null
}
- return null;
- });
- }
-
- protected void createLayers() {
- var mapFile = getMapFile();
+ }
- if (mapFile.isPresent()) {
- var rendererLayer = new TileRendererLayer(this.tileCaches.get(0), mapFile.get(),
- this.binding.map.mapView.getModel().mapViewPosition, false, true, false, AndroidGraphicFactory.INSTANCE) {
- @Override
- public boolean onLongPress(LatLong tapLatLong, Point thisXY,
- Point tapXY) {
- MapsActivity.this.onLongPress(tapLatLong);
- return true;
+ protected fun createLayers() {
+ val mapFile = mapFile
+ if (mapFile.isPresent) {
+ val rendererLayer: TileRendererLayer = object : TileRendererLayer(
+ tileCaches[0],
+ mapFile.get(),
+ binding!!.map.mapView.model.mapViewPosition,
+ false,
+ true,
+ false,
+ AndroidGraphicFactory.INSTANCE
+ ) {
+ override fun onLongPress(
+ tapLatLong: LatLong, thisXY: Point,
+ tapXY: Point
+ ): Boolean {
+ this@MapsActivity.onLongPress(tapLatLong)
+ return true
}
- };
- rendererLayer.setXmlRenderTheme(getRenderTheme());
- this.layer = rendererLayer;
- binding.map.mapView.getLayerManager().getLayers().add(this.layer);
+ }
+ rendererLayer.setXmlRenderTheme(renderTheme)
+ layer = rendererLayer
+ binding!!.map.mapView.layerManager.layers.add(layer)
} else {
- AbstractTileSource tileSource = onlineTileSources.get(baseApplication.getMap());
-
+ var tileSource: AbstractTileSource? = onlineTileSources[baseApplication.getMap()]
if (tileSource == null) {
- tileSource = OpenStreetMapMapnik.INSTANCE;
+ tileSource = OpenStreetMapMapnik.INSTANCE
}
-
- tileSource.setUserAgent(USER_AGENT);
- this.layer = new TileDownloadLayer(this.tileCaches.get(0),
- this.binding.map.mapView.getModel().mapViewPosition, tileSource,
- AndroidGraphicFactory.INSTANCE) {
- @Override
- public boolean onLongPress(LatLong tapLatLong, Point thisXY,
- Point tapXY) {
- MapsActivity.this.onLongPress(tapLatLong);
- return true;
+ tileSource!!.userAgent = USER_AGENT
+ layer = object : TileDownloadLayer(
+ tileCaches[0],
+ binding!!.map.mapView.model.mapViewPosition, tileSource,
+ AndroidGraphicFactory.INSTANCE
+ ) {
+ override fun onLongPress(
+ tapLatLong: LatLong, thisXY: Point,
+ tapXY: Point
+ ): Boolean {
+ this@MapsActivity.onLongPress(tapLatLong)
+ return true
}
- };
- binding.map.mapView.getLayerManager().getLayers().add(this.layer);
-
- binding.map.mapView.setZoomLevelMin(tileSource.getZoomLevelMin());
- binding.map.mapView.setZoomLevelMax(tileSource.getZoomLevelMax());
+ }
+ binding!!.map.mapView.layerManager.layers.add(layer)
+ binding!!.map.mapView.setZoomLevelMin(tileSource.zoomLevelMin)
+ binding!!.map.mapView.setZoomLevelMax(tileSource.zoomLevelMax)
}
-
}
- private Marker createBitmapMarker(LatLong latLong, int markerRes) {
- var drawable = ContextCompat.getDrawable(this, markerRes);
- assert drawable != null;
- var bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
- return new Marker(latLong, bitmap, -(bitmap.getWidth() / 2), -bitmap.getHeight());
+ private fun createBitmapMarker(latLong: LatLong?, markerRes: Int): Marker {
+ val drawable = ContextCompat.getDrawable(this, markerRes)!!
+ val bitmap = AndroidGraphicFactory.convertToBitmap(drawable)
+ return Marker(latLong, bitmap, -(bitmap.width / 2), -bitmap.height)
}
- private void onLongPress(LatLong tapLatLong) {
+ private fun onLongPress(tapLatLong: LatLong) {
if (missingMarker == null) {
// marker to show at the location
- var drawable = ContextCompat.getDrawable(this, R.drawable.marker_missing);
- assert drawable != null;
- var bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
- missingMarker = new Marker(tapLatLong, bitmap, -(bitmap.getWidth() / 2), -bitmap.getHeight()) {
- @Override
- public boolean onTap(LatLong tapLatLong, Point layerXY, Point tapXY) {
- SimpleDialogs.confirmOkCancel(MapsActivity.this, R.string.add_missing_station, (dialogInterface, i) -> {
- var intent = new Intent(MapsActivity.this, UploadActivity.class);
- intent.putExtra(UploadActivity.EXTRA_LATITUDE, getLatLong().latitude);
- intent.putExtra(UploadActivity.EXTRA_LONGITUDE, getLatLong().longitude);
- startActivity(intent);
- });
- return false;
+ val drawable = ContextCompat.getDrawable(this, R.drawable.marker_missing)!!
+ val bitmap = AndroidGraphicFactory.convertToBitmap(drawable)
+ missingMarker =
+ object : Marker(tapLatLong, bitmap, -(bitmap.width / 2), -bitmap.height) {
+ override fun onTap(tapLatLong: LatLong, layerXY: Point, tapXY: Point): Boolean {
+ SimpleDialogs.confirmOkCancel(
+ this@MapsActivity,
+ R.string.add_missing_station
+ ) { dialogInterface: DialogInterface?, i: Int ->
+ val intent = Intent(this@MapsActivity, UploadActivity::class.java)
+ intent.putExtra(
+ UploadActivity.Companion.EXTRA_LATITUDE,
+ latLong.latitude
+ )
+ intent.putExtra(
+ UploadActivity.Companion.EXTRA_LONGITUDE,
+ latLong.longitude
+ )
+ startActivity(intent)
+ }
+ return false
+ }
}
- };
- binding.map.mapView.getLayerManager().getLayers().add(missingMarker);
+ binding!!.map.mapView.layerManager.layers.add(missingMarker)
} else {
- missingMarker.setLatLong(tapLatLong);
- missingMarker.requestRedraw();
+ missingMarker!!.latLong = tapLatLong
+ missingMarker!!.requestRedraw()
}
// feedback for long click
- ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createOneShot(150, VibrationEffect.DEFAULT_AMPLITUDE));
-
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.maps, menu);
-
- var item = menu.findItem(R.id.menu_toggle_mypos);
- myLocSwitch = new CheckBox(this);
- myLocSwitch.setButtonDrawable(R.drawable.ic_gps_fix_selector);
- myLocSwitch.setChecked(baseApplication.isLocationUpdates());
- item.setActionView(myLocSwitch);
- myLocSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
- baseApplication.setLocationUpdates(isChecked);
- if (isChecked) {
- askedForPermission = false;
- registerLocationManager();
- } else {
- unregisterLocationManager();
- }
- }
- );
-
- var map = baseApplication.getMap();
-
- var osmMapnick = menu.findItem(R.id.osm_mapnik);
- osmMapnick.setChecked(map == null);
- osmMapnick.setOnMenuItemClickListener(new MapMenuListener(this, baseApplication, null));
+ (getSystemService(VIBRATOR_SERVICE) as Vibrator).vibrate(
+ VibrationEffect.createOneShot(
+ 150,
+ VibrationEffect.DEFAULT_AMPLITUDE
+ )
+ )
+ }
- var mapSubmenu = menu.findItem(R.id.maps_submenu).getSubMenu();
- assert mapSubmenu != null;
- for (var tileSource : onlineTileSources.values()) {
- var mapItem = mapSubmenu.add(R.id.maps_group, NONE, NONE, tileSource.getName());
- mapItem.setChecked(tileSource.getName().equals(map));
- mapItem.setOnMenuItemClickListener(new MapMenuListener(this, baseApplication, tileSource.getName()));
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ super.onCreateOptionsMenu(menu)
+ menuInflater.inflate(R.menu.maps, menu)
+ val item = menu.findItem(R.id.menu_toggle_mypos)
+ myLocSwitch = CheckBox(this)
+ myLocSwitch!!.setButtonDrawable(R.drawable.ic_gps_fix_selector)
+ myLocSwitch!!.isChecked = baseApplication!!.isLocationUpdates
+ item.actionView = myLocSwitch
+ myLocSwitch!!.setOnCheckedChangeListener { buttonView: CompoundButton?, isChecked: Boolean ->
+ baseApplication.setLocationUpdates(isChecked)
+ if (isChecked) {
+ askedForPermission = false
+ registerLocationManager()
+ } else {
+ unregisterLocationManager()
+ }
}
-
- var mapDirectory = baseApplication.getMapDirectoryUri();
- if (mapDirectory.isPresent()) {
- var documentsTree = getDocumentFileFromTreeUri(mapDirectory.get());
+ val map = baseApplication.getMap()
+ val osmMapnick = menu.findItem(R.id.osm_mapnik)
+ osmMapnick.isChecked = map == null
+ osmMapnick.setOnMenuItemClickListener(MapMenuListener(this, baseApplication, null))
+ val mapSubmenu = menu.findItem(R.id.maps_submenu).subMenu!!
+ for (tileSource in onlineTileSources.values) {
+ val mapItem = mapSubmenu.add(R.id.maps_group, Menu.NONE, Menu.NONE, tileSource.name)
+ mapItem.isChecked = tileSource.name == map
+ mapItem.setOnMenuItemClickListener(
+ MapMenuListener(
+ this,
+ baseApplication,
+ tileSource.name
+ )
+ )
+ }
+ val mapDirectory = baseApplication.getMapDirectoryUri()
+ if (mapDirectory!!.isPresent) {
+ val documentsTree = getDocumentFileFromTreeUri(mapDirectory!!.get())
if (documentsTree != null) {
- for (var file : documentsTree.listFiles()) {
- if (file.isFile() && file.getName().endsWith(".map")) {
- var mapItem = mapSubmenu.add(R.id.maps_group, NONE, NONE, file.getName());
- mapItem.setChecked(BaseApplication.toUri(map).map(uri -> file.getUri().equals(uri)).orElse(false));
- mapItem.setOnMenuItemClickListener(new MapMenuListener(this, baseApplication, file.getUri().toString()));
+ for (file in documentsTree.listFiles()) {
+ if (file.isFile && file.name!!.endsWith(".map")) {
+ val mapItem =
+ mapSubmenu.add(R.id.maps_group, Menu.NONE, Menu.NONE, file.name)
+ mapItem.isChecked = BaseApplication.Companion.toUri(map).map(
+ Function { uri: Uri -> file.uri == uri }).orElse(false)
+ mapItem.setOnMenuItemClickListener(
+ MapMenuListener(
+ this,
+ baseApplication,
+ file.uri.toString()
+ )
+ )
}
}
}
}
- mapSubmenu.setGroupCheckable(R.id.maps_group, true, true);
-
- var mapFolder = mapSubmenu.add(R.string.map_folder);
- mapFolder.setOnMenuItemClickListener(item1 -> {
- openMapDirectoryChooser();
- return false;
- });
-
- var mapTheme = baseApplication.getMapThemeUri();
- var mapThemeDirectory = baseApplication.getMapThemeDirectoryUri();
-
- var defaultTheme = menu.findItem(R.id.default_theme);
- defaultTheme.setChecked(!mapTheme.isPresent());
- defaultTheme.setOnMenuItemClickListener(new MapThemeMenuListener(this, baseApplication, null));
- var themeSubmenu = menu.findItem(R.id.themes_submenu).getSubMenu();
- assert themeSubmenu != null;
-
- if (mapThemeDirectory.isPresent()) {
- var documentsTree = getDocumentFileFromTreeUri(mapThemeDirectory.get());
+ mapSubmenu.setGroupCheckable(R.id.maps_group, true, true)
+ val mapFolder = mapSubmenu.add(R.string.map_folder)
+ mapFolder.setOnMenuItemClickListener { item1: MenuItem? ->
+ openMapDirectoryChooser()
+ false
+ }
+ val mapTheme = baseApplication.getMapThemeUri()
+ val mapThemeDirectory = baseApplication.getMapThemeDirectoryUri()
+ val defaultTheme = menu.findItem(R.id.default_theme)
+ defaultTheme.isChecked = !mapTheme!!.isPresent
+ defaultTheme.setOnMenuItemClickListener(MapThemeMenuListener(this, baseApplication, null))
+ val themeSubmenu = menu.findItem(R.id.themes_submenu).subMenu!!
+ if (mapThemeDirectory!!.isPresent) {
+ val documentsTree = getDocumentFileFromTreeUri(mapThemeDirectory!!.get())
if (documentsTree != null) {
- for (var file : documentsTree.listFiles()) {
- if (file.isFile() && file.getName().endsWith(".xml")) {
- var themeName = file.getName();
- var themeItem = themeSubmenu.add(R.id.themes_group, NONE, NONE, themeName);
- themeItem.setChecked(mapTheme.map(uri -> file.getUri().equals(uri)).orElse(false));
- themeItem.setOnMenuItemClickListener(new MapThemeMenuListener(this, baseApplication, file.getUri()));
- } else if (file.isDirectory()) {
- var childFile = file.findFile(file.getName() + ".xml");
+ for (file in documentsTree.listFiles()) {
+ if (file.isFile && file.name!!.endsWith(".xml")) {
+ val themeName = file.name
+ val themeItem =
+ themeSubmenu.add(R.id.themes_group, Menu.NONE, Menu.NONE, themeName)
+ themeItem.isChecked = mapTheme!!.map { uri: Uri? -> file.uri == uri }
+ .orElse(false)
+ themeItem.setOnMenuItemClickListener(
+ MapThemeMenuListener(
+ this,
+ baseApplication,
+ file.uri
+ )
+ )
+ } else if (file.isDirectory) {
+ val childFile = file.findFile(file.name + ".xml")
if (childFile != null) {
- var themeName = file.getName();
- var themeItem = themeSubmenu.add(R.id.themes_group, NONE, NONE, themeName);
- themeItem.setChecked(mapTheme.map(uri -> childFile.getUri().equals(uri)).orElse(false));
- themeItem.setOnMenuItemClickListener(new MapThemeMenuListener(this, baseApplication, childFile.getUri()));
+ val themeName = file.name
+ val themeItem =
+ themeSubmenu.add(R.id.themes_group, Menu.NONE, Menu.NONE, themeName)
+ themeItem.isChecked =
+ mapTheme!!.map { uri: Uri? -> childFile.uri == uri }
+ .orElse(false)
+ themeItem.setOnMenuItemClickListener(
+ MapThemeMenuListener(
+ this,
+ baseApplication,
+ childFile.uri
+ )
+ )
}
}
}
}
}
- themeSubmenu.setGroupCheckable(R.id.themes_group, true, true);
-
- var themeFolder = themeSubmenu.add(R.string.theme_folder);
- themeFolder.setOnMenuItemClickListener(item12 -> {
- openThemeDirectoryChooser();
- return false;
- });
-
- return true;
+ themeSubmenu.setGroupCheckable(R.id.themes_group, true, true)
+ val themeFolder = themeSubmenu.add(R.string.theme_folder)
+ themeFolder.setOnMenuItemClickListener { item12: MenuItem? ->
+ openThemeDirectoryChooser()
+ false
+ }
+ return true
}
- private DocumentFile getDocumentFileFromTreeUri(Uri uri) {
+ private fun getDocumentFileFromTreeUri(uri: Uri): DocumentFile? {
try {
- return DocumentFile.fromTreeUri(getApplication(), uri);
- } catch (Exception e) {
- Log.w(TAG, "Error getting DocumentFile from Uri: " + uri);
- }
- return null;
- }
-
- protected ActivityResultLauncher themeDirectoryLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
- var uri = result.getData().getData();
- if (uri != null) {
- getContentResolver().takePersistableUriPermission(
- uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- );
- baseApplication.setMapThemeDirectoryUri(uri);
- recreate();
- }
- }
- });
-
- protected ActivityResultLauncher mapDirectoryLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
- var uri = result.getData().getData();
- if (uri != null) {
- getContentResolver().takePersistableUriPermission(
- uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- );
- baseApplication.setMapDirectoryUri(uri);
- recreate();
- }
- }
- });
+ return DocumentFile.fromTreeUri(application, uri)
+ } catch (e: Exception) {
+ Log.w(TAG, "Error getting DocumentFile from Uri: $uri")
+ }
+ return null
+ }
- public void openDirectory(ActivityResultLauncher launcher) {
- var intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
- launcher.launch(intent);
+ protected var themeDirectoryLauncher = registerForActivityResult(
+ StartActivityForResult()
+ ) { result: ActivityResult ->
+ if (result.resultCode == RESULT_OK && result.data != null) {
+ val uri = result.data!!.data
+ if (uri != null) {
+ contentResolver.takePersistableUriPermission(
+ uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ baseApplication!!.setMapThemeDirectoryUri(uri)
+ recreate()
+ }
+ }
+ }
+ protected var mapDirectoryLauncher = registerForActivityResult(
+ StartActivityForResult()
+ ) { result: ActivityResult ->
+ if (result.resultCode == RESULT_OK && result.data != null) {
+ val uri = result.data!!.data
+ if (uri != null) {
+ contentResolver.takePersistableUriPermission(
+ uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ baseApplication!!.setMapDirectoryUri(uri)
+ recreate()
+ }
+ }
}
+ fun openDirectory(launcher: ActivityResultLauncher) {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
+ launcher.launch(intent)
+ }
- private void openMapDirectoryChooser() {
- openDirectory(mapDirectoryLauncher);
+ private fun openMapDirectoryChooser() {
+ openDirectory(mapDirectoryLauncher)
}
- private void openThemeDirectoryChooser() {
- openDirectory(themeDirectoryLauncher);
+ private fun openThemeDirectoryChooser() {
+ openDirectory(themeDirectoryLauncher)
}
/**
* Android Activity life cycle method.
*/
- @Override
- protected void onDestroy() {
- binding.map.mapView.destroyAll();
- AndroidGraphicFactory.clearResourceMemoryCache();
- purgeTileCaches();
- super.onDestroy();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.map_info) {
- new MapInfoFragment().show(getSupportFragmentManager(), "Map Info Dialog");
+ override fun onDestroy() {
+ binding!!.map.mapView.destroyAll()
+ AndroidGraphicFactory.clearResourceMemoryCache()
+ purgeTileCaches()
+ super.onDestroy()
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == R.id.map_info) {
+ MapInfoFragment().show(supportFragmentManager, "Map Info Dialog")
} else {
- return super.onOptionsItemSelected(item);
+ return super.onOptionsItemSelected(item)
}
- return true;
+ return true
}
- private void reloadMap() {
- destroyClusterManager();
- new LoadMapMarkerTask(this).start();
+ private fun reloadMap() {
+ destroyClusterManager()
+ LoadMapMarkerTask(this).start()
}
- private void runUpdateCountriesAndStations() {
- binding.map.progressBar.setVisibility(View.VISIBLE);
- baseApplication.getRsapiClient().runUpdateCountriesAndStations(this, baseApplication, success -> reloadMap());
+ private fun runUpdateCountriesAndStations() {
+ binding!!.map.progressBar.visibility = View.VISIBLE
+ baseApplication.getRsapiClient().runUpdateCountriesAndStations(
+ this,
+ baseApplication
+ ) { success: Boolean -> reloadMap() }
}
-
- private void onStationsLoaded(List stationList, List uploadList) {
+ private fun onStationsLoaded(stationList: List?, uploadList: List?) {
try {
- createClusterManager();
- addMarkers(stationList, uploadList);
- binding.map.progressBar.setVisibility(View.GONE);
- Toast.makeText(this, getResources().getQuantityString(R.plurals.stations_loaded, stationList.size(), stationList.size()), Toast.LENGTH_LONG).show();
- } catch (Exception e) {
- Log.e(TAG, "Error loading markers", e);
+ createClusterManager()
+ addMarkers(stationList, uploadList)
+ binding!!.map.progressBar.visibility = View.GONE
+ Toast.makeText(
+ this,
+ resources.getQuantityString(
+ R.plurals.stations_loaded,
+ stationList!!.size,
+ stationList.size
+ ),
+ Toast.LENGTH_LONG
+ ).show()
+ } catch (e: Exception) {
+ Log.e(TAG, "Error loading markers", e)
}
}
- @Override
- public void onTap(BahnhofGeoItem marker) {
- var intent = new Intent(MapsActivity.this, DetailsActivity.class);
- var id = marker.getStation().getId();
- var country = marker.getStation().getCountry();
+ override fun onTap(marker: BahnhofGeoItem) {
+ val intent = Intent(this@MapsActivity, DetailsActivity::class.java)
+ val id = marker.station!!.id
+ val country = marker.station!!.country
try {
- var station = dbAdapter.getStationByKey(country, id);
- intent.putExtra(DetailsActivity.EXTRA_STATION, station);
- startActivity(intent);
- } catch (RuntimeException e) {
- Log.wtf(TAG, String.format("Could not fetch station id %s that we put onto the map", id), e);
+ val station = dbAdapter!!.getStationByKey(country, id)
+ intent.putExtra(DetailsActivity.Companion.EXTRA_STATION, station)
+ startActivity(intent)
+ } catch (e: RuntimeException) {
+ Log.wtf(
+ TAG,
+ String.format("Could not fetch station id %s that we put onto the map", id),
+ e
+ )
}
}
- public void setMyLocSwitch(boolean checked) {
+ fun setMyLocSwitch(checked: Boolean) {
if (myLocSwitch != null) {
- myLocSwitch.setChecked(checked);
+ myLocSwitch!!.isChecked = checked
}
- baseApplication.setLocationUpdates(checked);
+ baseApplication.setLocationUpdates(checked)
}
- @Override
- public void stationFilterChanged(StationFilter stationFilter) {
- reloadMap();
+ override fun stationFilterChanged(stationFilter: StationFilter?) {
+ reloadMap()
}
- @Override
- public void sortOrderChanged(boolean sortByDistance) {
+ override fun sortOrderChanged(sortByDistance: Boolean) {
// unused
}
- private static class LoadMapMarkerTask extends Thread {
- private final WeakReference activityRef;
+ private class LoadMapMarkerTask(activity: MapsActivity) : Thread() {
+ private val activityRef: WeakReference
- public LoadMapMarkerTask(MapsActivity activity) {
- this.activityRef = new WeakReference<>(activity);
+ init {
+ activityRef = WeakReference(activity)
}
- @Override
- public void run() {
- var stationList = activityRef.get().readStations();
- var uploadList = activityRef.get().readPendingUploads();
- var mapsActivity = activityRef.get();
- if (mapsActivity != null) {
- mapsActivity.runOnUiThread(() -> mapsActivity.onStationsLoaded(stationList, uploadList));
- }
+ override fun run() {
+ val stationList = activityRef.get()!!.readStations()
+ val uploadList = activityRef.get()!!.readPendingUploads()
+ val mapsActivity = activityRef.get()
+ mapsActivity?.runOnUiThread { mapsActivity.onStationsLoaded(stationList, uploadList) }
}
-
}
- private List readStations() {
+ private fun readStations(): List? {
try {
- return dbAdapter.getAllStations(baseApplication.getStationFilter(), baseApplication.getCountryCodes());
- } catch (Exception e) {
- Log.i(TAG, "Datenbank konnte nicht geöffnet werden");
+ return dbAdapter!!.getAllStations(
+ baseApplication.getStationFilter(),
+ baseApplication.getCountryCodes()
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "Datenbank konnte nicht geöffnet werden")
}
- return null;
+ return null
}
- private List readPendingUploads() {
+ private fun readPendingUploads(): List? {
try {
- return dbAdapter.getPendingUploads(false);
- } catch (Exception e) {
- Log.i(TAG, "Datenbank konnte nicht geöffnet werden");
+ return dbAdapter!!.getPendingUploads(false)
+ } catch (e: Exception) {
+ Log.i(TAG, "Datenbank konnte nicht geöffnet werden")
}
- return null;
+ return null
}
- private List createMarkerBitmaps() {
- var markerBitmaps = new ArrayList();
- markerBitmaps.add(createSmallSingleIconMarker());
- markerBitmaps.add(createSmallClusterIconMarker());
- markerBitmaps.add(createLargeClusterIconMarker());
- return markerBitmaps;
+ private fun createMarkerBitmaps(): List {
+ val markerBitmaps = ArrayList()
+ markerBitmaps.add(createSmallSingleIconMarker())
+ markerBitmaps.add(createSmallClusterIconMarker())
+ markerBitmaps.add(createLargeClusterIconMarker())
+ return markerBitmaps
}
/**
* large cluster icon. 100 will be ignored.
*/
- private MarkerBitmap createLargeClusterIconMarker() {
- var bitmapBalloonMN = loadBitmap(R.drawable.balloon_m_n);
- var paint = AndroidGraphicFactory.INSTANCE.createPaint();
- paint.setStyle(Style.FILL);
- paint.setTextAlign(Align.CENTER);
- paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD);
- paint.setColor(Color.BLACK);
- return new MarkerBitmap(this.getApplicationContext(), bitmapBalloonMN,
- new Point(0, 0), 11f, 100, paint);
+ private fun createLargeClusterIconMarker(): MarkerBitmap {
+ val bitmapBalloonMN = loadBitmap(R.drawable.balloon_m_n)
+ val paint = AndroidGraphicFactory.INSTANCE.createPaint()
+ paint.setStyle(Style.FILL)
+ paint.setTextAlign(Align.CENTER)
+ paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD)
+ paint.color = Color.BLACK
+ return MarkerBitmap(
+ this.applicationContext, bitmapBalloonMN,
+ 11f, paint
+ )
}
/**
* small cluster icon. for 10 or less items.
*/
- private MarkerBitmap createSmallClusterIconMarker() {
- var bitmapBalloonSN = loadBitmap(R.drawable.balloon_s_n);
- var paint = AndroidGraphicFactory.INSTANCE.createPaint();
- paint.setStyle(Style.FILL);
- paint.setTextAlign(Align.CENTER);
- paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD);
- paint.setColor(Color.BLACK);
- return new MarkerBitmap(this.getApplicationContext(), bitmapBalloonSN,
- new Point(0, 0), 9f, 10, paint);
- }
-
- private MarkerBitmap createSmallSingleIconMarker() {
- var bitmapWithPhoto = loadBitmap(R.drawable.marker_green);
- var markerWithoutPhoto = loadBitmap(R.drawable.marker_red);
- var markerOwnPhoto = loadBitmap(R.drawable.marker_violet);
- var markerPendingUpload = loadBitmap(R.drawable.marker_yellow);
-
- var markerWithPhotoInactive = loadBitmap(R.drawable.marker_green_inactive);
- var markerWithoutPhotoInactive = loadBitmap(R.drawable.marker_red_inactive);
- var markerOwnPhotoInactive = loadBitmap(R.drawable.marker_violet_inactive);
-
- var paint = AndroidGraphicFactory.INSTANCE.createPaint();
- paint.setStyle(Style.FILL);
- paint.setTextAlign(Align.CENTER);
- paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD);
- paint.setColor(Color.RED);
-
- return new MarkerBitmap(this.getApplicationContext(), markerWithoutPhoto, bitmapWithPhoto, markerOwnPhoto,
- markerWithoutPhotoInactive, markerWithPhotoInactive, markerOwnPhotoInactive, markerPendingUpload,
- new Point(0, -(markerWithoutPhoto.getHeight() / 2.0)), 10f, 1, paint);
- }
-
- private Bitmap loadBitmap(int resourceId) {
- var bitmap = AndroidGraphicFactory.convertToBitmap(ResourcesCompat.getDrawable(getResources(), resourceId, null));
- bitmap.incrementRefCount();
- return bitmap;
- }
-
- private void addMarkers(List stationMarker, List uploadList) {
- double minLat = 0;
- double maxLat = 0;
- double minLon = 0;
- double maxLon = 0;
- for (var station : stationMarker) {
- var isPendingUpload = isPendingUpload(station, uploadList);
- var geoItem = new BahnhofGeoItem(station, isPendingUpload);
- var bahnhofPos = geoItem.getLatLong();
+ private fun createSmallClusterIconMarker(): MarkerBitmap {
+ val bitmapBalloonSN = loadBitmap(R.drawable.balloon_s_n)
+ val paint = AndroidGraphicFactory.INSTANCE.createPaint()
+ paint.setStyle(Style.FILL)
+ paint.setTextAlign(Align.CENTER)
+ paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD)
+ paint.color = Color.BLACK
+ return MarkerBitmap(
+ this.applicationContext, bitmapBalloonSN,
+ 9f, paint
+ )
+ }
+
+ private fun createSmallSingleIconMarker(): MarkerBitmap {
+ val bitmapWithPhoto = loadBitmap(R.drawable.marker_green)
+ val markerWithoutPhoto = loadBitmap(R.drawable.marker_red)
+ val markerOwnPhoto = loadBitmap(R.drawable.marker_violet)
+ val markerPendingUpload = loadBitmap(R.drawable.marker_yellow)
+ val markerWithPhotoInactive = loadBitmap(R.drawable.marker_green_inactive)
+ val markerWithoutPhotoInactive = loadBitmap(R.drawable.marker_red_inactive)
+ val markerOwnPhotoInactive = loadBitmap(R.drawable.marker_violet_inactive)
+ val paint = AndroidGraphicFactory.INSTANCE.createPaint()
+ paint.setStyle(Style.FILL)
+ paint.setTextAlign(Align.CENTER)
+ paint.setTypeface(FontFamily.DEFAULT, FontStyle.BOLD)
+ paint.color = Color.RED
+ return MarkerBitmap(
+ this.applicationContext,
+ markerWithoutPhoto,
+ bitmapWithPhoto,
+ markerOwnPhoto,
+ markerWithoutPhotoInactive,
+ markerWithPhotoInactive,
+ markerOwnPhotoInactive,
+ markerPendingUpload,
+ 10f,
+ paint
+ )
+ }
+
+ private fun loadBitmap(resourceId: Int): Bitmap {
+ val bitmap = AndroidGraphicFactory.convertToBitmap(
+ ResourcesCompat.getDrawable(
+ resources,
+ resourceId,
+ null
+ )
+ )
+ bitmap.incrementRefCount()
+ return bitmap
+ }
+
+ private fun addMarkers(stationMarker: List?, uploadList: List?) {
+ var minLat = 0.0
+ var maxLat = 0.0
+ var minLon = 0.0
+ var maxLon = 0.0
+ for (station in stationMarker!!) {
+ val isPendingUpload = isPendingUpload(station, uploadList)
+ val geoItem = BahnhofGeoItem(station, isPendingUpload)
+ val bahnhofPos = geoItem.getLatLong()
if (minLat == 0.0) {
- minLat = bahnhofPos.latitude;
- maxLat = bahnhofPos.latitude;
- minLon = bahnhofPos.longitude;
- maxLon = bahnhofPos.longitude;
+ minLat = bahnhofPos!!.latitude
+ maxLat = bahnhofPos.latitude
+ minLon = bahnhofPos.longitude
+ maxLon = bahnhofPos.longitude
} else {
- minLat = Math.min(minLat, bahnhofPos.latitude);
- maxLat = Math.max(maxLat, bahnhofPos.latitude);
- minLon = Math.min(minLon, bahnhofPos.longitude);
- maxLon = Math.max(maxLon, bahnhofPos.longitude);
+ minLat = Math.min(minLat, bahnhofPos!!.latitude)
+ maxLat = Math.max(maxLat, bahnhofPos.latitude)
+ minLon = Math.min(minLon, bahnhofPos.longitude)
+ maxLon = Math.max(maxLon, bahnhofPos.longitude)
}
- clusterer.addItem(geoItem);
+ clusterer!!.addItem(geoItem)
}
-
- clusterer.redraw();
-
- if (myPos == null || (myPos.latitude == 0.0 && myPos.longitude == 0.0)) {
- myPos = new LatLong((minLat + maxLat) / 2, (minLon + maxLon) / 2);
+ clusterer!!.redraw()
+ if (myPos == null || myPos!!.latitude == 0.0 && myPos!!.longitude == 0.0) {
+ myPos = LatLong((minLat + maxLat) / 2, (minLon + maxLon) / 2)
}
- updatePosition();
+ updatePosition()
}
- private boolean isPendingUpload(Station station, List uploadList) {
- for (var upload : uploadList) {
- if (upload.isPendingPhotoUpload() && station.getId().equals(upload.getStationId()) && station.getCountry().equals(upload.getCountry())) {
- return true;
+ private fun isPendingUpload(station: Station?, uploadList: List?): Boolean {
+ for (upload in uploadList!!) {
+ if (upload!!.isPendingPhotoUpload && station!!.id == upload.stationId && station.country == upload.country) {
+ return true
}
}
- return false;
+ return false
}
- @Override
- public void onResume() {
- super.onResume();
- if (this.layer instanceof TileDownloadLayer) {
- ((TileDownloadLayer) this.layer).onResume();
+ public override fun onResume() {
+ super.onResume()
+ if (layer is TileDownloadLayer) {
+ (layer as TileDownloadLayer?)!!.onResume()
}
- if (baseApplication.getLastUpdate() == 0) {
- runUpdateCountriesAndStations();
+ if (baseApplication.getLastUpdate() == 0L) {
+ runUpdateCountriesAndStations()
} else {
- reloadMap();
+ reloadMap()
}
- if (baseApplication.isLocationUpdates()) {
- registerLocationManager();
+ if (baseApplication!!.isLocationUpdates) {
+ registerLocationManager()
}
- binding.map.stationFilterBar.init(baseApplication, this);
- binding.map.stationFilterBar.setSortOrderEnabled(false);
+ binding!!.map.stationFilterBar.init(baseApplication, this)
+ binding!!.map.stationFilterBar.setSortOrderEnabled(false)
}
- private void createClusterManager() {
+ private fun createClusterManager() {
// create clusterer instance
- clusterer = new ClusterManager<>(
- binding.map.mapView,
- createMarkerBitmaps(),
- (byte) 9,
- this);
+ clusterer = ClusterManager(
+ binding!!.map.mapView,
+ createMarkerBitmaps(), 9.toByte(),
+ this
+ )
// this uses the framebuffer position, the mapview position can be out of sync with
// what the user sees on the screen if an animation is in progress
- this.binding.map.mapView.getModel().frameBufferModel.addObserver(clusterer);
+ binding!!.map.mapView.model.frameBufferModel.addObserver(clusterer)
}
- @Override
- protected void onPause() {
- if (this.layer instanceof TileDownloadLayer) {
- ((TileDownloadLayer) this.layer).onPause();
+ override fun onPause() {
+ if (layer is TileDownloadLayer) {
+ (layer as TileDownloadLayer?)!!.onPause()
}
- unregisterLocationManager();
- var mapPosition = binding.map.mapView.getModel().mapViewPosition.getMapPosition();
- baseApplication.setLastMapPosition(mapPosition);
- destroyClusterManager();
- super.onPause();
+ unregisterLocationManager()
+ val mapPosition = binding!!.map.mapView.model.mapViewPosition.mapPosition
+ baseApplication.setLastMapPosition(mapPosition)
+ destroyClusterManager()
+ super.onPause()
}
- private void destroyClusterManager() {
+ private fun destroyClusterManager() {
if (clusterer != null) {
- clusterer.destroyGeoClusterer();
- this.binding.map.mapView.getModel().frameBufferModel.removeObserver(clusterer);
- clusterer = null;
+ clusterer!!.destroyGeoClusterer()
+ binding!!.map.mapView.model.frameBufferModel.removeObserver(clusterer)
+ clusterer = null
}
}
- @Override
- public void onLocationChanged(Location location) {
- myPos = new LatLong(location.getLatitude(), location.getLongitude());
- updatePosition();
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
-
- }
-
- @Override
- public void onProviderEnabled(@NonNull String provider) {
-
+ override fun onLocationChanged(location: Location) {
+ myPos = LatLong(location.latitude, location.longitude)
+ updatePosition()
}
- @Override
- public void onProviderDisabled(@NonNull String provider) {
-
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
+ override fun onProviderEnabled(provider: String) {}
+ override fun onProviderDisabled(provider: String) {}
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_FINE_LOCATION) {
- Log.i(TAG, "Received response for location permission request.");
+ Log.i(TAG, "Received response for location permission request.")
// Check if the required permission has been granted
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Location permission has been granted
- registerLocationManager();
+ registerLocationManager()
} else {
//Permission not granted
- Toast.makeText(MapsActivity.this, R.string.grant_location_permission, Toast.LENGTH_LONG).show();
+ Toast.makeText(
+ this@MapsActivity,
+ R.string.grant_location_permission,
+ Toast.LENGTH_LONG
+ ).show()
}
}
}
- public void registerLocationManager() {
-
+ fun registerLocationManager() {
try {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
if (!askedForPermission) {
- ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
- askedForPermission = true;
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ REQUEST_FINE_LOCATION
+ )
+ askedForPermission = true
}
- setMyLocSwitch(false);
- return;
+ setMyLocSwitch(false)
+ return
}
-
- locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
+ locationManager =
+ applicationContext.getSystemService(LOCATION_SERVICE) as LocationManager
// getting GPS status
- var isGPSEnabled = locationManager
- .isProviderEnabled(LocationManager.GPS_PROVIDER);
+ val isGPSEnabled = locationManager
+ .isProviderEnabled(LocationManager.GPS_PROVIDER)
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "GPS Enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "GPS Enabled")
if (locationManager != null) {
- var loc = locationManager
- .getLastKnownLocation(LocationManager.GPS_PROVIDER);
- myPos = new LatLong(loc.getLatitude(), loc.getLongitude());
+ val loc = locationManager!!
+ .getLastKnownLocation(LocationManager.GPS_PROVIDER)
+ myPos = LatLong(loc!!.latitude, loc.longitude)
}
} else {
// getting network status
- var isNetworkEnabled = locationManager
- .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ val isNetworkEnabled = locationManager
+ .isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// First get location from Network Provider
if (isNetworkEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "Network Location enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "Network Location enabled")
if (locationManager != null) {
- var loc = locationManager
- .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
- myPos = new LatLong(loc.getLatitude(), loc.getLongitude());
+ val loc = locationManager!!
+ .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
+ myPos = LatLong(loc!!.latitude, loc.longitude)
}
}
}
- setMyLocSwitch(true);
- } catch (Exception e) {
- Log.e(TAG, "Error registering LocationManager", e);
- var b = new Bundle();
- b.putString("error", "Error registering LocationManager: " + e);
- locationManager = null;
- myPos = null;
- setMyLocSwitch(false);
- return;
+ setMyLocSwitch(true)
+ } catch (e: Exception) {
+ Log.e(TAG, "Error registering LocationManager", e)
+ val b = Bundle()
+ b.putString("error", "Error registering LocationManager: $e")
+ locationManager = null
+ myPos = null
+ setMyLocSwitch(false)
+ return
}
- Log.i(TAG, "LocationManager registered");
- updatePosition();
+ Log.i(TAG, "LocationManager registered")
+ updatePosition()
}
- private void unregisterLocationManager() {
+ private fun unregisterLocationManager() {
if (locationManager != null) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
- locationManager.removeUpdates(this);
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ locationManager!!.removeUpdates(this)
}
- locationManager = null;
+ locationManager = null
}
- Log.i(TAG, "LocationManager unregistered");
+ Log.i(TAG, "LocationManager unregistered")
}
- private void updatePosition() {
- if (myLocSwitch != null && myLocSwitch.isChecked()) {
- binding.map.mapView.setCenter(myPos);
- binding.map.mapView.repaint();
+ private fun updatePosition() {
+ if (myLocSwitch != null && myLocSwitch!!.isChecked) {
+ binding!!.map.mapView.setCenter(myPos)
+ binding!!.map.mapView.repaint()
}
}
- protected class BahnhofGeoItem implements GeoItem {
- public Station station;
- public final LatLong latLong;
- public final boolean pendingUpload;
-
- public BahnhofGeoItem(Station station, boolean pendingUpload) {
- this.station = station;
- this.pendingUpload = pendingUpload;
- this.latLong = new LatLong(station.getLat(), station.getLon());
- }
+ protected inner class BahnhofGeoItem(
+ var station: Station?,
+ override val isPendingUpload: Boolean
+ ) : GeoItem {
+ override val latLong: LatLong
- public LatLong getLatLong() {
- return latLong;
+ init {
+ latLong = LatLong(station!!.lat, station!!.lon)
}
- @Override
- public String getTitle() {
- return station.getTitle();
+ override fun getLatLong(): LatLong? {
+ return latLong
}
- @Override
- public boolean hasPhoto() {
- return station.hasPhoto();
- }
-
- @Override
- public boolean ownPhoto() {
- return hasPhoto() && station.getPhotographer().equals(nickname);
- }
+ override val title: String?
+ get() = station!!.title
- @Override
- public boolean stationActive() {
- return station.getActive();
+ override fun hasPhoto(): Boolean {
+ return station!!.hasPhoto()
}
- @Override
- public boolean isPendingUpload() {
- return pendingUpload;
+ override fun ownPhoto(): Boolean {
+ return hasPhoto() && station!!.photographer == nickname
}
- public Station getStation() {
- return station;
+ override fun stationActive(): Boolean {
+ return station!!.active
}
-
}
- private static class MapMenuListener implements MenuItem.OnMenuItemClickListener {
-
- private final WeakReference mapsActivityRef;
-
- private final BaseApplication baseApplication;
-
- private final String map;
+ private class MapMenuListener(
+ mapsActivity: MapsActivity,
+ private val baseApplication: BaseApplication?,
+ private val map: String?
+ ) : MenuItem.OnMenuItemClickListener {
+ private val mapsActivityRef: WeakReference
- private MapMenuListener(MapsActivity mapsActivity, BaseApplication baseApplication, String map) {
- this.mapsActivityRef = new WeakReference<>(mapsActivity);
- this.baseApplication = baseApplication;
- this.map = map;
+ init {
+ mapsActivityRef = WeakReference(mapsActivity)
}
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- item.setChecked(true);
- if (item.getItemId() == R.id.osm_mapnik) { // default Mapnik online tiles
- baseApplication.setMap(null);
+ override fun onMenuItemClick(item: MenuItem): Boolean {
+ item.isChecked = true
+ if (item.itemId == R.id.osm_mapnik) { // default Mapnik online tiles
+ baseApplication.setMap(null)
} else {
- baseApplication.setMap(map);
+ baseApplication.setMap(map)
}
-
- var mapsActivity = mapsActivityRef.get();
- if (mapsActivity != null) {
- mapsActivity.recreate();
- }
- return false;
+ val mapsActivity = mapsActivityRef.get()
+ mapsActivity?.recreate()
+ return false
}
}
- private static class MapThemeMenuListener implements MenuItem.OnMenuItemClickListener {
-
- private final WeakReference mapsActivityRef;
+ private class MapThemeMenuListener(
+ mapsActivity: MapsActivity,
+ private val baseApplication: BaseApplication?,
+ private val mapThemeUri: Uri?
+ ) : MenuItem.OnMenuItemClickListener {
+ private val mapsActivityRef: WeakReference
- private final BaseApplication baseApplication;
-
- private final Uri mapThemeUri;
-
- private MapThemeMenuListener(MapsActivity mapsActivity, BaseApplication baseApplication, Uri mapThemeUri) {
- this.mapsActivityRef = new WeakReference<>(mapsActivity);
- this.baseApplication = baseApplication;
- this.mapThemeUri = mapThemeUri;
+ init {
+ mapsActivityRef = WeakReference(mapsActivity)
}
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- item.setChecked(true);
- if (item.getItemId() == R.id.default_theme) { // default theme
- baseApplication.setMapThemeUri(null);
+ override fun onMenuItemClick(item: MenuItem): Boolean {
+ item.isChecked = true
+ if (item.itemId == R.id.default_theme) { // default theme
+ baseApplication!!.setMapThemeUri(null)
} else {
- baseApplication.setMapThemeUri(mapThemeUri);
- }
-
- var mapsActivity = mapsActivityRef.get();
- if (mapsActivity != null) {
- mapsActivity.recreate();
+ baseApplication!!.setMapThemeUri(mapThemeUri)
}
- return false;
+ val mapsActivity = mapsActivityRef.get()
+ mapsActivity?.recreate()
+ return false
}
}
-}
+ companion object {
+ const val EXTRAS_LATITUDE = "Extras_Latitude"
+ const val EXTRAS_LONGITUDE = "Extras_Longitude"
+ const val EXTRAS_MARKER = "Extras_Marker"
+
+ // The minimum distance to change Updates in meters
+ private const val MIN_DISTANCE_CHANGE_FOR_UPDATES: Long = 1 // meters
+ // The minimum time between updates in milliseconds
+ private const val MIN_TIME_BW_UPDATES: Long = 500 // minute
+ private val TAG = MapsActivity::class.java.simpleName
+ private const val REQUEST_FINE_LOCATION = 1
+ private const val USER_AGENT = "railway-stations.org-android"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MyDataActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MyDataActivity.kt
index bcb89ae4..e014961b 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MyDataActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/MyDataActivity.kt
@@ -1,452 +1,481 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
-import java.util.Objects;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMydataBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ChangePasswordBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.License;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Profile;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Token;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class MyDataActivity extends AppCompatActivity {
-
- private static final String TAG = MyDataActivity.class.getSimpleName();
-
- private License license;
- private BaseApplication baseApplication;
- private RSAPIClient rsapiClient;
- private Profile profile;
- private ActivityMydataBinding binding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ActivityMydataBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
- Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setTitle(R.string.login);
-
- binding.myData.profileForm.setVisibility(View.INVISIBLE);
-
- baseApplication = (BaseApplication) getApplication();
- rsapiClient = baseApplication.getRsapiClient();
-
- setProfileToUI(baseApplication.getProfile());
-
- oauthAuthorizationCallback(getIntent());
- if (isLoginDataAvailable()) {
- loadRemoteProfile();
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.content.DialogInterface
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.util.Patterns
+import android.view.ContextThemeWrapper
+import android.view.View
+import android.widget.EditText
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityMydataBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ChangePasswordBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.License
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Profile
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Token
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import org.apache.commons.lang3.StringUtils
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.io.UnsupportedEncodingException
+import java.net.MalformedURLException
+import java.net.URL
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
+import java.security.NoSuchAlgorithmException
+import java.util.Objects
+
+class MyDataActivity : AppCompatActivity() {
+ private var license: License? = null
+ private var baseApplication: BaseApplication? = null
+ private var rsapiClient: RSAPIClient? = null
+ private var profile: Profile? = null
+ private var binding: ActivityMydataBinding? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMydataBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ Objects.requireNonNull(supportActionBar).setDisplayHomeAsUpEnabled(true)
+ supportActionBar!!.setTitle(R.string.login)
+ binding!!.myData.profileForm.visibility = View.INVISIBLE
+ baseApplication = application as BaseApplication
+ rsapiClient = baseApplication.getRsapiClient()
+ setProfileToUI(baseApplication.getProfile())
+ oauthAuthorizationCallback(intent)
+ if (isLoginDataAvailable) {
+ loadRemoteProfile()
}
}
- private void setProfileToUI(Profile profile) {
- binding.myData.etNickname.setText(profile.getNickname());
- binding.myData.etEmail.setText(profile.getEmail());
- binding.myData.etLinking.setText(profile.getLink());
- license = profile.getLicense();
- binding.myData.cbLicenseCC0.setChecked(license == License.CC0);
- binding.myData.cbOwnPhoto.setChecked(profile.getPhotoOwner());
- binding.myData.cbAnonymous.setChecked(profile.getAnonymous());
- onAnonymousChecked(null);
-
- if (profile.getEmailVerified()) {
- binding.myData.tvEmailVerification.setText(R.string.emailVerified);
- binding.myData.tvEmailVerification.setTextColor(getResources().getColor(R.color.emailVerified, null));
+ private fun setProfileToUI(profile: Profile?) {
+ binding!!.myData.etNickname.setText(profile!!.nickname)
+ binding!!.myData.etEmail.setText(profile.email)
+ binding!!.myData.etLinking.setText(profile.link)
+ license = profile.license
+ binding!!.myData.cbLicenseCC0.isChecked = license === License.CC0
+ binding!!.myData.cbOwnPhoto.isChecked = profile.photoOwner
+ binding!!.myData.cbAnonymous.isChecked = profile.anonymous
+ onAnonymousChecked(null)
+ if (profile.emailVerified) {
+ binding!!.myData.tvEmailVerification.setText(R.string.emailVerified)
+ binding!!.myData.tvEmailVerification.setTextColor(
+ resources.getColor(
+ R.color.emailVerified,
+ null
+ )
+ )
} else {
- binding.myData.tvEmailVerification.setText(R.string.emailUnverified);
- binding.myData.tvEmailVerification.setTextColor(getResources().getColor(R.color.emailUnverified, null));
+ binding!!.myData.tvEmailVerification.setText(R.string.emailUnverified)
+ binding!!.myData.tvEmailVerification.setTextColor(
+ resources.getColor(
+ R.color.emailUnverified,
+ null
+ )
+ )
}
- this.profile = profile;
+ this.profile = profile
}
- private void loadRemoteProfile() {
- binding.myData.loginForm.setVisibility(View.VISIBLE);
- binding.myData.profileForm.setVisibility(View.GONE);
- binding.myData.progressBar.setVisibility(View.VISIBLE);
-
- rsapiClient.getProfile().enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- binding.myData.progressBar.setVisibility(View.GONE);
-
- switch (response.code()) {
- case 200:
- Log.i(TAG, "Successfully loaded profile");
- var remoteProfile = response.body();
+ private fun loadRemoteProfile() {
+ binding!!.myData.loginForm.visibility = View.VISIBLE
+ binding!!.myData.profileForm.visibility = View.GONE
+ binding!!.myData.progressBar.visibility = View.VISIBLE
+ rsapiClient.getProfile().enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ binding!!.myData.progressBar.visibility = View.GONE
+ when (response.code()) {
+ 200 -> {
+ Log.i(TAG, "Successfully loaded profile")
+ val remoteProfile = response.body()
if (remoteProfile != null) {
- saveLocalProfile(remoteProfile);
- showProfileView();
+ saveLocalProfile(remoteProfile)
+ showProfileView()
}
- break;
- case 401:
- logout(null);
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.authorization_failed);
- break;
- default:
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.read_profile_failed, String.valueOf(response.code())));
+ }
+
+ 401 -> {
+ logout(null)
+ confirmOk(this@MyDataActivity, R.string.authorization_failed)
+ }
+
+ else -> confirmOk(
+ this@MyDataActivity,
+ getString(R.string.read_profile_failed, response.code().toString())
+ )
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- binding.myData.progressBar.setVisibility(View.GONE);
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.read_profile_failed, t.getMessage()));
+ override fun onFailure(call: Call, t: Throwable) {
+ binding!!.myData.progressBar.visibility = View.GONE
+ confirmOk(
+ this@MyDataActivity,
+ getString(R.string.read_profile_failed, t.message)
+ )
}
- });
+ })
}
- private void showProfileView() {
- binding.myData.loginForm.setVisibility(View.GONE);
- binding.myData.profileForm.setVisibility(View.VISIBLE);
- Objects.requireNonNull(getSupportActionBar()).setTitle(R.string.tvProfile);
- binding.myData.btProfileSave.setText(R.string.bt_mydata_commit);
- binding.myData.btLogout.setVisibility(View.VISIBLE);
- binding.myData.btChangePassword.setVisibility(View.VISIBLE);
+ private fun showProfileView() {
+ binding!!.myData.loginForm.visibility = View.GONE
+ binding!!.myData.profileForm.visibility = View.VISIBLE
+ Objects.requireNonNull(supportActionBar).setTitle(R.string.tvProfile)
+ binding!!.myData.btProfileSave.setText(R.string.bt_mydata_commit)
+ binding!!.myData.btLogout.visibility = View.VISIBLE
+ binding!!.myData.btChangePassword.visibility = View.VISIBLE
}
- private void oauthAuthorizationCallback(Intent intent) {
- if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
- var data = intent.getData();
+ private fun oauthAuthorizationCallback(intent: Intent?) {
+ if (intent != null && Intent.ACTION_VIEW == intent.action) {
+ val data = intent.data
if (data != null) {
- if (data.toString().startsWith(baseApplication.getRsapiClient().getRedirectUri())) {
- var code = data.getQueryParameter("code");
+ if (data.toString().startsWith(baseApplication.getRsapiClient().redirectUri)) {
+ val code = data.getQueryParameter("code")
if (code != null) {
- baseApplication.getRsapiClient().requestAccessToken(code).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- var token = response.body();
- Log.d(TAG, String.valueOf(token));
- if (token != null) {
- baseApplication.setAccessToken(token.getAccessToken());
- baseApplication.getRsapiClient().setToken(token);
- loadRemoteProfile();
- } else {
- Toast.makeText(MyDataActivity.this, getString(R.string.authorization_error, "no token"), Toast.LENGTH_LONG).show();
+ baseApplication.getRsapiClient().requestAccessToken(code)
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ val token = response.body()
+ Log.d(TAG, token.toString())
+ if (token != null) {
+ baseApplication.setAccessToken(token.accessToken)
+ baseApplication.getRsapiClient().setToken(token)
+ loadRemoteProfile()
+ } else {
+ Toast.makeText(
+ this@MyDataActivity,
+ getString(R.string.authorization_error, "no token"),
+ Toast.LENGTH_LONG
+ ).show()
+ }
}
- }
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Toast.makeText(MyDataActivity.this, getString(R.string.authorization_error, t.getMessage()), Toast.LENGTH_LONG).show();
- }
- });
+ override fun onFailure(call: Call, t: Throwable) {
+ Toast.makeText(
+ this@MyDataActivity,
+ getString(R.string.authorization_error, t.message),
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ })
} else {
- String error = data.getQueryParameter("error");
+ val error = data.getQueryParameter("error")
if (error != null) {
- Toast.makeText(this, getString(R.string.authorization_error, error), Toast.LENGTH_LONG).show();
+ Toast.makeText(
+ this,
+ getString(R.string.authorization_error, error),
+ Toast.LENGTH_LONG
+ ).show()
}
}
-
- if (isLoginDataAvailable()) {
- loadRemoteProfile();
+ if (isLoginDataAvailable) {
+ loadRemoteProfile()
}
}
}
}
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- oauthAuthorizationCallback(intent);
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ oauthAuthorizationCallback(intent)
}
- public void selectLicense(View view) {
- license = binding.myData.cbLicenseCC0.isChecked() ? License.CC0 : License.UNKNOWN;
- if (license != License.CC0) {
- SimpleDialogs.confirmOk(this, R.string.cc0_needed);
+ fun selectLicense(view: View?) {
+ license = if (binding!!.myData.cbLicenseCC0.isChecked) License.CC0 else License.UNKNOWN
+ if (license !== License.CC0) {
+ confirmOk(this, R.string.cc0_needed)
}
}
- public void save(View view) {
- profile = createProfileFromUI();
+ fun save(view: View?) {
+ profile = createProfileFromUI()
if (!isValid(profile)) {
- return;
+ return
}
- if (rsapiClient.hasToken()) {
- binding.myData.progressBar.setVisibility(View.VISIBLE);
-
- rsapiClient.saveProfile(profile).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- binding.myData.progressBar.setVisibility(View.GONE);
-
- switch (response.code()) {
- case 200:
- Log.i(TAG, "Successfully saved profile");
- break;
- case 202:
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.password_email);
- break;
- case 400:
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.profile_wrong_data);
- break;
- case 401:
- logout(view);
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.authorization_failed);
- break;
- case 409:
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.profile_conflict);
- break;
- default:
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.save_profile_failed, String.valueOf(response.code())));
+ if (rsapiClient!!.hasToken()) {
+ binding!!.myData.progressBar.visibility = View.VISIBLE
+ rsapiClient!!.saveProfile(profile)!!.enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ binding!!.myData.progressBar.visibility = View.GONE
+ when (response.code()) {
+ 200 -> Log.i(TAG, "Successfully saved profile")
+ 202 -> confirmOk(this@MyDataActivity, R.string.password_email)
+ 400 -> confirmOk(this@MyDataActivity, R.string.profile_wrong_data)
+ 401 -> {
+ logout(view)
+ confirmOk(this@MyDataActivity, R.string.authorization_failed)
+ }
+
+ 409 -> confirmOk(this@MyDataActivity, R.string.profile_conflict)
+ else -> confirmOk(
+ this@MyDataActivity,
+ getString(R.string.save_profile_failed, response.code().toString())
+ )
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- binding.myData.progressBar.setVisibility(View.GONE);
- Log.e(TAG, "Error uploading profile", t);
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.save_profile_failed, t.getMessage()));
+ override fun onFailure(call: Call, t: Throwable) {
+ binding!!.myData.progressBar.visibility = View.GONE
+ Log.e(TAG, "Error uploading profile", t)
+ confirmOk(
+ this@MyDataActivity,
+ getString(R.string.save_profile_failed, t.message)
+ )
}
- });
+ })
}
-
- saveLocalProfile(profile);
- Toast.makeText(this, R.string.preferences_saved, Toast.LENGTH_LONG).show();
+ saveLocalProfile(profile)
+ Toast.makeText(this, R.string.preferences_saved, Toast.LENGTH_LONG).show()
}
- private Profile createProfileFromUI() {
- var newProfile = new Profile(
- binding.myData.etNickname.getText().toString().trim(),
- license,
- binding.myData.cbOwnPhoto.isChecked(),
- binding.myData.cbAnonymous.isChecked(),
- binding.myData.etLinking.getText().toString().trim(),
- binding.myData.etEmail.getText().toString().trim()
- );
-
- if (this.profile != null) {
- newProfile.setEmailVerified(this.profile.getEmailVerified());
+ private fun createProfileFromUI(): Profile {
+ val newProfile = Profile(
+ binding!!.myData.etNickname.text.toString().trim { it <= ' ' },
+ license,
+ binding!!.myData.cbOwnPhoto.isChecked,
+ binding!!.myData.cbAnonymous.isChecked,
+ binding!!.myData.etLinking.text.toString().trim { it <= ' ' },
+ binding!!.myData.etEmail.text.toString().trim { it <= ' ' }
+ )
+ if (profile != null) {
+ newProfile.emailVerified = profile!!.emailVerified
}
-
- return newProfile;
+ return newProfile
}
- private void saveLocalProfile(Profile profile) {
- baseApplication.setProfile(profile);
- setProfileToUI(profile);
+ private fun saveLocalProfile(profile: Profile?) {
+ baseApplication.setProfile(profile)
+ setProfileToUI(profile)
}
- private boolean isLoginDataAvailable() {
- return baseApplication.getAccessToken() != null;
- }
+ private val isLoginDataAvailable: Boolean
+ private get() = baseApplication.getAccessToken() != null
- @Override
- public void onBackPressed() {
- startActivity(new Intent(this, MainActivity.class));
- finish();
+ override fun onBackPressed() {
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
}
- public boolean isValid(Profile profile) {
- if (StringUtils.isBlank(profile.getNickname())) {
- SimpleDialogs.confirmOk(this, R.string.missing_nickname);
- return false;
+ fun isValid(profile: Profile?): Boolean {
+ if (StringUtils.isBlank(profile!!.nickname)) {
+ confirmOk(this, R.string.missing_nickname)
+ return false
}
- if (!isValidEmail(profile.getEmail())) {
- SimpleDialogs.confirmOk(this, R.string.missing_email_address);
- return false;
+ if (!isValidEmail(profile.email)) {
+ confirmOk(this, R.string.missing_email_address)
+ return false
}
- String url = profile.getLink();
+ val url = profile.link
if (StringUtils.isNotBlank(url) && !isValidHTTPURL(url)) {
- SimpleDialogs.confirmOk(this, R.string.missing_link);
- return false;
+ confirmOk(this, R.string.missing_link)
+ return false
}
-
- return true;
+ return true
}
- private boolean isValidHTTPURL(String urlString) {
+ private fun isValidHTTPURL(urlString: String?): Boolean {
try {
- var url = new URL(urlString);
- if (!"http".equals(url.getProtocol()) && !"https".equals(url.getProtocol())) {
- return false;
+ val url = URL(urlString)
+ if ("http" != url.protocol && "https" != url.protocol) {
+ return false
}
- } catch (MalformedURLException e) {
- return false;
+ } catch (e: MalformedURLException) {
+ return false
}
- return true;
+ return true
}
- public boolean isValidEmail(CharSequence target) {
- return target != null && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
-
+ fun isValidEmail(target: CharSequence?): Boolean {
+ return target != null && Patterns.EMAIL_ADDRESS.matcher(target).matches()
}
- public void onAnonymousChecked(View view) {
- if (binding.myData.cbAnonymous.isChecked()) {
- binding.myData.etLinking.setVisibility(View.GONE);
- binding.myData.tvLinking.setVisibility(View.GONE);
+ fun onAnonymousChecked(view: View?) {
+ if (binding!!.myData.cbAnonymous.isChecked) {
+ binding!!.myData.etLinking.visibility = View.GONE
+ binding!!.myData.tvLinking.visibility = View.GONE
} else {
- binding.myData.etLinking.setVisibility(View.VISIBLE);
- binding.myData.tvLinking.setVisibility(View.VISIBLE);
+ binding!!.myData.etLinking.visibility = View.VISIBLE
+ binding!!.myData.tvLinking.visibility = View.VISIBLE
}
}
- public void login(View view) throws NoSuchAlgorithmException {
- Intent intent = new Intent(
- Intent.ACTION_VIEW,
- rsapiClient.createAuthorizeUri());
- startActivity(intent);
- finish();
+ @Throws(NoSuchAlgorithmException::class)
+ fun login(view: View?) {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ rsapiClient!!.createAuthorizeUri()
+ )
+ startActivity(intent)
+ finish()
}
- public void logout(View view) {
- baseApplication.setAccessToken(null);
- rsapiClient.clearToken();
- profile = new Profile();
- saveLocalProfile(profile);
- binding.myData.profileForm.setVisibility(View.GONE);
- binding.myData.loginForm.setVisibility(View.VISIBLE);
- Objects.requireNonNull(getSupportActionBar()).setTitle(R.string.login);
+ fun logout(view: View?) {
+ baseApplication.setAccessToken(null)
+ rsapiClient!!.clearToken()
+ profile = Profile()
+ saveLocalProfile(profile)
+ binding!!.myData.profileForm.visibility = View.GONE
+ binding!!.myData.loginForm.visibility = View.VISIBLE
+ Objects.requireNonNull(supportActionBar).setTitle(R.string.login)
}
- public void deleteAccount(View view) {
- SimpleDialogs.confirmOkCancel(this, R.string.deleteAccountConfirmation, (d, i) -> rsapiClient.deleteAccount().enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- switch (response.code()) {
- case 204:
- Log.i(TAG, "Successfully deleted account");
- logout(view);
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.account_deleted);
- break;
- case 401:
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.authorization_failed);
- logout(view);
- break;
- default:
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.account_deletion_failed, String.valueOf(response.code())));
- }
- }
+ fun deleteAccount(view: View?) {
+ SimpleDialogs.confirmOkCancel(
+ this,
+ R.string.deleteAccountConfirmation
+ ) { d: DialogInterface?, i: Int ->
+ rsapiClient!!.deleteAccount()!!
+ .enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ when (response.code()) {
+ 204 -> {
+ Log.i(TAG, "Successfully deleted account")
+ logout(view)
+ confirmOk(this@MyDataActivity, R.string.account_deleted)
+ }
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error deleting account", t);
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.account_deletion_failed, t.getMessage()));
- }
- }));
- }
+ 401 -> {
+ confirmOk(this@MyDataActivity, R.string.authorization_failed)
+ logout(view)
+ }
- public void changePassword(View view) {
- var builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom));
- var passwordBinding = ChangePasswordBinding.inflate(getLayoutInflater());
+ else -> confirmOk(
+ this@MyDataActivity,
+ getString(
+ R.string.account_deletion_failed,
+ response.code().toString()
+ )
+ )
+ }
+ }
- builder.setTitle(R.string.bt_change_password)
- .setView(passwordBinding.getRoot())
- .setIcon(R.mipmap.ic_launcher)
- .setPositiveButton(android.R.string.ok, null)
- .setNegativeButton(android.R.string.cancel, (dialog, id) -> dialog.cancel());
-
- var alertDialog = builder.create();
- alertDialog.show();
-
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
- String newPassword = getValidPassword(passwordBinding.password, passwordBinding.passwordRepeat);
- if (newPassword == null) {
- return;
- }
- alertDialog.dismiss();
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error deleting account", t)
+ confirmOk(
+ this@MyDataActivity,
+ getString(R.string.account_deletion_failed, t.message)
+ )
+ }
+ })
+ }
+ }
+ fun changePassword(view: View?) {
+ val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.AlertDialogCustom))
+ val passwordBinding = ChangePasswordBinding.inflate(
+ layoutInflater
+ )
+ builder.setTitle(R.string.bt_change_password)
+ .setView(passwordBinding.root)
+ .setIcon(R.mipmap.ic_launcher)
+ .setPositiveButton(android.R.string.ok, null)
+ .setNegativeButton(android.R.string.cancel) { dialog: DialogInterface, id: Int -> dialog.cancel() }
+ val alertDialog = builder.create()
+ alertDialog.show()
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { v: View? ->
+ var newPassword: String? =
+ getValidPassword(passwordBinding.password, passwordBinding.passwordRepeat)
+ ?: return@setOnClickListener
+ alertDialog.dismiss()
try {
- newPassword = URLEncoder.encode(newPassword, String.valueOf(StandardCharsets.UTF_8));
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, "Error encoding new password", e);
+ newPassword = URLEncoder.encode(newPassword, StandardCharsets.UTF_8.toString())
+ } catch (e: UnsupportedEncodingException) {
+ Log.e(TAG, "Error encoding new password", e)
}
+ rsapiClient!!.changePassword(newPassword)!!.enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ when (response.code()) {
+ 200 -> {
+ Log.i(TAG, "Successfully changed password")
+ logout(view)
+ confirmOk(this@MyDataActivity, R.string.password_changed)
+ }
+
+ 401 -> {
+ confirmOk(this@MyDataActivity, R.string.authorization_failed)
+ logout(view)
+ }
- rsapiClient.changePassword(newPassword).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- switch (response.code()) {
- case 200:
- Log.i(TAG, "Successfully changed password");
- logout(view);
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.password_changed);
- break;
- case 401:
- SimpleDialogs.confirmOk(MyDataActivity.this, R.string.authorization_failed);
- logout(view);
- break;
- default:
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.change_password_failed, String.valueOf(response.code())));
+ else -> confirmOk(
+ this@MyDataActivity,
+ getString(R.string.change_password_failed, response.code().toString())
+ )
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error changing password", t);
- SimpleDialogs.confirmOk(MyDataActivity.this,
- getString(R.string.change_password_failed, t.getMessage()));
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error changing password", t)
+ confirmOk(
+ this@MyDataActivity,
+ getString(R.string.change_password_failed, t.message)
+ )
}
- });
- });
-
+ })
+ }
}
- private String getValidPassword(EditText etNewPassword, EditText etPasswordRepeat) {
- var newPassword = etNewPassword.getText().toString().trim();
-
- if (newPassword.length() < 8) {
- Toast.makeText(MyDataActivity.this, R.string.password_too_short, Toast.LENGTH_LONG).show();
- return null;
+ private fun getValidPassword(etNewPassword: EditText, etPasswordRepeat: EditText): String? {
+ val newPassword = etNewPassword.text.toString().trim { it <= ' ' }
+ if (newPassword.length < 8) {
+ Toast.makeText(this@MyDataActivity, R.string.password_too_short, Toast.LENGTH_LONG)
+ .show()
+ return null
}
- if (!newPassword.equals(etPasswordRepeat.getText().toString().trim())) {
- Toast.makeText(MyDataActivity.this, R.string.password_repeat_fail, Toast.LENGTH_LONG).show();
- return null;
+ if (newPassword != etPasswordRepeat.text.toString().trim { it <= ' ' }) {
+ Toast.makeText(this@MyDataActivity, R.string.password_repeat_fail, Toast.LENGTH_LONG)
+ .show()
+ return null
}
- return newPassword;
+ return newPassword
}
- public void requestEmailVerification(View view) {
- SimpleDialogs.confirmOkCancel(this, R.string.requestEmailVerification, (dialogInterface, i) -> rsapiClient.resendEmailVerification().enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- if (response.code() == 200) {
- Log.i(TAG, "Successfully requested email verification");
- Toast.makeText(MyDataActivity.this, R.string.emailVerificationRequested, Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(MyDataActivity.this, R.string.emailVerificationRequestFailed, Toast.LENGTH_LONG).show();
- }
- }
+ fun requestEmailVerification(view: View?) {
+ SimpleDialogs.confirmOkCancel(
+ this,
+ R.string.requestEmailVerification
+ ) { dialogInterface: DialogInterface?, i: Int ->
+ rsapiClient!!.resendEmailVerification()!!
+ .enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ if (response.code() == 200) {
+ Log.i(TAG, "Successfully requested email verification")
+ Toast.makeText(
+ this@MyDataActivity,
+ R.string.emailVerificationRequested,
+ Toast.LENGTH_LONG
+ ).show()
+ } else {
+ Toast.makeText(
+ this@MyDataActivity,
+ R.string.emailVerificationRequestFailed,
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error requesting email verification", t);
- Toast.makeText(MyDataActivity.this, R.string.emailVerificationRequestFailed, Toast.LENGTH_LONG).show();
- }
- }));
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error requesting email verification", t)
+ Toast.makeText(
+ this@MyDataActivity,
+ R.string.emailVerificationRequestFailed,
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ })
+ }
}
-}
+ companion object {
+ private val TAG = MyDataActivity::class.java.simpleName
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/NearbyNotificationService.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/NearbyNotificationService.kt
index f6555c92..409a4b1a 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/NearbyNotificationService.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/NearbyNotificationService.kt
@@ -1,193 +1,152 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import static android.app.PendingIntent.FLAG_IMMUTABLE;
-
-import android.Manifest;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationManagerCompat;
-import androidx.core.content.ContextCompat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.notification.NearbyBahnhofNotificationManager;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.notification.NearbyBahnhofNotificationManagerFactory;
-
-public class NearbyNotificationService extends Service implements LocationListener {
-
- // The minimum distance to change Updates in meters
- private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1000; // 1km
-
- // The minimum time between updates in milliseconds
- private static final long MIN_TIME_BW_UPDATES = 10000; // 10 seconds
-
- private static final double MIN_NOTIFICATION_DISTANCE = 1.0d; // km
- private static final double EARTH_CIRCUMFERENCE = 40075.017d; // km at equator
- private static final int ONGOING_NOTIFICATION_ID = 0xdeadbeef;
-
- private final String TAG = NearbyNotificationService.class.getSimpleName();
- private List nearStations;
- private Location myPos = new Location((String)null);
-
- private LocationManager locationManager;
-
- private NearbyBahnhofNotificationManager notifiedStationManager;
- private BaseApplication baseApplication = null;
- private DbAdapter dbAdapter = null;
-
- /**
- * The intent action to use to bind to this service's status interface.
- */
- public static final String STATUS_INTERFACE = NearbyNotificationService.class.getPackage().getName() + ".Status";
-
- public NearbyNotificationService() {
- }
-
- @Override
- public void onCreate() {
- Log.i(TAG, "About to create");
- super.onCreate();
- myPos.setLatitude(50d);
- myPos.setLongitude(8d);
- nearStations = new ArrayList<>(0); // no markers until we know where we are
- notifiedStationManager = null;
- baseApplication = (BaseApplication)getApplication();
- dbAdapter = baseApplication.getDbAdapter();
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.Manifest
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+import androidx.core.app.ActivityCompat
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.ContextCompat
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.notification.NearbyBahnhofNotificationManager
+import de.bahnhoefe.deutschlands.bahnhofsfotos.notification.NearbyBahnhofNotificationManagerFactory
+import kotlin.math.abs
+import kotlin.math.cos
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+class NearbyNotificationService : Service(), LocationListener {
+ private val TAG = NearbyNotificationService::class.java.simpleName
+ private var nearStations = listOf()
+ private var myPos: Location? = Location(null as String?)
+ private var locationManager: LocationManager? = null
+ private var notifiedStationManager: NearbyBahnhofNotificationManager? = null
+ private lateinit var baseApplication: BaseApplication
+ private lateinit var dbAdapter: DbAdapter
+ override fun onCreate() {
+ super.onCreate()
+ myPos!!.latitude = 50.0
+ myPos!!.longitude = 8.0
+ notifiedStationManager = null
+ baseApplication = application as BaseApplication
+ dbAdapter = baseApplication.dbAdapter
}
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- cancelNotification();
-
- Log.i(TAG, "Received start command");
-
- var resultIntent = new Intent(this, MainActivity.class);
- var resultPendingIntent =
- PendingIntent.getActivity(
- this,
- 0,
- resultIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE
- );
-
- NearbyBahnhofNotificationManager.createChannel(this);
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ cancelNotification()
+ Log.i(TAG, "Received start command")
+ val resultIntent = Intent(this, MainActivity::class.java)
+ val resultPendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ resultIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ NearbyBahnhofNotificationManager.Companion.createChannel(this)
// show a permanent notification to indicate that position detection is running
- var ongoingNotification = new NotificationCompat.Builder(this, NearbyBahnhofNotificationManager.CHANNEL_ID)
+ val ongoingNotification: Notification =
+ NotificationCompat.Builder(this, NearbyBahnhofNotificationManager.Companion.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.nearby_notification_active))
.setOngoing(true)
.setLocalOnly(true)
.setContentIntent(resultPendingIntent)
- .build();
- var notificationManager = NotificationManagerCompat.from(this);
- notificationManager.notify(ONGOING_NOTIFICATION_ID, ongoingNotification);
-
- registerLocationManager();
-
- return START_STICKY;
+ .build()
+ val notificationManager = NotificationManagerCompat.from(this)
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return START_STICKY
+ }
+ notificationManager.notify(ONGOING_NOTIFICATION_ID, ongoingNotification)
+ registerLocationManager()
+ return START_STICKY
}
- @Override
- public void onLowMemory() {
+ override fun onLowMemory() {
// stop tracking
- super.onLowMemory();
- stopSelf();
+ super.onLowMemory()
+ stopSelf()
}
- @Override
- public void onDestroy() {
- Log.i(TAG, "Service gets destroyed");
+ override fun onDestroy() {
+ Log.i(TAG, "Service gets destroyed")
try {
- cancelNotification();
- unregisterLocationManager();
- } catch (Throwable t) {
- Log.wtf(TAG, "Unknown problem when trying to de-register from GPS updates", t);
+ cancelNotification()
+ unregisterLocationManager()
+ } catch (t: Throwable) {
+ Log.wtf(TAG, "Unknown problem when trying to de-register from GPS updates", t)
}
// Cancel the ongoing notification
- var notificationManager =
- NotificationManagerCompat.from(this);
- notificationManager.cancel(ONGOING_NOTIFICATION_ID);
-
- super.onDestroy();
+ val notificationManager = NotificationManagerCompat.from(this)
+ notificationManager.cancel(ONGOING_NOTIFICATION_ID)
+ super.onDestroy()
}
- private void cancelNotification() {
+ private fun cancelNotification() {
if (notifiedStationManager != null) {
- notifiedStationManager.destroy();
- notifiedStationManager = null;
+ notifiedStationManager!!.destroy()
+ notifiedStationManager = null
}
}
- @Override
- public void onLocationChanged(@NonNull Location location) {
- Log.i(TAG, "Received new location: " + location);
+ override fun onLocationChanged(location: Location) {
+ Log.i(TAG, "Received new location: $location")
try {
- myPos = location;
+ myPos = location
// check if currently advertised station is still in range
if (notifiedStationManager != null) {
- if (calcDistance(notifiedStationManager.getStation()) > MIN_NOTIFICATION_DISTANCE) {
- cancelNotification();
+ if (calcDistance(notifiedStationManager!!.station) > MIN_NOTIFICATION_DISTANCE) {
+ cancelNotification()
}
}
- Log.d(TAG, "Reading matching stations from local database");
- readStations();
+ Log.d(TAG, "Reading matching stations from local database")
+ readStations()
// check if a user notification is appropriate
- checkNearestStation();
- } catch (Throwable t) {
- Log.e(TAG, "Unknown Problem arised during location change handling", t);
+ checkNearestStation()
+ } catch (t: Throwable) {
+ Log.e(TAG, "Unknown Problem arised during location change handling", t)
}
}
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
-
- }
-
- @Override
- public void onProviderEnabled(@NonNull String provider) {
-
- }
-
- @Override
- public void onProviderDisabled(@NonNull String provider) {
-
+ @Deprecated("Deprecated in Java")
+ override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
}
- private void checkNearestStation() {
- double minDist = 3e3;
- Station nearest = null;
- for (var station : nearStations) {
- var dist = calcDistance(station);
+ override fun onProviderEnabled(provider: String) {}
+ override fun onProviderDisabled(provider: String) {}
+ private fun checkNearestStation() {
+ var minDist = 3e3
+ var nearest: Station? = null
+ for (station in nearStations) {
+ val dist = calcDistance(station)
if (dist < minDist) {
- nearest = station;
- minDist = dist;
+ nearest = station
+ minDist = dist
}
}
if (nearest != null && minDist < MIN_NOTIFICATION_DISTANCE) {
- notifyNearest(nearest, minDist);
- Log.i(TAG, "Issued notification to user");
+ notifyNearest(nearest, minDist)
+ Log.i(TAG, "Issued notification to user")
} else {
- Log.d(TAG, "No notification - nearest station was " + minDist + " km away: " + nearest);
+ Log.d(TAG, "No notification - nearest station was $minDist km away: $nearest")
}
}
@@ -199,17 +158,22 @@ public class NearbyNotificationService extends Service implements LocationListen
* @param nearest the station nearest to the current position
* @param distance the distance of the station to the current position
*/
- private void notifyNearest(Station nearest, double distance) {
+ private fun notifyNearest(nearest: Station, distance: Double) {
if (notifiedStationManager != null) {
- if (notifiedStationManager.getStation().equals(nearest)) {
- return; // Notification für diesen Bahnhof schon angezeigt
+ notifiedStationManager = if (nearest == notifiedStationManager!!.station) {
+ return // Notification für diesen Bahnhof schon angezeigt
} else {
- notifiedStationManager.destroy();
- notifiedStationManager = null;
+ notifiedStationManager!!.destroy()
+ null
}
}
- notifiedStationManager = NearbyBahnhofNotificationManagerFactory.create(this, nearest, distance, dbAdapter.fetchCountriesWithProviderApps(baseApplication.getCountryCodes()));
- notifiedStationManager.notifyUser();
+ notifiedStationManager = NearbyBahnhofNotificationManagerFactory.create(
+ this,
+ nearest,
+ distance,
+ dbAdapter.fetchCountriesWithProviderApps(baseApplication.countryCodes)
+ )
+ notifiedStationManager!!.notifyUser()
}
/**
@@ -218,78 +182,96 @@ public class NearbyNotificationService extends Service implements LocationListen
* @param station the station to calculate the distance to
* @return the distance
*/
- private double calcDistance(Station station) {
+ private fun calcDistance(station: Station): Double {
// Wir nähern für glatte Oberflächen, denn wir sind an Abständen kleiner 1km interessiert
- var lateralDiff = myPos.getLatitude() - station.getLat();
- var longDiff = (Math.abs(myPos.getLatitude()) < 89.99d) ?
- (myPos.getLongitude() - station.getLon()) * Math.cos(myPos.getLatitude() / 180 * Math.PI) :
- 0.0d; // at the poles, longitude doesn't matter
+ val lateralDiff = myPos!!.latitude - station.lat
+ val longDiff =
+ if (abs(myPos!!.latitude) < 89.99) (myPos!!.longitude - station.lon) * cos(
+ myPos!!.latitude / 180 * Math.PI
+ ) else 0.0 // at the poles, longitude doesn't matter
// simple Pythagoras now.
- return Math.sqrt(Math.pow(lateralDiff, 2.0d) + Math.pow(longDiff, 2.0d)) * EARTH_CIRCUMFERENCE / 360.0d;
+ return sqrt(
+ lateralDiff.pow(2.0) + longDiff.pow(2.0)
+ ) * EARTH_CIRCUMFERENCE / 360.0
}
- public void registerLocationManager() {
-
+ private fun registerLocationManager() {
try {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "No Location Permission");
- return;
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ Log.w(TAG, "No Location Permission")
+ return
}
-
- locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
+ locationManager =
+ applicationContext.getSystemService(LOCATION_SERVICE) as LocationManager
// getting GPS status
- var isGPSEnabled = locationManager
- .isProviderEnabled(LocationManager.GPS_PROVIDER);
+ val isGPSEnabled = locationManager!!
+ .isProviderEnabled(LocationManager.GPS_PROVIDER)
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "GPS Enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "GPS Enabled")
if (locationManager != null) {
- myPos = locationManager
- .getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ myPos = locationManager!!
+ .getLastKnownLocation(LocationManager.GPS_PROVIDER)
}
} else {
// getting network status
- var isNetworkEnabled = locationManager
- .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ val isNetworkEnabled = locationManager!!
+ .isProviderEnabled(LocationManager.NETWORK_PROVIDER)
// First get location from Network Provider
if (isNetworkEnabled) {
- locationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER,
- MIN_TIME_BW_UPDATES,
- MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
- Log.d(TAG, "Network Location enabled");
+ locationManager!!.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER,
+ MIN_TIME_BW_UPDATES,
+ MIN_DISTANCE_CHANGE_FOR_UPDATES.toFloat(), this
+ )
+ Log.d(TAG, "Network Location enabled")
if (locationManager != null) {
- myPos = locationManager
- .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+ myPos = locationManager!!
+ .getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
}
}
}
- } catch (Exception e) {
- Log.e(TAG, "Error registering LocationManager", e);
- var b = new Bundle();
- b.putString("error", "Error registering LocationManager: " + e);
- locationManager = null;
- myPos = null;
- return;
+ } catch (e: Exception) {
+ Log.e(TAG, "Error registering LocationManager", e)
+ val b = Bundle()
+ b.putString("error", "Error registering LocationManager: $e")
+ locationManager = null
+ myPos = null
+ return
}
- Log.i(TAG, "LocationManager registered");
+ Log.i(TAG, "LocationManager registered")
}
- private void unregisterLocationManager() {
+ private fun unregisterLocationManager() {
if (locationManager != null) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
- locationManager.removeUpdates(this);
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ locationManager!!.removeUpdates(this)
}
- locationManager = null;
+ locationManager = null
}
- Log.i(TAG, "LocationManager unregistered");
+ Log.i(TAG, "LocationManager unregistered")
}
/**
@@ -297,34 +279,52 @@ public class NearbyNotificationService extends Service implements LocationListen
* Currently, can only be used to query the service state, i.e. if the location tracking
* is switched off or on with photo or on without photo.
*/
- public static class StatusBinder extends Binder {
- }
+ class StatusBinder : Binder()
/**
* Bind to interfaces provided by this service. Currently implemented:
- *
- * - STATUS_INTERFACE: Returns a StatusBinder that can be used to query the tracking status
- *
+ *
+ * * STATUS_INTERFACE: Returns a StatusBinder that can be used to query the tracking status
+ *
*
* @param intent an Intent giving the intended action
* @return a Binder instance suitable for the intent supplied, or null if none matches.
*/
- @Override
- public IBinder onBind(Intent intent) {
- if (STATUS_INTERFACE.equals(intent.getAction())) {
- return new StatusBinder();
+ override fun onBind(intent: Intent): IBinder? {
+ return if (STATUS_INTERFACE == intent.action) {
+ StatusBinder()
} else {
- return null;
+ null
}
}
- private void readStations() {
+ private fun readStations() {
try {
- Log.i(TAG, "Lade nahegelegene Bahnhoefe");
- nearStations = dbAdapter.getStationByLatLngRectangle(myPos.getLatitude(), myPos.getLongitude(), baseApplication.getStationFilter());
- } catch (Exception e) {
- Log.e(TAG, "Datenbank konnte nicht geöffnet werden", e);
+ Log.i(TAG, "Lade nahegelegene Bahnhoefe")
+ nearStations = dbAdapter.getStationByLatLngRectangle(
+ myPos!!.latitude,
+ myPos!!.longitude,
+ baseApplication.stationFilter
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "Datenbank konnte nicht geöffnet werden", e)
}
}
-}
+ companion object {
+ // The minimum distance to change Updates in meters
+ private const val MIN_DISTANCE_CHANGE_FOR_UPDATES: Long = 1000 // 1km
+
+ // The minimum time between updates in milliseconds
+ private const val MIN_TIME_BW_UPDATES: Long = 10000 // 10 seconds
+ private const val MIN_NOTIFICATION_DISTANCE = 1.0 // km
+ private const val EARTH_CIRCUMFERENCE = 40075.017 // km at equator
+ private const val ONGOING_NOTIFICATION_ID = -0x21524111
+
+ /**
+ * The intent action to use to bind to this service's status interface.
+ */
+ val STATUS_INTERFACE =
+ (NearbyNotificationService::class.java.getPackage()?.name ?: "") + ".Status"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/OutboxActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/OutboxActivity.kt
index f68efc0b..1fa5b22e 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/OutboxActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/OutboxActivity.kt
@@ -1,151 +1,156 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import static java.util.stream.Collectors.toList;
-
-import android.app.AlertDialog;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-
-import java.util.List;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityOutboxBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.db.OutboxAdapter;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class OutboxActivity extends AppCompatActivity {
-
- private static final String TAG = OutboxActivity.class.getSimpleName();
-
- private OutboxAdapter adapter;
- private DbAdapter dbAdapter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- var baseApplication = (BaseApplication) getApplication();
- dbAdapter = baseApplication.getDbAdapter();
-
- var binding = ActivityOutboxBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- adapter = new OutboxAdapter(OutboxActivity.this, dbAdapter.getOutbox());
- binding.lstUploads.setAdapter(adapter);
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.app.AlertDialog
+import android.content.DialogInterface
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.ContextThemeWrapper
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemClickListener
+import android.widget.AdapterView.OnItemLongClickListener
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityOutboxBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.DbAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.db.OutboxAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.util.stream.Collectors
+
+class OutboxActivity : AppCompatActivity() {
+ private var adapter: OutboxAdapter? = null
+ private var dbAdapter: DbAdapter? = null
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val baseApplication = application as BaseApplication
+ dbAdapter = baseApplication.dbAdapter
+ val binding = ActivityOutboxBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding.root)
+ adapter = OutboxAdapter(this@OutboxActivity, dbAdapter.getOutbox())
+ binding.lstUploads.adapter = adapter
// item click
- binding.lstUploads.setOnItemClickListener((parent, view, position, id) -> {
- var upload = dbAdapter.getUploadById(id);
- Intent intent;
- if (upload.isProblemReport()) {
- intent = new Intent(OutboxActivity.this, ProblemReportActivity.class);
- intent.putExtra(ProblemReportActivity.EXTRA_UPLOAD, upload);
- } else {
- intent = new Intent(OutboxActivity.this, UploadActivity.class);
- intent.putExtra(UploadActivity.EXTRA_UPLOAD, upload);
- }
- startActivity(intent);
- });
-
- binding.lstUploads.setOnItemLongClickListener((parent, view, position, id) -> {
- var uploadId = String.valueOf(id);
- SimpleDialogs.confirmOkCancel(OutboxActivity.this, getResources().getString(R.string.delete_upload, uploadId), (dialog, which) -> {
- dbAdapter.deleteUpload(id);
- FileUtils.deleteQuietly(FileUtils.getStoredMediaFile(this, id));
- adapter.changeCursor(dbAdapter.getOutbox());
- });
- return true;
- });
-
- var query = dbAdapter.getPendingUploads(true).stream()
- .map(upload -> new InboxStateQuery(upload.getRemoteId()))
- .collect(toList());
-
- baseApplication.getRsapiClient().queryUploadState(query).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call> call, @NonNull Response> response) {
- if (response.isSuccessful()) {
- var stateQueries = response.body();
- if (stateQueries != null) {
- dbAdapter.updateUploadStates(stateQueries);
- adapter.changeCursor(dbAdapter.getOutbox());
- }
- } else if (response.code() == 401) {
- baseApplication.setAccessToken(null);
- baseApplication.getRsapiClient().clearToken();
- Toast.makeText(OutboxActivity.this, R.string.authorization_failed, Toast.LENGTH_LONG).show();
- startActivity(new Intent(OutboxActivity.this, MyDataActivity.class));
- finish();
+ binding.lstUploads.onItemClickListener =
+ OnItemClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
+ val upload = dbAdapter!!.getUploadById(id)
+ val intent: Intent
+ if (upload!!.isProblemReport) {
+ intent = Intent(this@OutboxActivity, ProblemReportActivity::class.java)
+ intent.putExtra(ProblemReportActivity.Companion.EXTRA_UPLOAD, upload)
} else {
- Log.w(TAG, "Upload states not processable");
+ intent = Intent(this@OutboxActivity, UploadActivity::class.java)
+ intent.putExtra(UploadActivity.Companion.EXTRA_UPLOAD, upload)
+ }
+ startActivity(intent)
+ }
+ binding.lstUploads.onItemLongClickListener =
+ OnItemLongClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
+ val uploadId = id.toString()
+ SimpleDialogs.confirmOkCancel(
+ this@OutboxActivity,
+ resources.getString(R.string.delete_upload, uploadId)
+ ) { dialog: DialogInterface?, which: Int ->
+ dbAdapter!!.deleteUpload(id)
+ FileUtils.deleteQuietly(FileUtils.getStoredMediaFile(this, id))
+ adapter!!.changeCursor(dbAdapter.getOutbox())
}
+ true
}
+ val query = dbAdapter!!.getPendingUploads(true).stream()
+ .map { upload: Upload? ->
+ InboxStateQuery(
+ upload!!.remoteId
+ )
+ }
+ .collect(Collectors.toList())
+ baseApplication.rsapiClient.queryUploadState(query)
+ .enqueue(object : Callback?> {
+ override fun onResponse(
+ call: Call?>,
+ response: Response?>
+ ) {
+ if (response.isSuccessful) {
+ val stateQueries = response.body()
+ if (stateQueries != null) {
+ dbAdapter!!.updateUploadStates(stateQueries)
+ adapter!!.changeCursor(dbAdapter.getOutbox())
+ }
+ } else if (response.code() == 401) {
+ baseApplication.accessToken = null
+ baseApplication.rsapiClient.clearToken()
+ Toast.makeText(
+ this@OutboxActivity,
+ R.string.authorization_failed,
+ Toast.LENGTH_LONG
+ ).show()
+ startActivity(Intent(this@OutboxActivity, MyDataActivity::class.java))
+ finish()
+ } else {
+ Log.w(TAG, "Upload states not processable")
+ }
+ }
- @Override
- public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
- Log.e(TAG, "Error retrieving upload state", t);
- Toast.makeText(OutboxActivity.this,
+ override fun onFailure(call: Call?>, t: Throwable) {
+ Log.e(TAG, "Error retrieving upload state", t)
+ Toast.makeText(
+ this@OutboxActivity,
R.string.error_retrieving_upload_state,
- Toast.LENGTH_LONG).show();
- }
- });
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ })
}
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- menu.clear();
- getMenuInflater().inflate(R.menu.outbox, menu);
- return super.onPrepareOptionsMenu(menu);
+ override fun onPrepareOptionsMenu(menu: Menu): Boolean {
+ menu.clear()
+ menuInflater.inflate(R.menu.outbox, menu)
+ return super.onPrepareOptionsMenu(menu)
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.nav_delete_processed_uploads) {
- deleteCompletedUploads();
- return true;
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == R.id.nav_delete_processed_uploads) {
+ deleteCompletedUploads()
+ return true
}
- return super.onOptionsItemSelected(item);
+ return super.onOptionsItemSelected(item)
}
- private void deleteCompletedUploads() {
- var uploads = dbAdapter.getCompletedUploads();
- if (uploads.isEmpty()) {
- return;
+ private fun deleteCompletedUploads() {
+ val uploads = dbAdapter.getCompletedUploads()
+ if (uploads!!.isEmpty()) {
+ return
}
-
- new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom))
- .setIcon(R.mipmap.ic_launcher)
- .setTitle(R.string.confirm_delete_processed_uploads)
- .setPositiveButton(R.string.button_ok_text, (dialog, which) -> {
- for (Upload upload : uploads) {
- dbAdapter.deleteUpload(upload.getId());
- FileUtils.deleteQuietly(FileUtils.getStoredMediaFile(this, upload.getId()));
- }
- adapter.changeCursor(dbAdapter.getOutbox());
- })
- .setNegativeButton(R.string.button_cancel_text, null)
- .create().show();
+ AlertDialog.Builder(ContextThemeWrapper(this, R.style.AlertDialogCustom))
+ .setIcon(R.mipmap.ic_launcher)
+ .setTitle(R.string.confirm_delete_processed_uploads)
+ .setPositiveButton(R.string.button_ok_text) { dialog: DialogInterface?, which: Int ->
+ for (upload in uploads) {
+ dbAdapter!!.deleteUpload(upload!!.id!!)
+ FileUtils.deleteQuietly(FileUtils.getStoredMediaFile(this, upload!!.id))
+ }
+ adapter!!.changeCursor(dbAdapter.getOutbox())
+ }
+ .setNegativeButton(R.string.button_cancel_text, null)
+ .create().show()
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- adapter.changeCursor(dbAdapter.getOutbox());
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ adapter!!.changeCursor(dbAdapter.getOutbox())
}
+ companion object {
+ private val TAG = OutboxActivity::class.java.simpleName
+ }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/PhotoPagerAdapter.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/PhotoPagerAdapter.kt
index 2e3cb7fa..d76c3dd5 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/PhotoPagerAdapter.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/PhotoPagerAdapter.kt
@@ -1,70 +1,49 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.github.chrisbanes.photoview.PhotoView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PageablePhoto;
-
-public class PhotoPagerAdapter extends RecyclerView.Adapter {
-
- private final List pageablePhotos = new ArrayList<>();
-
- private final Context context;
-
- public PhotoPagerAdapter(Context context) {
- this.context = context;
- }
-
- public int addPageablePhoto(PageablePhoto pageablePhoto) {
- pageablePhotos.add(pageablePhoto);
- notifyDataSetChanged();
- return pageablePhotos.size() - 1;
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.github.chrisbanes.photoview.PhotoView
+import de.bahnhoefe.deutschlands.bahnhofsfotos.PhotoPagerAdapter.PhotoViewHolder
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PageablePhoto
+
+class PhotoPagerAdapter(private val context: Context) : RecyclerView.Adapter() {
+ private val pageablePhotos: MutableList = ArrayList()
+ fun addPageablePhoto(pageablePhoto: PageablePhoto): Int {
+ pageablePhotos.add(pageablePhoto)
+ notifyDataSetChanged()
+ return pageablePhotos.size - 1
}
- @NonNull
- @Override
- public PhotoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- var view = LayoutInflater.from(context).inflate(R.layout.photo_view_item, parent, false);
- return new PhotoViewHolder(view);
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoViewHolder {
+ val view = LayoutInflater.from(context).inflate(R.layout.photo_view_item, parent, false)
+ return PhotoViewHolder(view)
}
- @Override
- public void onBindViewHolder(@NonNull PhotoViewHolder holder, int position) {
- var pageablePhoto = getPageablePhotoAtPosition(position);
+ override fun onBindViewHolder(holder: PhotoViewHolder, position: Int) {
+ val pageablePhoto = getPageablePhotoAtPosition(position)
if (pageablePhoto == null) {
- holder.photoView.setImageResource(R.drawable.photo_missing);
+ holder.photoView.setImageResource(R.drawable.photo_missing)
} else {
- holder.photoView.setImageBitmap(pageablePhoto.getBitmap());
+ holder.photoView.setImageBitmap(pageablePhoto.bitmap)
}
}
- public PageablePhoto getPageablePhotoAtPosition(int position) {
- return pageablePhotos.isEmpty() ? null : pageablePhotos.get(position);
+ fun getPageablePhotoAtPosition(position: Int): PageablePhoto? {
+ return if (pageablePhotos.isEmpty()) null else pageablePhotos[position]
}
- @Override
- public int getItemCount() {
- return pageablePhotos.isEmpty() ? 1 : pageablePhotos.size();
+ override fun getItemCount(): Int {
+ return if (pageablePhotos.isEmpty()) 1 else pageablePhotos.size
}
- public static class PhotoViewHolder extends RecyclerView.ViewHolder {
-
- PhotoView photoView;
+ class PhotoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var photoView: PhotoView
- public PhotoViewHolder(@NonNull View itemView) {
- super(itemView);
- photoView = itemView.findViewById(R.id.photoView);
+ init {
+ photoView = itemView.findViewById(R.id.photoView)
}
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ProblemReportActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ProblemReportActivity.kt
index 369193f3..05dd2f8e 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ProblemReportActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ProblemReportActivity.kt
@@ -1,321 +1,334 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.app.TaskStackBuilder;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.NavUtils;
-
-import com.google.gson.Gson;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ReportProblemBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxResponse;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemReport;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemType;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class ProblemReportActivity extends AppCompatActivity {
-
- private static final String TAG = ProblemReportActivity.class.getSimpleName();
-
- public static final String EXTRA_UPLOAD = "EXTRA_UPLOAD";
- public static final String EXTRA_STATION = "EXTRA_STATION";
- public static final String EXTRA_PHOTO_ID = "EXTRA_PHOTO_ID";
-
- private BaseApplication baseApplication;
- private RSAPIClient rsapiClient;
- private ReportProblemBinding binding;
-
- private Upload upload;
- private Station station;
- private Long photoId;
- private final ArrayList problemTypes = new ArrayList<>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ReportProblemBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- baseApplication = (BaseApplication) getApplication();
- rsapiClient = baseApplication.getRsapiClient();
-
- Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
-
- problemTypes.add(getString(R.string.problem_please_specify));
- for (var type : ProblemType.values()) {
- problemTypes.add(getString(type.getMessageId()));
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.app.TaskStackBuilder
+import android.content.DialogInterface
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.EditText
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.NavUtils
+import com.google.gson.Gson
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ReportProblemBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxResponse
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemReport
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemType
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import org.apache.commons.lang3.StringUtils
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.util.Objects
+
+class ProblemReportActivity : AppCompatActivity() {
+ private var baseApplication: BaseApplication? = null
+ private var rsapiClient: RSAPIClient? = null
+ private var binding: ReportProblemBinding? = null
+ private var upload: Upload? = null
+ private var station: Station? = null
+ private var photoId: Long? = null
+ private val problemTypes = ArrayList()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ReportProblemBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ baseApplication = application as BaseApplication
+ rsapiClient = baseApplication.getRsapiClient()
+ Objects.requireNonNull(supportActionBar).setDisplayHomeAsUpEnabled(true)
+ problemTypes.add(getString(R.string.problem_please_specify))
+ for (type in ProblemType.values()) {
+ problemTypes.add(getString(type.messageId))
}
- var adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, problemTypes);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- binding.problemType.setAdapter(adapter);
-
- binding.problemType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(final AdapterView> parent, final View view, final int position, final long id) {
+ val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, problemTypes)
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ binding!!.problemType.adapter = adapter
+ binding!!.problemType.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>?,
+ view: View,
+ position: Int,
+ id: Long
+ ) {
if (position > 0) {
- var type = ProblemType.values()[position - 1];
- setCoordsVisible(type == ProblemType.WRONG_LOCATION);
- setTitleVisible(type == ProblemType.WRONG_NAME);
+ val type = ProblemType.values()[position - 1]
+ setCoordsVisible(type === ProblemType.WRONG_LOCATION)
+ setTitleVisible(type === ProblemType.WRONG_NAME)
} else {
- setCoordsVisible(false);
- setTitleVisible(false);
+ setCoordsVisible(false)
+ setTitleVisible(false)
}
}
- @Override
- public void onNothingSelected(final AdapterView> parent) {
- setCoordsVisible(false);
- setTitleVisible(false);
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ setCoordsVisible(false)
+ setTitleVisible(false)
}
- });
-
- if (!baseApplication.isLoggedIn()) {
- Toast.makeText(this, R.string.please_login, Toast.LENGTH_LONG).show();
- startActivity(new Intent(ProblemReportActivity.this, MyDataActivity.class));
- finish();
- return;
}
-
- if (!baseApplication.getProfile().getEmailVerified()) {
- SimpleDialogs.confirmOk(this, R.string.email_unverified_for_problem_report, (dialog, view) -> {
- startActivity(new Intent(ProblemReportActivity.this, MyDataActivity.class));
- finish();
- });
- return;
+ if (!baseApplication!!.isLoggedIn) {
+ Toast.makeText(this, R.string.please_login, Toast.LENGTH_LONG).show()
+ startActivity(Intent(this@ProblemReportActivity, MyDataActivity::class.java))
+ finish()
+ return
}
-
- onNewIntent(getIntent());
+ if (!baseApplication.getProfile().emailVerified) {
+ SimpleDialogs.confirmOk(
+ this,
+ R.string.email_unverified_for_problem_report
+ ) { dialog: DialogInterface?, view: Int ->
+ startActivity(Intent(this@ProblemReportActivity, MyDataActivity::class.java))
+ finish()
+ }
+ return
+ }
+ onNewIntent(intent)
}
- private void setCoordsVisible(boolean visible) {
- binding.tvNewCoords.setVisibility(visible ? View.VISIBLE : View.GONE);
- binding.etNewLatitude.setVisibility(visible ? View.VISIBLE : View.GONE);
- binding.etNewLongitude.setVisibility(visible ? View.VISIBLE : View.GONE);
+ private fun setCoordsVisible(visible: Boolean) {
+ binding!!.tvNewCoords.visibility = if (visible) View.VISIBLE else View.GONE
+ binding!!.etNewLatitude.visibility = if (visible) View.VISIBLE else View.GONE
+ binding!!.etNewLongitude.visibility = if (visible) View.VISIBLE else View.GONE
}
- private void setTitleVisible(boolean visible) {
- binding.tvNewTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
- binding.etNewTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
+ private fun setTitleVisible(visible: Boolean) {
+ binding!!.tvNewTitle.visibility = if (visible) View.VISIBLE else View.GONE
+ binding!!.etNewTitle.visibility = if (visible) View.VISIBLE else View.GONE
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
if (intent != null) {
- upload = (Upload) intent.getSerializableExtra(EXTRA_UPLOAD);
- station = (Station) intent.getSerializableExtra(EXTRA_STATION);
- photoId = (Long) intent.getSerializableExtra(EXTRA_PHOTO_ID);
-
- if (upload != null && upload.isProblemReport()) {
- binding.etProblemComment.setText(upload.getComment());
- binding.etNewLatitude.setText(upload.getLat() != null ? upload.getLat().toString() : "");
- binding.etNewLongitude.setText(upload.getLon() != null ? upload.getLon().toString() : "");
-
- int selected = upload.getProblemType().ordinal() + 1;
- binding.problemType.setSelection(selected);
-
+ upload = intent.getSerializableExtra(EXTRA_UPLOAD) as Upload?
+ station = intent.getSerializableExtra(EXTRA_STATION) as Station?
+ photoId = intent.getSerializableExtra(EXTRA_PHOTO_ID) as Long?
+ if (upload != null && upload!!.isProblemReport) {
+ binding!!.etProblemComment.setText(upload!!.comment)
+ binding!!.etNewLatitude.setText(if (upload!!.lat != null) upload!!.lat.toString() else "")
+ binding!!.etNewLongitude.setText(if (upload!!.lon != null) upload!!.lon.toString() else "")
+ val selected = upload!!.problemType!!.ordinal + 1
+ binding!!.problemType.setSelection(selected)
if (station == null) {
- station = baseApplication.getDbAdapter().getStationForUpload(upload);
+ station = baseApplication.getDbAdapter().getStationForUpload(upload)
}
-
- fetchUploadStatus(upload);
+ fetchUploadStatus(upload)
}
-
if (station != null) {
- binding.tvStationTitle.setText(station.getTitle());
- binding.etNewTitle.setText(station.getTitle());
- binding.etNewLatitude.setText(String.valueOf(station.getLat()));
- binding.etNewLongitude.setText(String.valueOf(station.getLon()));
+ binding!!.tvStationTitle.text = station!!.title
+ binding!!.etNewTitle.setText(station!!.title)
+ binding!!.etNewLatitude.setText(station!!.lat.toString())
+ binding!!.etNewLongitude.setText(station!!.lon.toString())
}
}
}
- public void reportProblem(View view) {
- int selectedType = binding.problemType.getSelectedItemPosition();
+ fun reportProblem(view: View?) {
+ val selectedType = binding!!.problemType.selectedItemPosition
if (selectedType == 0) {
- Toast.makeText(getApplicationContext(), getString(R.string.problem_please_specify), Toast.LENGTH_LONG).show();
- return;
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.problem_please_specify),
+ Toast.LENGTH_LONG
+ ).show()
+ return
}
- var type = ProblemType.values()[selectedType - 1];
- var comment = binding.etProblemComment.getText().toString();
+ val type = ProblemType.values()[selectedType - 1]
+ val comment = binding!!.etProblemComment.text.toString()
if (StringUtils.isBlank(comment)) {
- Toast.makeText(getApplicationContext(), getString(R.string.problem_please_comment), Toast.LENGTH_LONG).show();
- return;
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.problem_please_comment),
+ Toast.LENGTH_LONG
+ ).show()
+ return
}
-
- Double lat = null;
- Double lon = null;
- if (binding.etNewLatitude.getVisibility() == View.VISIBLE) {
- lat = parseDouble(binding.etNewLatitude);
+ var lat: Double? = null
+ var lon: Double? = null
+ if (binding!!.etNewLatitude.visibility == View.VISIBLE) {
+ lat = parseDouble(binding!!.etNewLatitude)
}
- if (binding.etNewLongitude.getVisibility() == View.VISIBLE) {
- lon = parseDouble(binding.etNewLongitude);
+ if (binding!!.etNewLongitude.visibility == View.VISIBLE) {
+ lon = parseDouble(binding!!.etNewLongitude)
}
- if (type == ProblemType.WRONG_LOCATION && (lat == null || lon == null)) {
- Toast.makeText(getApplicationContext(), getString(R.string.problem_wrong_lat_lon), Toast.LENGTH_LONG).show();
- return;
+ if (type === ProblemType.WRONG_LOCATION && (lat == null || lon == null)) {
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.problem_wrong_lat_lon),
+ Toast.LENGTH_LONG
+ ).show()
+ return
}
- var title = binding.etNewTitle.getText().toString();
- if (type == ProblemType.WRONG_NAME && (StringUtils.isBlank(title) || Objects.equals(station.getTitle(), title))) {
- Toast.makeText(getApplicationContext(), getString(R.string.problem_please_provide_corrected_title), Toast.LENGTH_LONG).show();
- return;
+ val title = binding!!.etNewTitle.text.toString()
+ if (type === ProblemType.WRONG_NAME && (StringUtils.isBlank(title) || station!!.title == title)) {
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.problem_please_provide_corrected_title),
+ Toast.LENGTH_LONG
+ ).show()
+ return
}
-
- upload = new Upload(
- null,
- station.getCountry(),
- station.getId(),
- null,
- title,
- lat,
- lon,
- comment,
- null,
- type
- );
-
- upload = baseApplication.getDbAdapter().insertUpload(upload);
-
- var problemReport = new ProblemReport(
- station.getCountry(),
- station.getId(),
- comment,
- type,
- photoId,
- lat,
- lon,
- title);
-
- SimpleDialogs.confirmOkCancel(ProblemReportActivity.this, R.string.send_problem_report,
- (dialog, which) -> rsapiClient.reportProblem(problemReport).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- InboxResponse inboxResponse;
- if (response.isSuccessful()) {
- inboxResponse = response.body();
+ upload = Upload(
+ null,
+ station!!.country,
+ station!!.id,
+ null,
+ title,
+ lat,
+ lon,
+ comment,
+ null,
+ type
+ )
+ upload = baseApplication.getDbAdapter().insertUpload(upload)
+ val problemReport = ProblemReport(
+ station!!.country,
+ station!!.id,
+ comment,
+ type,
+ photoId,
+ lat,
+ lon,
+ title
+ )
+ SimpleDialogs.confirmOkCancel(
+ this@ProblemReportActivity, R.string.send_problem_report
+ ) { dialog: DialogInterface?, which: Int ->
+ rsapiClient!!.reportProblem(problemReport)!!
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ val inboxResponse: InboxResponse?
+ inboxResponse = if (response.isSuccessful) {
+ response.body()
} else if (response.code() == 401) {
- onUnauthorized();
- return;
+ onUnauthorized()
+ return@confirmOkCancel
} else {
- inboxResponse = new Gson().fromJson(response.errorBody().charStream(), InboxResponse.class);
+ Gson().fromJson(
+ response.errorBody()!!.charStream(),
+ InboxResponse::class.java
+ )
}
-
- upload.setRemoteId(inboxResponse.getId());
- upload.setUploadState(inboxResponse.getState().getUploadState());
- baseApplication.getDbAdapter().updateUpload(upload);
- if (inboxResponse.getState() == InboxResponse.InboxResponseState.ERROR) {
- SimpleDialogs.confirmOk(ProblemReportActivity.this,
- getString(InboxResponse.InboxResponseState.ERROR.getMessageId(), inboxResponse.getMessage()));
+ upload!!.remoteId = inboxResponse!!.id
+ upload!!.uploadState = inboxResponse.state.uploadState
+ baseApplication.getDbAdapter().updateUpload(upload)
+ if (inboxResponse.state === InboxResponse.InboxResponseState.ERROR) {
+ confirmOk(
+ this@ProblemReportActivity,
+ getString(
+ InboxResponse.InboxResponseState.ERROR.messageId,
+ inboxResponse.message
+ )
+ )
} else {
- SimpleDialogs.confirmOk(ProblemReportActivity.this, inboxResponse.getState().getMessageId());
+ confirmOk(this@ProblemReportActivity, inboxResponse.state.messageId)
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error reporting problem", t);
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error reporting problem", t)
}
- }));
+ })
+ }
}
- private void onUnauthorized() {
- baseApplication.setAccessToken(null);
- rsapiClient.clearToken();
- Toast.makeText(ProblemReportActivity.this, R.string.authorization_failed, Toast.LENGTH_LONG).show();
- startActivity(new Intent(ProblemReportActivity.this, MyDataActivity.class));
- finish();
+ private fun onUnauthorized() {
+ baseApplication.setAccessToken(null)
+ rsapiClient!!.clearToken()
+ Toast.makeText(this@ProblemReportActivity, R.string.authorization_failed, Toast.LENGTH_LONG)
+ .show()
+ startActivity(Intent(this@ProblemReportActivity, MyDataActivity::class.java))
+ finish()
}
- private Double parseDouble(final EditText editText) {
+ private fun parseDouble(editText: EditText): Double? {
try {
- return Double.parseDouble(String.valueOf(editText.getText()));
- } catch (Exception e) {
- Log.e(TAG, "error parsing double " + editText.getText(), e);
+ return editText.text.toString().toDouble()
+ } catch (e: Exception) {
+ Log.e(TAG, "error parsing double " + editText.text, e)
}
- return null;
+ return null
}
- private void fetchUploadStatus(Upload upload) {
- if (upload == null || upload.getRemoteId() == null) {
- return;
+ private fun fetchUploadStatus(upload: Upload?) {
+ if (upload == null || upload.remoteId == null) {
+ return
}
-
- var stateQuery = new InboxStateQuery(
- upload.getRemoteId(),
- upload.getCountry(),
- upload.getStationId());
-
- rsapiClient.queryUploadState(List.of(stateQuery)).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call> call, @NonNull Response> response) {
- if (response.isSuccessful()) {
- var stateQueries = response.body();
- if (stateQueries != null && !stateQueries.isEmpty()) {
- var stateQuery = stateQueries.get(0);
- binding.uploadStatus.setText(getString(R.string.upload_state, getString(stateQuery.getState().getTextId())));
- binding.uploadStatus.setTextColor(getResources().getColor(stateQuery.getState().getColorId(), null));
- upload.setUploadState(stateQuery.getState());
- upload.setRejectReason(stateQuery.getRejectedReason());
- upload.setCrc32(stateQuery.getCrc32());
- upload.setRemoteId(stateQuery.getId());
- baseApplication.getDbAdapter().updateUpload(upload);
+ val stateQuery = InboxStateQuery(
+ upload.remoteId,
+ upload.country,
+ upload.stationId
+ )
+ rsapiClient!!.queryUploadState(java.util.List.of(stateQuery))!!
+ .enqueue(object : Callback?> {
+ override fun onResponse(
+ call: Call?>,
+ response: Response?>
+ ) {
+ if (response.isSuccessful) {
+ val stateQueries = response.body()
+ if (stateQueries != null && !stateQueries.isEmpty()) {
+ val stateQuery = stateQueries[0]
+ binding!!.uploadStatus.text =
+ getString(R.string.upload_state, getString(stateQuery.state.textId))
+ binding!!.uploadStatus.setTextColor(
+ resources.getColor(
+ stateQuery.state.colorId,
+ null
+ )
+ )
+ upload.uploadState = stateQuery.state
+ upload.rejectReason = stateQuery.rejectedReason
+ upload.crc32 = stateQuery.crc32
+ upload.remoteId = stateQuery.id
+ baseApplication.getDbAdapter().updateUpload(upload)
+ }
+ } else if (response.code() == 401) {
+ onUnauthorized()
+ } else {
+ Log.w(TAG, "Upload states not processable")
}
- } else if (response.code() == 401) {
- onUnauthorized();
- } else {
- Log.w(TAG, "Upload states not processable");
}
- }
-
- @Override
- public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
- Log.e(TAG, "Error retrieving upload state", t);
- }
- });
+ override fun onFailure(call: Call?>, t: Throwable) {
+ Log.e(TAG, "Error retrieving upload state", t)
+ }
+ })
}
- @Override
- public void onBackPressed() {
- navigateUp();
+ override fun onBackPressed() {
+ navigateUp()
}
- public void navigateUp() {
- var callingActivity = getCallingActivity(); // if MapsActivity was calling, then we don't want to rebuild the Backstack
+ fun navigateUp() {
+ val callingActivity =
+ callingActivity // if MapsActivity was calling, then we don't want to rebuild the Backstack
if (callingActivity == null) {
- var upIntent = NavUtils.getParentActivityIntent(this);
- assert upIntent != null;
- upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
- Log.v(TAG, "Recreate back stack");
- TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
+ val upIntent = NavUtils.getParentActivityIntent(this)!!
+ upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot) {
+ Log.v(TAG, "Recreate back stack")
+ TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
+ .startActivities()
}
}
-
- finish();
+ finish()
}
-}
+ companion object {
+ private val TAG = ProblemReportActivity::class.java.simpleName
+ const val EXTRA_UPLOAD = "EXTRA_UPLOAD"
+ const val EXTRA_STATION = "EXTRA_STATION"
+ const val EXTRA_PHOTO_ID = "EXTRA_PHOTO_ID"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ShowErrorActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ShowErrorActivity.kt
index 9f688109..d87f14f6 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ShowErrorActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/ShowErrorActivity.kt
@@ -1,85 +1,80 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityShowErrorBinding;
-
-public class ShowErrorActivity extends AppCompatActivity {
-
- public static final String EXTRA_ERROR_TEXT = "error";
-
- private ActivityShowErrorBinding binding;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- binding = ActivityShowErrorBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- binding.textViewError.setText(getIntent().getStringExtra(EXTRA_ERROR_TEXT));
-
- setSupportActionBar(binding.mapsToolbar);
- if (getSupportActionBar() != null) {
- getSupportActionBar().setTitle(createErrorTitle());
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityShowErrorBinding
+import java.io.UnsupportedEncodingException
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
+
+class ShowErrorActivity : AppCompatActivity() {
+ private var binding: ActivityShowErrorBinding? = null
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityShowErrorBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ binding!!.textViewError.text = intent.getStringExtra(EXTRA_ERROR_TEXT)
+ setSupportActionBar(binding!!.mapsToolbar)
+ if (supportActionBar != null) {
+ supportActionBar!!.title = createErrorTitle()
}
}
- private String createErrorTitle() {
- return String.format(getString(R.string.error_crash_title), getString(R.string.app_name));
+ private fun createErrorTitle(): String {
+ return String.format(getString(R.string.error_crash_title), getString(R.string.app_name))
}
- private void reportBug() {
- Uri uriUrl;
- try {
- uriUrl = Uri.parse(
- String.format(
- getString(R.string.report_issue_link),
- URLEncoder.encode(binding.textViewError.getText().toString(), StandardCharsets.UTF_8.toString())
+ private fun reportBug() {
+ val uriUrl: Uri
+ uriUrl = try {
+ Uri.parse(
+ String.format(
+ getString(R.string.report_issue_link),
+ URLEncoder.encode(
+ binding!!.textViewError.text.toString(),
+ StandardCharsets.UTF_8.toString()
)
- );
- } catch (UnsupportedEncodingException ignored) {
+ )
+ )
+ } catch (ignored: UnsupportedEncodingException) {
// can't happen as UTF-8 is always available
- return;
+ return
}
- var intent = new Intent(Intent.ACTION_VIEW, uriUrl);
- startActivity(intent);
+ val intent = Intent(Intent.ACTION_VIEW, uriUrl)
+ startActivity(intent)
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.show_error, menu);
- return super.onCreateOptionsMenu(menu);
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.show_error, menu)
+ return super.onCreateOptionsMenu(menu)
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.error_share) {
- onClickedShare();
- return true;
- } else if (item.getItemId() == R.id.error_report) {
- reportBug();
- return true;
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == R.id.error_share) {
+ onClickedShare()
+ return true
+ } else if (item.itemId == R.id.error_report) {
+ reportBug()
+ return true
}
- return super.onOptionsItemSelected(item);
+ return super.onOptionsItemSelected(item)
}
- private void onClickedShare() {
- var intent = new Intent(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_SUBJECT, createErrorTitle());
- intent.putExtra(Intent.EXTRA_TEXT, binding.textViewError.getText());
- intent.setType("text/plain");
- startActivity(intent);
+ private fun onClickedShare() {
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.putExtra(Intent.EXTRA_SUBJECT, createErrorTitle())
+ intent.putExtra(Intent.EXTRA_TEXT, binding!!.textViewError.text)
+ intent.type = "text/plain"
+ startActivity(intent)
}
-}
+ companion object {
+ const val EXTRA_ERROR_TEXT = "error"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/UploadActivity.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/UploadActivity.kt
index 442f30db..30cf80fa 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/UploadActivity.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/UploadActivity.kt
@@ -1,343 +1,347 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos;
-
-import static android.content.Intent.createChooser;
-
-import android.app.Activity;
-import android.app.TaskStackBuilder;
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.provider.MediaStore;
-import android.text.Html;
-import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Toast;
-
-import androidx.activity.OnBackPressedCallback;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ActivityCompat;
-import androidx.core.app.NavUtils;
-import androidx.core.content.FileProvider;
-
-import com.google.gson.Gson;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLConnection;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.zip.CRC32;
-import java.util.zip.CheckedInputStream;
-import java.util.zip.CheckedOutputStream;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityUploadBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxResponse;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.KeyValueSpinnerItem;
-import okhttp3.MediaType;
-import okhttp3.RequestBody;
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class UploadActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
-
- private static final String TAG = UploadActivity.class.getSimpleName();
-
- // Names of Extras that this class reacts to
- public static final String EXTRA_UPLOAD = "EXTRA_UPLOAD";
- public static final String EXTRA_STATION = "EXTRA_STATION";
- public static final String EXTRA_LATITUDE = "EXTRA_LATITUDE";
- public static final String EXTRA_LONGITUDE = "EXTRA_LONGITUDE";
-
- private BaseApplication baseApplication;
- private RSAPIClient rsapiClient;
-
- private ActivityUploadBinding binding;
-
- private Upload upload;
- private Station station;
- private List countries;
- private Double latitude;
- private Double longitude;
- private String bahnhofId;
- private Long crc32 = null;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- binding = ActivityUploadBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- baseApplication = (BaseApplication) getApplication();
- rsapiClient = baseApplication.getRsapiClient();
- countries = new ArrayList<>(baseApplication.getDbAdapter().getAllCountries());
-
- Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
-
- if (!baseApplication.isLoggedIn()) {
- Toast.makeText(this, R.string.please_login, Toast.LENGTH_LONG).show();
- startActivity(new Intent(this, MyDataActivity.class));
- finish();
- return;
+package de.bahnhoefe.deutschlands.bahnhofsfotos
+
+import android.app.TaskStackBuilder
+import android.content.ActivityNotFoundException
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.net.Uri
+import android.os.Bundle
+import android.provider.MediaStore
+import android.text.Html
+import android.text.TextUtils
+import android.text.method.LinkMovementMethod
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.Toast
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.OnBackPressedDispatcher.addCallback
+import androidx.activity.result.ActivityResult
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback
+import androidx.core.app.NavUtils
+import androidx.core.content.FileProvider
+import com.google.gson.Gson
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ActivityUploadBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.dialogs.SimpleDialogs
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country.Companion.getCountryByCode
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxResponse
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.rsapi.RSAPIClient
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.FileUtils
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.KeyValueSpinnerItem
+import okhttp3.RequestBody
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.UnsupportedEncodingException
+import java.net.URLConnection
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
+import java.util.Objects
+import java.util.zip.CRC32
+import java.util.zip.CheckedInputStream
+import java.util.zip.CheckedOutputStream
+
+class UploadActivity : AppCompatActivity(), OnRequestPermissionsResultCallback {
+ private var baseApplication: BaseApplication? = null
+ private var rsapiClient: RSAPIClient? = null
+ private var binding: ActivityUploadBinding? = null
+ private var upload: Upload? = null
+ private var station: Station? = null
+ private var countries: List? = null
+ private var latitude: Double? = null
+ private var longitude: Double? = null
+ private var bahnhofId: String? = null
+ private var crc32: Long? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityUploadBinding.inflate(
+ layoutInflater
+ )
+ setContentView(binding!!.root)
+ baseApplication = application as BaseApplication
+ rsapiClient = baseApplication.getRsapiClient()
+ countries = ArrayList(baseApplication.getDbAdapter().allCountries)
+ Objects.requireNonNull(supportActionBar).setDisplayHomeAsUpEnabled(true)
+ if (!baseApplication!!.isLoggedIn) {
+ Toast.makeText(this, R.string.please_login, Toast.LENGTH_LONG).show()
+ startActivity(Intent(this, MyDataActivity::class.java))
+ finish()
+ return
}
-
if (!baseApplication.getProfile().isAllowedToUploadPhoto()) {
- SimpleDialogs.confirmOk(this, R.string.no_photo_upload_allowed, (dialog, which) -> {
- startActivity(new Intent(this, MyDataActivity.class));
- finish();
- });
- return;
+ SimpleDialogs.confirmOk(
+ this,
+ R.string.no_photo_upload_allowed
+ ) { dialog: DialogInterface?, which: Int ->
+ startActivity(Intent(this, MyDataActivity::class.java))
+ finish()
+ }
+ return
}
-
- getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
- @Override
- public void handleOnBackPressed() {
- navigateUp();
+ getOnBackPressedDispatcher().addCallback(this, object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ navigateUp()
}
- });
-
- onNewIntent(getIntent());
+ })
+ onNewIntent(intent)
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
if (intent != null) {
- upload = (Upload) intent.getSerializableExtra(EXTRA_UPLOAD);
- station = (Station) intent.getSerializableExtra(EXTRA_STATION);
- latitude = (Double) intent.getSerializableExtra(EXTRA_LATITUDE);
- longitude = (Double) intent.getSerializableExtra(EXTRA_LONGITUDE);
-
- if (station == null && upload != null && upload.isUploadForExistingStation()) {
- station = baseApplication.getDbAdapter().getStationForUpload(upload);
+ upload = intent.getSerializableExtra(EXTRA_UPLOAD) as Upload?
+ station = intent.getSerializableExtra(EXTRA_STATION) as Station?
+ latitude = intent.getSerializableExtra(EXTRA_LATITUDE) as Double?
+ longitude = intent.getSerializableExtra(EXTRA_LONGITUDE) as Double?
+ if (station == null && upload != null && upload!!.isUploadForExistingStation) {
+ station = baseApplication.getDbAdapter().getStationForUpload(upload)
}
-
- if (latitude == null && longitude == null && upload != null && upload.isUploadForMissingStation()) {
- latitude = upload.getLat();
- longitude = upload.getLon();
+ if (latitude == null && longitude == null && upload != null && upload!!.isUploadForMissingStation) {
+ latitude = upload!!.lat
+ longitude = upload!!.lon
}
-
if (station == null && (latitude == null || longitude == null)) {
- Log.w(TAG, "EXTRA_STATION and EXTRA_LATITUDE or EXTRA_LONGITUDE in intent data missing");
- Toast.makeText(this, R.string.station_or_coords_not_found, Toast.LENGTH_LONG).show();
- finish();
- return;
+ Log.w(
+ TAG,
+ "EXTRA_STATION and EXTRA_LATITUDE or EXTRA_LONGITUDE in intent data missing"
+ )
+ Toast.makeText(this, R.string.station_or_coords_not_found, Toast.LENGTH_LONG).show()
+ finish()
+ return
}
-
if (station != null) {
- bahnhofId = station.getId();
- binding.upload.etStationTitle.setText(station.getTitle());
- binding.upload.etStationTitle.setInputType(EditorInfo.TYPE_NULL);
- binding.upload.etStationTitle.setSingleLine(false);
-
+ bahnhofId = station!!.id
+ binding!!.upload.etStationTitle.setText(station!!.title)
+ binding!!.upload.etStationTitle.inputType = EditorInfo.TYPE_NULL
+ binding!!.upload.etStationTitle.isSingleLine = false
if (upload == null) {
- upload = baseApplication.getDbAdapter().getPendingUploadsForStation(station).stream()
+ upload =
+ baseApplication.getDbAdapter().getPendingUploadsForStation(station).stream()
.filter(Upload::isPendingPhotoUpload)
.findFirst()
- .orElse(null);
+ .orElse(null)
}
-
- setLocalBitmap(upload);
-
- binding.upload.spActive.setVisibility(View.GONE);
- binding.upload.spCountries.setVisibility(View.GONE);
-
- String country = station.getCountry();
- updateOverrideLicense(country);
+ setLocalBitmap(upload)
+ binding!!.upload.spActive.visibility = View.GONE
+ binding!!.upload.spCountries.visibility = View.GONE
+ val country = station!!.country
+ updateOverrideLicense(country)
} else {
if (upload == null) {
- upload = baseApplication.getDbAdapter().getPendingUploadForCoordinates(latitude, longitude);
+ upload = baseApplication.getDbAdapter()
+ .getPendingUploadForCoordinates(latitude, longitude)
}
-
- binding.upload.etStationTitle.setInputType(EditorInfo.TYPE_CLASS_TEXT);
- binding.upload.spActive.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, getResources().getStringArray(R.array.active_flag_options)));
+ binding!!.upload.etStationTitle.inputType = EditorInfo.TYPE_CLASS_TEXT
+ binding!!.upload.spActive.adapter = ArrayAdapter(
+ this, android.R.layout.simple_spinner_dropdown_item, resources.getStringArray(
+ R.array.active_flag_options
+ )
+ )
if (upload != null) {
- binding.upload.etStationTitle.setText(upload.getTitle());
- setLocalBitmap(upload);
-
- if (upload.getActive() == null) {
- binding.upload.spActive.setSelection(0);
- } else if (upload.getActive()) {
- binding.upload.spActive.setSelection(1);
+ binding!!.upload.etStationTitle.setText(upload!!.title)
+ setLocalBitmap(upload)
+ if (upload!!.active == null) {
+ binding!!.upload.spActive.setSelection(0)
+ } else if (upload!!.active!!) {
+ binding!!.upload.spActive.setSelection(1)
} else {
- binding.upload.spActive.setSelection(2);
+ binding!!.upload.spActive.setSelection(2)
}
} else {
- binding.upload.spActive.setSelection(0);
+ binding!!.upload.spActive.setSelection(0)
}
-
- var items = new KeyValueSpinnerItem[countries.size() + 1];
- items[0] = new KeyValueSpinnerItem(getString(R.string.chooseCountry), "");
- int selected = 0;
-
- for (int i = 0; i < countries.size(); i++) {
- var country = countries.get(i);
- items[i + 1] = new KeyValueSpinnerItem(country.getName(), country.getCode());
- if (upload != null && country.getCode().equals(upload.getCountry())) {
- selected = i + 1;
+ val items = arrayOfNulls(
+ countries!!.size + 1
+ )
+ items[0] = KeyValueSpinnerItem(getString(R.string.chooseCountry), "")
+ var selected = 0
+ for (i in countries!!.indices) {
+ val country = countries!![i]
+ items[i + 1] = KeyValueSpinnerItem(country!!.name, country.code)
+ if (upload != null && country.code == upload!!.country) {
+ selected = i + 1
}
}
- var countryAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, items);
- countryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- binding.upload.spCountries.setAdapter(countryAdapter);
- binding.upload.spCountries.setSelection(selected);
- binding.upload.spCountries.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(final AdapterView> parent, final View view, final int position, final long id) {
- var selectedCountry = (KeyValueSpinnerItem) parent.getItemAtPosition(position);
- updateOverrideLicense(selectedCountry.getValue());
- }
+ val countryAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, items)
+ countryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ binding!!.upload.spCountries.adapter = countryAdapter
+ binding!!.upload.spCountries.setSelection(selected)
+ binding!!.upload.spCountries.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(
+ parent: AdapterView<*>,
+ view: View,
+ position: Int,
+ id: Long
+ ) {
+ val selectedCountry =
+ parent.getItemAtPosition(position) as KeyValueSpinnerItem
+ updateOverrideLicense(selectedCountry.value)
+ }
- @Override
- public void onNothingSelected(final AdapterView> parent) {
- updateOverrideLicense(null);
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ updateOverrideLicense(null)
+ }
}
- });
}
-
if (upload != null) {
- binding.upload.etComment.setText(upload.getComment());
+ binding!!.upload.etComment.setText(upload!!.comment)
}
-
- binding.upload.txtPanorama.setText(Html.fromHtml(getString(R.string.panorama_info), Html.FROM_HTML_MODE_COMPACT));
- binding.upload.txtPanorama.setMovementMethod(LinkMovementMethod.getInstance());
- binding.upload.txtPanorama.setLinkTextColor(Color.parseColor("#c71c4d"));
-
+ binding!!.upload.txtPanorama.text =
+ Html.fromHtml(getString(R.string.panorama_info), Html.FROM_HTML_MODE_COMPACT)
+ binding!!.upload.txtPanorama.movementMethod = LinkMovementMethod.getInstance()
+ binding!!.upload.txtPanorama.setLinkTextColor(Color.parseColor("#c71c4d"))
}
}
- private void updateOverrideLicense(final String country) {
- var overrideLicense = Country.getCountryByCode(countries, country).map(Country::getOverrideLicense).orElse(null);
+ private fun updateOverrideLicense(country: String?) {
+ val overrideLicense =
+ getCountryByCode(countries, country).map(Country::overrideLicense).orElse(null)
if (overrideLicense != null) {
- binding.upload.cbSpecialLicense.setText(getString(R.string.special_license, overrideLicense));
+ binding!!.upload.cbSpecialLicense.text =
+ getString(R.string.special_license, overrideLicense)
}
- binding.upload.cbSpecialLicense.setVisibility(overrideLicense == null ? View.GONE : View.VISIBLE);
+ binding!!.upload.cbSpecialLicense.visibility =
+ if (overrideLicense == null) View.GONE else View.VISIBLE
}
- private final ActivityResultLauncher imageCaptureResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK) {
- try {
- assertCurrentPhotoUploadExists();
- var cameraTempFile = getCameraTempFile();
- var options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true; // just query the image size in the first step
- BitmapFactory.decodeFile(cameraTempFile.getPath(), options);
-
- int sampling = options.outWidth / Constants.STORED_PHOTO_WIDTH;
- if (sampling > 1) {
- options.inSampleSize = sampling;
- }
- options.inJustDecodeBounds = false;
-
- storeBitmapToLocalFile(getStoredMediaFile(upload), BitmapFactory.decodeFile(cameraTempFile.getPath(), options));
- FileUtils.deleteQuietly(cameraTempFile);
- } catch (Exception e) {
- Log.e(TAG, "Error processing photo", e);
- Toast.makeText(getApplicationContext(), getString(R.string.error_processing_photo) + e.getMessage(), Toast.LENGTH_LONG).show();
- }
+ private val imageCaptureResultLauncher = registerForActivityResult(
+ StartActivityForResult()
+ ) { result: ActivityResult ->
+ if (result.resultCode == RESULT_OK) {
+ try {
+ assertCurrentPhotoUploadExists()
+ val cameraTempFile = cameraTempFile
+ val options = BitmapFactory.Options()
+ options.inJustDecodeBounds = true // just query the image size in the first step
+ BitmapFactory.decodeFile(cameraTempFile!!.path, options)
+ val sampling = options.outWidth / Constants.STORED_PHOTO_WIDTH
+ if (sampling > 1) {
+ options.inSampleSize = sampling
}
- });
-
- public void takePicture(View view) {
- if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
- return;
+ options.inJustDecodeBounds = false
+ storeBitmapToLocalFile(
+ getStoredMediaFile(upload), BitmapFactory.decodeFile(
+ cameraTempFile.path, options
+ )
+ )
+ FileUtils.deleteQuietly(cameraTempFile)
+ } catch (e: Exception) {
+ Log.e(TAG, "Error processing photo", e)
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.error_processing_photo) + e.message,
+ Toast.LENGTH_LONG
+ ).show()
+ }
}
+ }
- assertCurrentPhotoUploadExists();
- var photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", getCameraTempFile());
- var intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
- intent.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, getResources().getString(R.string.app_name));
- intent.putExtra(MediaStore.EXTRA_MEDIA_TITLE, binding.upload.etStationTitle.getText());
- intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ fun takePicture(view: View?) {
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
+ return
+ }
+ assertCurrentPhotoUploadExists()
+ val photoURI = FileProvider.getUriForFile(
+ this,
+ BuildConfig.APPLICATION_ID + ".fileprovider",
+ cameraTempFile!!
+ )
+ val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
+ intent.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, resources.getString(R.string.app_name))
+ intent.putExtra(MediaStore.EXTRA_MEDIA_TITLE, binding!!.upload.etStationTitle.text)
+ intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
try {
- imageCaptureResultLauncher.launch(intent);
- } catch (ActivityNotFoundException exception) {
- Toast.makeText(this, R.string.no_image_capture_app_found, Toast.LENGTH_LONG).show();
+ imageCaptureResultLauncher.launch(intent)
+ } catch (exception: ActivityNotFoundException) {
+ Toast.makeText(this, R.string.no_image_capture_app_found, Toast.LENGTH_LONG).show()
}
}
- private final ActivityResultLauncher selectPictureResultLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(),
- uri -> {
- try (var parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r")) {
- if (parcelFileDescriptor == null) {
- return;
- }
- var fileDescriptor = parcelFileDescriptor.getFileDescriptor();
- assertCurrentPhotoUploadExists();
-
- var bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
- int sampling = bitmap.getWidth() / Constants.STORED_PHOTO_WIDTH;
- var scaledScreen = bitmap;
- if (sampling > 1) {
- scaledScreen = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / sampling, bitmap.getHeight() / sampling, false);
- }
-
- storeBitmapToLocalFile(getStoredMediaFile(upload), scaledScreen);
- } catch (Exception e) {
- Log.e(TAG, "Error processing photo", e);
- Toast.makeText(getApplicationContext(), getString(R.string.error_processing_photo) + e.getMessage(), Toast.LENGTH_LONG).show();
+ private val selectPictureResultLauncher = registerForActivityResult(
+ GetContent()
+ ) { uri: Uri? ->
+ try {
+ contentResolver.openFileDescriptor(uri!!, "r").use { parcelFileDescriptor ->
+ if (parcelFileDescriptor == null) {
+ return@registerForActivityResult
}
- });
+ val fileDescriptor = parcelFileDescriptor.fileDescriptor
+ assertCurrentPhotoUploadExists()
+ val bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
+ val sampling = bitmap.width / Constants.STORED_PHOTO_WIDTH
+ var scaledScreen = bitmap
+ if (sampling > 1) {
+ scaledScreen = Bitmap.createScaledBitmap(
+ bitmap,
+ bitmap.width / sampling,
+ bitmap.height / sampling,
+ false
+ )
+ }
+ storeBitmapToLocalFile(getStoredMediaFile(upload), scaledScreen)
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Error processing photo", e)
+ Toast.makeText(
+ applicationContext,
+ getString(R.string.error_processing_photo) + e.message,
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
- public void selectPicture(View view) {
- selectPictureResultLauncher.launch("image/*");
+ fun selectPicture(view: View?) {
+ selectPictureResultLauncher.launch("image/*")
}
- private void assertCurrentPhotoUploadExists() {
- if (upload == null || upload.isProblemReport() || upload.isUploaded()) {
- upload = new Upload(
- null,
- station != null ? station.getCountry() : null,
- station != null ? station.getId() : null,
- null,
- null,
- latitude,
- longitude);
- upload = baseApplication.getDbAdapter().insertUpload(upload);
+ private fun assertCurrentPhotoUploadExists() {
+ if (upload == null || upload!!.isProblemReport || upload!!.isUploaded) {
+ upload = Upload(
+ null,
+ if (station != null) station!!.country else null,
+ if (station != null) station!!.id else null,
+ null,
+ null,
+ latitude,
+ longitude
+ )
+ upload = baseApplication.getDbAdapter().insertUpload(upload)
}
}
- private void storeBitmapToLocalFile(File file, Bitmap bitmap) throws IOException {
+ @Throws(IOException::class)
+ private fun storeBitmapToLocalFile(file: File?, bitmap: Bitmap?) {
if (bitmap == null) {
- throw new RuntimeException(getString(R.string.error_scaling_photo));
+ throw RuntimeException(getString(R.string.error_scaling_photo))
}
- Log.i(TAG, "Save photo with width=" + bitmap.getWidth() + " and height=" + bitmap.getHeight() + " to: " + file);
- try (var cos = new CheckedOutputStream(new FileOutputStream(file), new CRC32())) {
- bitmap.compress(Bitmap.CompressFormat.JPEG, Constants.STORED_PHOTO_QUALITY, cos);
- crc32 = cos.getChecksum().getValue();
- setLocalBitmap(upload);
+ Log.i(
+ TAG,
+ "Save photo with width=" + bitmap.width + " and height=" + bitmap.height + " to: " + file
+ )
+ CheckedOutputStream(FileOutputStream(file), CRC32()).use { cos ->
+ bitmap.compress(Bitmap.CompressFormat.JPEG, Constants.STORED_PHOTO_QUALITY, cos)
+ crc32 = cos.checksum.value
+ setLocalBitmap(upload)
}
}
@@ -346,257 +350,290 @@ public class UploadActivity extends AppCompatActivity implements ActivityCompat.
*
* @return the File
*/
- @Nullable
- public File getStoredMediaFile(Upload upload) {
- if (upload == null) {
- return null;
- }
- return FileUtils.getStoredMediaFile(this, upload.getId());
+ fun getStoredMediaFile(upload: Upload?): File? {
+ return if (upload == null) {
+ null
+ } else FileUtils.getStoredMediaFile(this, upload.id)
}
- /**
- * Get the file path for the Camera app to store the unprocessed photo to.
- */
- private File getCameraTempFile() {
- return FileUtils.getImageCacheFile(this, String.valueOf(upload.getId()));
- }
+ private val cameraTempFile: File?
+ /**
+ * Get the file path for the Camera app to store the unprocessed photo to.
+ */
+ private get() = FileUtils.getImageCacheFile(this, upload!!.id.toString())
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.upload, menu);
- return super.onCreateOptionsMenu(menu);
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.upload, menu)
+ return super.onCreateOptionsMenu(menu)
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val itemId = item.itemId
if (itemId == R.id.share_photo) {
- var shareIntent = createPhotoSendIntent();
+ val shareIntent = createPhotoSendIntent()
if (shareIntent != null) {
- shareIntent.putExtra(Intent.EXTRA_TEXT, binding.upload.etStationTitle.getText());
- shareIntent.setType("image/jpeg");
- startActivity(createChooser(shareIntent, getString(R.string.share_photo)));
+ shareIntent.putExtra(Intent.EXTRA_TEXT, binding!!.upload.etStationTitle.text)
+ shareIntent.type = "image/jpeg"
+ startActivity(Intent.createChooser(shareIntent, getString(R.string.share_photo)))
}
} else if (itemId == android.R.id.home) {
- navigateUp();
+ navigateUp()
} else {
- return super.onOptionsItemSelected(item);
+ return super.onOptionsItemSelected(item)
}
-
- return true;
+ return true
}
- public void navigateUp() {
- var callingActivity = getCallingActivity(); // if MapsActivity was calling, then we don't want to rebuild the Backstack
- var upIntent = NavUtils.getParentActivityIntent(this);
+ fun navigateUp() {
+ val callingActivity =
+ callingActivity // if MapsActivity was calling, then we don't want to rebuild the Backstack
+ val upIntent = NavUtils.getParentActivityIntent(this)
if (callingActivity == null && upIntent != null) {
- upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
- if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
- Log.v(TAG, "Recreate back stack");
- TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
+ upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot) {
+ Log.v(TAG, "Recreate back stack")
+ TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
+ .startActivities()
}
}
-
- finish();
+ finish()
}
- public void upload(View view) {
- if (TextUtils.isEmpty(binding.upload.etStationTitle.getText())) {
- Toast.makeText(this, R.string.station_title_needed, Toast.LENGTH_LONG).show();
- return;
+ fun upload(view: View?) {
+ if (TextUtils.isEmpty(binding!!.upload.etStationTitle.text)) {
+ Toast.makeText(this, R.string.station_title_needed, Toast.LENGTH_LONG).show()
+ return
}
-
- assertCurrentPhotoUploadExists();
-
- var mediaFile = getStoredMediaFile(upload);
- assert mediaFile != null;
-
+ assertCurrentPhotoUploadExists()
+ val mediaFile = getStoredMediaFile(upload)!!
if (!mediaFile.exists()) {
if (station != null) {
- Toast.makeText(this, R.string.please_take_photo, Toast.LENGTH_LONG).show();
- return;
+ Toast.makeText(this, R.string.please_take_photo, Toast.LENGTH_LONG).show()
+ return
}
}
-
- if (binding.upload.cbSpecialLicense.getText().length() > 0 && !binding.upload.cbSpecialLicense.isChecked()) {
- Toast.makeText(this, R.string.special_license_confirm, Toast.LENGTH_LONG).show();
- return;
+ if (binding!!.upload.cbSpecialLicense.text.length > 0 && !binding!!.upload.cbSpecialLicense.isChecked) {
+ Toast.makeText(this, R.string.special_license_confirm, Toast.LENGTH_LONG).show()
+ return
}
- if (crc32 != null && upload != null && crc32.equals(upload.getCrc32()) && !binding.upload.cbChecksum.isChecked()) {
- Toast.makeText(this, R.string.photo_checksum, Toast.LENGTH_LONG).show();
- return;
+ if (crc32 != null && upload != null && crc32 == upload!!.crc32 && !binding!!.upload.cbChecksum.isChecked) {
+ Toast.makeText(this, R.string.photo_checksum, Toast.LENGTH_LONG).show()
+ return
}
if (station == null) {
- if (binding.upload.spActive.getSelectedItemPosition() == 0) {
- Toast.makeText(this, R.string.active_flag_choose, Toast.LENGTH_LONG).show();
- return;
+ if (binding!!.upload.spActive.selectedItemPosition == 0) {
+ Toast.makeText(this, R.string.active_flag_choose, Toast.LENGTH_LONG).show()
+ return
}
- var selectedCountry = (KeyValueSpinnerItem) binding.upload.spCountries.getSelectedItem();
- upload.setCountry(selectedCountry.getValue());
+ val selectedCountry = binding!!.upload.spCountries.selectedItem as KeyValueSpinnerItem
+ upload!!.country = selectedCountry.value
}
-
- SimpleDialogs.confirmOkCancel(this, station != null ? R.string.photo_upload : R.string.report_missing_station, (dialog, which) -> {
- binding.upload.progressBar.setVisibility(View.VISIBLE);
-
- var stationTitle = binding.upload.etStationTitle.getText().toString();
- var comment = binding.upload.etComment.getText().toString();
- upload.setTitle(stationTitle);
- upload.setComment(comment);
-
+ SimpleDialogs.confirmOkCancel(
+ this,
+ if (station != null) R.string.photo_upload else R.string.report_missing_station
+ ) { dialog: DialogInterface?, which: Int ->
+ binding!!.upload.progressBar.visibility = View.VISIBLE
+ var stationTitle: String? = binding!!.upload.etStationTitle.text.toString()
+ var comment: String? = binding!!.upload.etComment.text.toString()
+ upload!!.title = stationTitle
+ upload!!.comment = comment
try {
- stationTitle = URLEncoder.encode(binding.upload.etStationTitle.getText().toString(), String.valueOf(StandardCharsets.UTF_8));
- comment = URLEncoder.encode(comment, String.valueOf(StandardCharsets.UTF_8));
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, "Error encoding station title or comment", e);
+ stationTitle = URLEncoder.encode(
+ binding!!.upload.etStationTitle.text.toString(),
+ StandardCharsets.UTF_8.toString()
+ )
+ comment = URLEncoder.encode(comment, StandardCharsets.UTF_8.toString())
+ } catch (e: UnsupportedEncodingException) {
+ Log.e(TAG, "Error encoding station title or comment", e)
}
- upload.setActive(binding.upload.spActive.getSelectedItemPosition() == 1);
- baseApplication.getDbAdapter().updateUpload(upload);
-
- var file = mediaFile.exists() ? RequestBody.create(mediaFile, MediaType.parse(URLConnection.guessContentTypeFromName(mediaFile.getName()))) : RequestBody.create(new byte[]{}, MediaType.parse("application/octet-stream"));
- rsapiClient.photoUpload(bahnhofId, station != null ? station.getCountry() : upload.getCountry(),
- stationTitle, latitude, longitude, comment, upload.getActive(), file).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) {
- binding.upload.progressBar.setVisibility(View.GONE);
- InboxResponse inboxResponse;
- if (response.isSuccessful()) {
- inboxResponse = response.body();
+ upload!!.active = binding!!.upload.spActive.selectedItemPosition == 1
+ baseApplication.getDbAdapter().updateUpload(upload)
+ val file: RequestBody = if (mediaFile.exists()) RequestBody.create(
+ mediaFile, parse.parse(
+ URLConnection.guessContentTypeFromName(
+ mediaFile.name
+ )
+ )
+ ) else RequestBody.create(byteArrayOf(), parse.parse("application/octet-stream"))
+ rsapiClient!!.photoUpload(
+ bahnhofId, if (station != null) station!!.country else upload!!.country,
+ stationTitle, latitude, longitude, comment, upload!!.active, file
+ )!!.enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ binding!!.upload.progressBar.visibility = View.GONE
+ val inboxResponse: InboxResponse?
+ inboxResponse = if (response.isSuccessful) {
+ response.body()
} else if (response.code() == 401) {
- onUnauthorized();
- return;
+ onUnauthorized()
+ return@confirmOkCancel
} else {
- assert response.errorBody() != null;
- var gson = new Gson();
- inboxResponse = gson.fromJson(response.errorBody().charStream(), InboxResponse.class);
+ assert(response.errorBody() != null)
+ val gson = Gson()
+ gson.fromJson(
+ response.errorBody()!!.charStream(),
+ InboxResponse::class.java
+ )
}
-
- assert inboxResponse != null;
- upload.setRemoteId(inboxResponse.getId());
- upload.setInboxUrl(inboxResponse.getInboxUrl());
- upload.setUploadState(inboxResponse.getState().getUploadState());
- upload.setCrc32(inboxResponse.getCrc32());
- baseApplication.getDbAdapter().updateUpload(upload);
- if (inboxResponse.getState() == InboxResponse.InboxResponseState.ERROR) {
- SimpleDialogs.confirmOk(UploadActivity.this,
- getString(InboxResponse.InboxResponseState.ERROR.getMessageId(), inboxResponse.getMessage()));
+ assert(inboxResponse != null)
+ upload!!.remoteId = inboxResponse!!.id
+ upload!!.inboxUrl = inboxResponse.inboxUrl
+ upload!!.uploadState = inboxResponse.state.uploadState
+ upload!!.crc32 = inboxResponse.crc32
+ baseApplication.getDbAdapter().updateUpload(upload)
+ if (inboxResponse.state === InboxResponse.InboxResponseState.ERROR) {
+ confirmOk(
+ this@UploadActivity,
+ getString(
+ InboxResponse.InboxResponseState.ERROR.messageId,
+ inboxResponse.message
+ )
+ )
} else {
- SimpleDialogs.confirmOk(UploadActivity.this, inboxResponse.getState().getMessageId());
+ confirmOk(this@UploadActivity, inboxResponse.state.messageId)
}
}
- @Override
- public void onFailure(@NonNull Call call, @NonNull Throwable t) {
- Log.e(TAG, "Error uploading photo", t);
- binding.upload.progressBar.setVisibility(View.GONE);
-
- SimpleDialogs.confirmOk(UploadActivity.this,
- getString(InboxResponse.InboxResponseState.ERROR.getMessageId(), t.getMessage()));
- fetchUploadStatus(upload); // try to get the upload state again
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e(TAG, "Error uploading photo", t)
+ binding!!.upload.progressBar.visibility = View.GONE
+ confirmOk(
+ this@UploadActivity,
+ getString(InboxResponse.InboxResponseState.ERROR.messageId, t.message)
+ )
+ fetchUploadStatus(upload) // try to get the upload state again
}
- });
- });
+ })
+ }
}
- private Intent createPhotoSendIntent() {
- var file = getStoredMediaFile(upload);
+ private fun createPhotoSendIntent(): Intent? {
+ val file = getStoredMediaFile(upload)
if (file != null && file.canRead()) {
- var sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(UploadActivity.this,
- BuildConfig.APPLICATION_ID + ".fileprovider", file));
- return sendIntent;
+ val sendIntent = Intent(Intent.ACTION_SEND)
+ sendIntent.putExtra(
+ Intent.EXTRA_STREAM, FileProvider.getUriForFile(
+ this@UploadActivity,
+ BuildConfig.APPLICATION_ID + ".fileprovider", file
+ )
+ )
+ return sendIntent
}
- return null;
+ return null
}
/**
* Fetch bitmap from device local location, if it exists, and set the photo view.
*/
- private void setLocalBitmap(Upload upload) {
- var localPhoto = checkForLocalPhoto(upload);
+ private fun setLocalBitmap(upload: Upload?) {
+ val localPhoto = checkForLocalPhoto(upload)
if (localPhoto != null) {
- binding.upload.imageview.setImageBitmap(localPhoto);
- fetchUploadStatus(upload);
+ binding!!.upload.imageview.setImageBitmap(localPhoto)
+ fetchUploadStatus(upload)
}
}
- private void fetchUploadStatus(Upload upload) {
- if (upload == null || upload.getRemoteId() == null) {
- return;
+ private fun fetchUploadStatus(upload: Upload?) {
+ if (upload == null || upload.remoteId == null) {
+ return
}
- var stateQuery = new InboxStateQuery(
- upload.getRemoteId(),
- upload.getCountry(),
- upload.getStationId());
-
- rsapiClient.queryUploadState(List.of(stateQuery)).enqueue(new Callback<>() {
- @Override
- public void onResponse(@NonNull Call> call, @NonNull Response> response) {
- if (response.isSuccessful()) {
- var stateQueries = response.body();
- if (stateQueries != null && !stateQueries.isEmpty()) {
- var stateQuery = stateQueries.get(0);
- binding.upload.uploadStatus.setText(getString(R.string.upload_state, getString(stateQuery.getState().getTextId())));
- binding.upload.uploadStatus.setTextColor(getResources().getColor(stateQuery.getState().getColorId(), null));
- binding.upload.uploadStatus.setVisibility(View.VISIBLE);
- upload.setUploadState(stateQuery.getState());
- upload.setRejectReason(stateQuery.getRejectedReason());
- upload.setCrc32(stateQuery.getCrc32());
- upload.setRemoteId(stateQuery.getId());
- baseApplication.getDbAdapter().updateUpload(upload);
- updateCrc32Checkbox();
+ val stateQuery = InboxStateQuery(
+ upload.remoteId,
+ upload.country,
+ upload.stationId
+ )
+ rsapiClient!!.queryUploadState(java.util.List.of(stateQuery))!!
+ .enqueue(object : Callback?> {
+ override fun onResponse(
+ call: Call?>,
+ response: Response?>
+ ) {
+ if (response.isSuccessful) {
+ val stateQueries = response.body()
+ if (stateQueries != null && !stateQueries.isEmpty()) {
+ val stateQuery = stateQueries[0]
+ binding!!.upload.uploadStatus.text =
+ getString(R.string.upload_state, getString(stateQuery.state.textId))
+ binding!!.upload.uploadStatus.setTextColor(
+ resources.getColor(
+ stateQuery.state.colorId,
+ null
+ )
+ )
+ binding!!.upload.uploadStatus.visibility = View.VISIBLE
+ upload.uploadState = stateQuery.state
+ upload.rejectReason = stateQuery.rejectedReason
+ upload.crc32 = stateQuery.crc32
+ upload.remoteId = stateQuery.id
+ baseApplication.getDbAdapter().updateUpload(upload)
+ updateCrc32Checkbox()
+ }
+ } else if (response.code() == 401) {
+ onUnauthorized()
+ } else {
+ Log.w(TAG, "Upload states not processable")
}
- } else if (response.code() == 401) {
- onUnauthorized();
- } else {
- Log.w(TAG, "Upload states not processable");
}
- }
-
- @Override
- public void onFailure(@NonNull Call> call, @NonNull Throwable t) {
- Log.e(TAG, "Error retrieving upload state", t);
- }
- });
+ override fun onFailure(call: Call?>, t: Throwable) {
+ Log.e(TAG, "Error retrieving upload state", t)
+ }
+ })
}
- private void onUnauthorized() {
- baseApplication.setAccessToken(null);
- rsapiClient.clearToken();
- Toast.makeText(this, R.string.authorization_failed, Toast.LENGTH_LONG).show();
- startActivity(new Intent(this, MyDataActivity.class));
- finish();
+ private fun onUnauthorized() {
+ baseApplication.setAccessToken(null)
+ rsapiClient!!.clearToken()
+ Toast.makeText(this, R.string.authorization_failed, Toast.LENGTH_LONG).show()
+ startActivity(Intent(this, MyDataActivity::class.java))
+ finish()
}
- private void updateCrc32Checkbox() {
+ private fun updateCrc32Checkbox() {
if (crc32 != null && upload != null) {
- var sameChecksum = crc32.equals(upload.getCrc32());
- binding.upload.cbChecksum.setVisibility(sameChecksum ? View.VISIBLE : View.GONE);
+ val sameChecksum = crc32 == upload!!.crc32
+ binding!!.upload.cbChecksum.visibility = if (sameChecksum) View.VISIBLE else View.GONE
}
}
/**
* Check if there's a local photo file for this station.
*/
- @Nullable
- private Bitmap checkForLocalPhoto(Upload upload) {
+ private fun checkForLocalPhoto(upload: Upload?): Bitmap? {
// show the image
- var localFile = getStoredMediaFile(upload);
- Log.d(TAG, "File: " + localFile);
- crc32 = null;
+ val localFile = getStoredMediaFile(upload)
+ Log.d(TAG, "File: $localFile")
+ crc32 = null
if (localFile != null && localFile.canRead()) {
- Log.d(TAG, "FileGetPath: " + localFile.getPath());
- try (var cis = new CheckedInputStream(new FileInputStream(localFile), new CRC32())) {
- var scaledScreen = BitmapFactory.decodeStream(cis);
- crc32 = cis.getChecksum().getValue();
- Log.d(TAG, "img width " + scaledScreen.getWidth() + ", height " + scaledScreen.getHeight() + ", crc32 " + crc32);
- updateCrc32Checkbox();
- return scaledScreen;
- } catch (Exception e) {
- Log.e(TAG, String.format("Error reading media file for station %s", bahnhofId), e);
+ Log.d(TAG, "FileGetPath: " + localFile.path)
+ try {
+ CheckedInputStream(FileInputStream(localFile), CRC32()).use { cis ->
+ val scaledScreen = BitmapFactory.decodeStream(cis)
+ crc32 = cis.checksum.value
+ Log.d(
+ TAG,
+ "img width " + scaledScreen.width + ", height " + scaledScreen.height + ", crc32 " + crc32
+ )
+ updateCrc32Checkbox()
+ return scaledScreen
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, String.format("Error reading media file for station %s", bahnhofId), e)
}
}
- return null;
+ return null
}
-}
+ companion object {
+ private val TAG = UploadActivity::class.java.simpleName
+
+ // Names of Extras that this class reacts to
+ const val EXTRA_UPLOAD = "EXTRA_UPLOAD"
+ const val EXTRA_STATION = "EXTRA_STATION"
+ const val EXTRA_LATITUDE = "EXTRA_LATITUDE"
+ const val EXTRA_LONGITUDE = "EXTRA_LONGITUDE"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/CountryAdapter.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/CountryAdapter.kt
index 21be4562..d1e6f5b5 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/CountryAdapter.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/CountryAdapter.kt
@@ -1,123 +1,121 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos.db;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CursorAdapter;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.BaseApplication;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.R;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ItemCountryBinding;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants;
-
-public class CountryAdapter extends CursorAdapter {
- private final LayoutInflater layoutInflater;
- private final String TAG = getClass().getSimpleName();
- private final Set selectedCountries;
-
- private final Context context;
-
- public CountryAdapter(Context context, Cursor c, int flags) {
- super(context, c, flags);
- layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- selectedCountries = new HashSet<>(BaseApplication.getInstance().getCountryCodes());
- this.context = context;
+package de.bahnhoefe.deutschlands.bahnhofsfotos.db
+
+import android.content.Context
+import android.database.Cursor
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import android.widget.CursorAdapter
+import de.bahnhoefe.deutschlands.bahnhofsfotos.BaseApplication
+import de.bahnhoefe.deutschlands.bahnhofsfotos.R
+import de.bahnhoefe.deutschlands.bahnhofsfotos.databinding.ItemCountryBinding
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants.COUNTRIES
+
+class CountryAdapter(private val context: Context, c: Cursor?, flags: Int) : CursorAdapter(
+ context, c, flags
+) {
+ private val layoutInflater: LayoutInflater =
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
+ private val selectedCountries: MutableSet =
+ BaseApplication.instance.countryCodes.toMutableSet()
+
+ companion object {
+ private val TAG = CountryAdapter::class.java.simpleName
}
- public void getView(int selectedPosition, View convertView, ViewGroup parent, Cursor cursor) {
- ItemCountryBinding binding;
- if (convertView == null) {
- binding = ItemCountryBinding.inflate(layoutInflater, parent, false);
- convertView = binding.getRoot();
-
+ fun getView(selectedPosition: Int, convertView: View?, parent: ViewGroup?, cursor: Cursor?) {
+ var rowView = convertView
+ val binding: ItemCountryBinding
+ if (rowView == null) {
+ binding = ItemCountryBinding.inflate(layoutInflater, parent, false)
+ rowView = binding.root
if (selectedPosition % 2 == 1) {
- convertView.setBackgroundResource(R.drawable.item_list_backgroundcolor);
+ rowView.setBackgroundResource(R.drawable.item_list_backgroundcolor)
} else {
- convertView.setBackgroundResource(R.drawable.item_list_backgroundcolor2);
+ rowView.setBackgroundResource(R.drawable.item_list_backgroundcolor2)
}
-
- convertView.setTag(binding);
+ rowView.setTag(binding)
} else {
- binding = (ItemCountryBinding) convertView.getTag();
+ binding = rowView.tag as ItemCountryBinding
}
-
- var countryCode = cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYSHORTCODE));
- binding.txtCountryShortCode.setText(countryCode);
- var countryName = getCountryName(countryCode, cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYNAME)));
- binding.txtCountryName.setText(countryName);
-
- var newCountry = cursor.getString(1);
- Log.i(TAG, newCountry);
+ val countryCode =
+ cursor!!.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYSHORTCODE))
+ binding.txtCountryShortCode.text = countryCode
+ val countryName = getCountryName(
+ countryCode,
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYNAME))
+ )
+ binding.txtCountryName.text = countryName
+ val newCountry = cursor.getString(1)
+ Log.i(TAG, newCountry)
if (selectedCountries.contains(newCountry)) {
- binding.checkCountry.setChecked(false);
- selectedCountries.remove(newCountry);
+ binding.checkCountry.isChecked = false
+ selectedCountries.remove(newCountry)
} else {
- binding.checkCountry.setChecked(true);
- selectedCountries.add(newCountry);
+ binding.checkCountry.isChecked = true
+ selectedCountries.add(newCountry)
}
-
}
- private String getCountryName(final String countryCode, final String defaultName) {
- int strId = context.getResources().getIdentifier("country_" + countryCode, "string", context.getPackageName());
- if (strId != 0) {
- return context.getString(strId);
- }
- return defaultName;
+ private fun getCountryName(countryCode: String, defaultName: String): String {
+ val strId =
+ context.resources.getIdentifier("country_$countryCode", "string", context.packageName)
+ return if (strId != 0) {
+ context.getString(strId)
+ } else defaultName
}
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- var binding = ItemCountryBinding.inflate(layoutInflater, parent, false);
- var view = binding.getRoot();
- view.setTag(binding);
- return view;
+ override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
+ val binding = ItemCountryBinding.inflate(layoutInflater, parent, false)
+ val view = binding.root
+ view.tag = binding
+ return view
}
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
+ override fun bindView(view: View, context: Context, cursor: Cursor) {
//If you want to have zebra lines color effect uncomment below code
- if (cursor.getPosition() % 2 == 1) {
- view.setBackgroundResource(R.drawable.item_list_backgroundcolor);
+ if (cursor.position % 2 == 1) {
+ view.setBackgroundResource(R.drawable.item_list_backgroundcolor)
} else {
- view.setBackgroundResource(R.drawable.item_list_backgroundcolor2);
+ view.setBackgroundResource(R.drawable.item_list_backgroundcolor2)
}
-
- var binding = (ItemCountryBinding) view.getTag();
-
- var countryCode = cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYSHORTCODE));
- binding.txtCountryShortCode.setText(countryCode);
- var countryName = getCountryName(countryCode, cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYNAME)));
- binding.txtCountryName.setText(countryName);
-
- var newCountry = cursor.getString(1);
- Log.i(TAG, newCountry);
- binding.checkCountry.setChecked(selectedCountries.contains(newCountry));
- binding.checkCountry.setOnClickListener(onStateChangedListener(binding.checkCountry, cursor.getPosition()));
+ val binding = view.tag as ItemCountryBinding
+ val countryCode = cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYSHORTCODE))
+ binding.txtCountryShortCode.text = countryCode
+ val countryName = getCountryName(
+ countryCode,
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYNAME))
+ )
+ binding.txtCountryName.text = countryName
+ val newCountry = cursor.getString(1)
+ Log.i(TAG, newCountry)
+ binding.checkCountry.isChecked = selectedCountries.contains(newCountry)
+ binding.checkCountry.setOnClickListener(
+ onStateChangedListener(
+ binding.checkCountry,
+ cursor.position
+ )
+ )
}
- private View.OnClickListener onStateChangedListener(CheckBox checkCountry, int position) {
- return v -> {
- var cursor = (Cursor) getItem(position);
- var country = cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYSHORTCODE));
- if (checkCountry.isChecked()) {
- selectedCountries.add(country);
+ private fun onStateChangedListener(
+ checkCountry: CheckBox,
+ position: Int
+ ): View.OnClickListener {
+ return View.OnClickListener { v: View? ->
+ val cursor = getItem(position) as Cursor
+ val country = cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYSHORTCODE))
+ if (checkCountry.isChecked) {
+ selectedCountries.add(country)
} else {
- selectedCountries.remove(country);
+ selectedCountries.remove(country)
}
- };
+ }
}
- public Set getSelectedCountries() {
- return selectedCountries;
+ fun getSelectedCountries(): Set {
+ return selectedCountries
}
-
-}
-
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/DbAdapter.kt b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/DbAdapter.kt
index abcb3acc..116ba33c 100644
--- a/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/DbAdapter.kt
+++ b/app/src/main/kotlin/de/bahnhoefe/deutschlands/bahnhofsfotos/db/DbAdapter.kt
@@ -1,239 +1,192 @@
-package de.bahnhoefe.deutschlands.bahnhofsfotos.db;
-
-import static java.util.stream.Collectors.joining;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.location.Location;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.text.Normalizer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Predicate;
-
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStation;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStations;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemType;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProviderApp;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Statistic;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UploadState;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants;
-import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter;
-
-public class DbAdapter {
-
- private static final String TAG = DbAdapter.class.getSimpleName();
-
- private static final String DATABASE_TABLE_STATIONS = "bahnhoefe";
- private static final String DATABASE_TABLE_COUNTRIES = "laender";
- private static final String DATABASE_TABLE_PROVIDER_APPS = "providerApps";
- private static final String DATABASE_TABLE_UPLOADS = "uploads";
- private static final String DATABASE_NAME = "bahnhoefe.db";
- private static final int DATABASE_VERSION = 22;
-
- private static final String CREATE_STATEMENT_STATIONS = "CREATE TABLE " + DATABASE_TABLE_STATIONS + " ("
- + Constants.STATIONS.ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + Constants.STATIONS.COUNTRY + " TEXT, "
- + Constants.STATIONS.ID + " TEXT, "
- + Constants.STATIONS.TITLE + " TEXT, "
- + Constants.STATIONS.NORMALIZED_TITLE + " TEXT, "
- + Constants.STATIONS.LAT + " REAL, "
- + Constants.STATIONS.LON + " REAL, "
- + Constants.STATIONS.PHOTO_ID + " INTEGER, "
- + Constants.STATIONS.PHOTO_URL + " TEXT, "
- + Constants.STATIONS.PHOTOGRAPHER + " TEXT, "
- + Constants.STATIONS.PHOTOGRAPHER_URL + " TEXT, "
- + Constants.STATIONS.LICENSE + " TEXT, "
- + Constants.STATIONS.LICENSE_URL + " TEXT, "
- + Constants.STATIONS.DS100 + " TEXT, "
- + Constants.STATIONS.ACTIVE + " INTEGER, "
- + Constants.STATIONS.OUTDATED + " INTEGER)";
- private static final String CREATE_STATEMENT_STATIONS_IDX = "CREATE INDEX " + DATABASE_TABLE_STATIONS + "_IDX "
- + "ON " + DATABASE_TABLE_STATIONS + "(" + Constants.STATIONS.COUNTRY + ", " + Constants.STATIONS.ID + ")";
- private static final String CREATE_STATEMENT_COUNTRIES = "CREATE TABLE " + DATABASE_TABLE_COUNTRIES + " ("
- + Constants.COUNTRIES.ROWID_COUNTRIES + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + Constants.COUNTRIES.COUNTRYSHORTCODE + " TEXT, "
- + Constants.COUNTRIES.COUNTRYNAME + " TEXT, "
- + Constants.COUNTRIES.EMAIL + " TEXT, "
- + Constants.COUNTRIES.TIMETABLE_URL_TEMPLATE + " TEXT, "
- + Constants.COUNTRIES.OVERRIDE_LICENSE + " TEXT)";
- private static final String CREATE_STATEMENT_PROVIDER_APPS = "CREATE TABLE " + DATABASE_TABLE_PROVIDER_APPS + " ("
- + Constants.PROVIDER_APPS.COUNTRYSHORTCODE + " TEXT,"
- + Constants.PROVIDER_APPS.PA_TYPE + " TEXT,"
- + Constants.PROVIDER_APPS.PA_NAME + " TEXT, "
- + Constants.PROVIDER_APPS.PA_URL + " TEXT)";
- private static final String CREATE_STATEMENT_UPLOADS = "CREATE TABLE " + DATABASE_TABLE_UPLOADS + " ("
- + Constants.UPLOADS.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + Constants.UPLOADS.STATION_ID + " TEXT, "
- + Constants.UPLOADS.COUNTRY + " TEXT, "
- + Constants.UPLOADS.REMOTE_ID + " INTEGER, "
- + Constants.UPLOADS.TITLE + " TEXT, "
- + Constants.UPLOADS.LAT + " REAL, "
- + Constants.UPLOADS.LON + " REAL, "
- + Constants.UPLOADS.COMMENT + " TEXT, "
- + Constants.UPLOADS.INBOX_URL + " TEXT, "
- + Constants.UPLOADS.PROBLEM_TYPE + " TEXT, "
- + Constants.UPLOADS.REJECTED_REASON + " TEXT, "
- + Constants.UPLOADS.UPLOAD_STATE + " TEXT, "
- + Constants.UPLOADS.CREATED_AT + " INTEGER, "
- + Constants.UPLOADS.ACTIVE + " INTEGER, "
- + Constants.UPLOADS.CRC32 + " INTEGER)";
-
- private static final String DROP_STATEMENT_STATIONS_IDX = "DROP INDEX IF EXISTS " + DATABASE_TABLE_STATIONS + "_IDX";
- private static final String DROP_STATEMENT_STATIONS = "DROP TABLE IF EXISTS " + DATABASE_TABLE_STATIONS;
- private static final String DROP_STATEMENT_COUNTRIES = "DROP TABLE IF EXISTS " + DATABASE_TABLE_COUNTRIES;
- private static final String DROP_STATEMENT_PROVIDER_APPS = "DROP TABLE IF EXISTS " + DATABASE_TABLE_PROVIDER_APPS;
-
- private final Context context;
- private DbOpenHelper dbHelper;
- private SQLiteDatabase db;
-
- public DbAdapter(Context context) {
- this.context = context;
- }
-
- public void open() {
- dbHelper = new DbOpenHelper(context);
- db = dbHelper.getWritableDatabase();
- }
-
- public void close() {
- db.close();
- dbHelper.close();
- }
-
- public void insertStations(PhotoStations photoStations, String countryCode) {
- db.beginTransaction();
+package de.bahnhoefe.deutschlands.bahnhofsfotos.db
+
+import android.content.ContentValues
+import android.content.Context
+import android.database.Cursor
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteOpenHelper
+import android.database.sqlite.SQLiteQueryBuilder
+import android.location.Location
+import android.util.Log
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Country
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.InboxStateQuery
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStation
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.PhotoStations
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProblemType
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.ProviderApp
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Station
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Statistic
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.Upload
+import de.bahnhoefe.deutschlands.bahnhofsfotos.model.UploadState
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants.COUNTRIES
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants.PROVIDER_APPS
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants.STATIONS
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.Constants.UPLOADS
+import de.bahnhoefe.deutschlands.bahnhofsfotos.util.StationFilter
+import org.apache.commons.lang3.StringUtils
+import java.text.Normalizer
+import java.util.Arrays
+import java.util.function.Consumer
+import java.util.function.Predicate
+import java.util.stream.Collectors
+
+class DbAdapter(private val context: Context) {
+ private var dbHelper: DbOpenHelper? = null
+ private var db: SQLiteDatabase? = null
+ fun open() {
+ dbHelper = DbOpenHelper(context)
+ db = dbHelper!!.writableDatabase
+ }
+
+ fun close() {
+ db!!.close()
+ dbHelper!!.close()
+ }
+
+ fun insertStations(photoStations: PhotoStations, countryCode: String?) {
+ db!!.beginTransaction()
try {
- deleteStations(Set.of(countryCode));
- photoStations.getStations().forEach(station -> db.insert(DATABASE_TABLE_STATIONS, null, toContentValues(station, photoStations)));
- db.setTransactionSuccessful();
+ deleteStations(java.util.Set.of(countryCode))
+ photoStations.stations.forEach(Consumer { station: PhotoStation ->
+ db!!.insert(
+ DATABASE_TABLE_STATIONS, null, toContentValues(station, photoStations)
+ )
+ })
+ db!!.setTransactionSuccessful()
} finally {
- db.endTransaction();
- }
- }
-
- private ContentValues toContentValues(PhotoStation station, PhotoStations photoStations) {
- var values = new ContentValues();
- values.put(Constants.STATIONS.ID, station.getId());
- values.put(Constants.STATIONS.COUNTRY, station.getCountry());
- values.put(Constants.STATIONS.TITLE, station.getTitle());
- values.put(Constants.STATIONS.NORMALIZED_TITLE, StringUtils.replaceChars(StringUtils.deleteWhitespace(StringUtils.stripAccents(Normalizer.normalize(station.getTitle(), Normalizer.Form.NFC))), "-_()", null));
- values.put(Constants.STATIONS.LAT, station.getLat());
- values.put(Constants.STATIONS.LON, station.getLon());
- values.put(Constants.STATIONS.DS100, station.getShortCode());
- values.put(Constants.STATIONS.ACTIVE, !station.getInactive());
- if (station.getPhotos().size() > 0) {
- var photo = station.getPhotos().get(0);
- values.put(Constants.STATIONS.PHOTO_ID, photo.getId());
- values.put(Constants.STATIONS.PHOTO_URL, photoStations.getPhotoBaseUrl() + photo.getPath());
- values.put(Constants.STATIONS.PHOTOGRAPHER, photo.getPhotographer());
- values.put(Constants.STATIONS.OUTDATED, photo.getOutdated());
- values.put(Constants.STATIONS.PHOTOGRAPHER_URL, photoStations.getPhotographerUrl(photo.getPhotographer()));
- values.put(Constants.STATIONS.LICENSE, photoStations.getLicenseName(photo.getLicense()));
- values.put(Constants.STATIONS.LICENSE_URL, photoStations.getLicenseUrl(photo.getLicense()));
- }
- return values;
- }
-
- public void insertCountries(List countries) {
+ db!!.endTransaction()
+ }
+ }
+
+ private fun toContentValues(
+ station: PhotoStation,
+ photoStations: PhotoStations
+ ): ContentValues {
+ val values = ContentValues()
+ values.put(STATIONS.ID, station.id)
+ values.put(STATIONS.COUNTRY, station.country)
+ values.put(STATIONS.TITLE, station.title)
+ values.put(
+ STATIONS.NORMALIZED_TITLE, StringUtils.replaceChars(
+ StringUtils.deleteWhitespace(
+ StringUtils.stripAccents(
+ Normalizer.normalize(
+ station.title,
+ Normalizer.Form.NFC
+ )
+ )
+ ), "-_()", null
+ )
+ )
+ values.put(STATIONS.LAT, station.lat)
+ values.put(STATIONS.LON, station.lon)
+ values.put(STATIONS.DS100, station.shortCode)
+ values.put(STATIONS.ACTIVE, !station.inactive)
+ if (station.photos!!.size > 0) {
+ val (id, photographer, path, _, license, outdated) = station.photos!![0]
+ values.put(STATIONS.PHOTO_ID, id)
+ values.put(STATIONS.PHOTO_URL, photoStations.photoBaseUrl + path)
+ values.put(STATIONS.PHOTOGRAPHER, photographer)
+ values.put(STATIONS.OUTDATED, outdated)
+ values.put(STATIONS.PHOTOGRAPHER_URL, photoStations.getPhotographerUrl(photographer))
+ values.put(STATIONS.LICENSE, photoStations.getLicenseName(license))
+ values.put(STATIONS.LICENSE_URL, photoStations.getLicenseUrl(license))
+ }
+ return values
+ }
+
+ fun insertCountries(countries: List) {
if (countries.isEmpty()) {
- return;
+ return
}
- db.beginTransaction();
+ db!!.beginTransaction()
try {
- deleteCountries();
- countries.forEach(this::insertCountry);
- db.setTransactionSuccessful();
+ deleteCountries()
+ countries.forEach(Consumer { country: Country -> insertCountry(country) })
+ db!!.setTransactionSuccessful()
} finally {
- db.endTransaction();
+ db!!.endTransaction()
}
}
- private void insertCountry(Country country) {
- db.insert(DATABASE_TABLE_COUNTRIES, null, toContentValues(country));
-
- country.getProviderApps().stream()
- .map(p -> toContentValues(country.getCode(), p))
- .forEach(values -> db.insert(DATABASE_TABLE_PROVIDER_APPS, null, values));
+ private fun insertCountry(country: Country) {
+ db!!.insert(DATABASE_TABLE_COUNTRIES, null, toContentValues(country))
+ country.providerApps.stream()
+ .map { p: ProviderApp -> toContentValues(country.code, p) }
+ .forEach { values: ContentValues? ->
+ db!!.insert(
+ DATABASE_TABLE_PROVIDER_APPS,
+ null,
+ values
+ )
+ }
}
- private ContentValues toContentValues(String countryCode, ProviderApp app) {
- var values = new ContentValues();
- values.put(Constants.PROVIDER_APPS.COUNTRYSHORTCODE, countryCode);
- values.put(Constants.PROVIDER_APPS.PA_TYPE, app.getType());
- values.put(Constants.PROVIDER_APPS.PA_NAME, app.getName());
- values.put(Constants.PROVIDER_APPS.PA_URL, app.getUrl());
- return values;
+ private fun toContentValues(countryCode: String, app: ProviderApp): ContentValues {
+ val values = ContentValues()
+ values.put(PROVIDER_APPS.COUNTRYSHORTCODE, countryCode)
+ values.put(PROVIDER_APPS.PA_TYPE, app.type)
+ values.put(PROVIDER_APPS.PA_NAME, app.name)
+ values.put(PROVIDER_APPS.PA_URL, app.url)
+ return values
}
- private ContentValues toContentValues(Country country) {
- var values = new ContentValues();
- values.put(Constants.COUNTRIES.COUNTRYSHORTCODE, country.getCode());
- values.put(Constants.COUNTRIES.COUNTRYNAME, country.getName());
- values.put(Constants.COUNTRIES.EMAIL, country.getEmail());
- values.put(Constants.COUNTRIES.TIMETABLE_URL_TEMPLATE, country.getTimetableUrlTemplate());
- values.put(Constants.COUNTRIES.OVERRIDE_LICENSE, country.getOverrideLicense());
- return values;
+ private fun toContentValues(country: Country): ContentValues {
+ val values = ContentValues()
+ values.put(COUNTRIES.COUNTRYSHORTCODE, country.code)
+ values.put(COUNTRIES.COUNTRYNAME, country.name)
+ values.put(COUNTRIES.EMAIL, country.email)
+ values.put(COUNTRIES.TIMETABLE_URL_TEMPLATE, country.timetableUrlTemplate)
+ values.put(COUNTRIES.OVERRIDE_LICENSE, country.overrideLicense)
+ return values
}
- public Upload insertUpload(Upload upload) {
- upload.setId(db.insert(DATABASE_TABLE_UPLOADS, null, toContentValues(upload)));
- return upload;
+ fun insertUpload(upload: Upload): Upload {
+ upload.id = db!!.insert(DATABASE_TABLE_UPLOADS, null, toContentValues(upload))
+ return upload
}
- public void deleteStations(Set countryCodes) {
- db.delete(DATABASE_TABLE_STATIONS, whereCountryCodeIn(countryCodes), null);
+ fun deleteStations(countryCodes: Set?) {
+ db!!.delete(DATABASE_TABLE_STATIONS, whereCountryCodeIn(countryCodes), null)
}
- public void deleteCountries() {
- db.delete(DATABASE_TABLE_PROVIDER_APPS, null, null);
- db.delete(DATABASE_TABLE_COUNTRIES, null, null);
+ fun deleteCountries() {
+ db!!.delete(DATABASE_TABLE_PROVIDER_APPS, null, null)
+ db!!.delete(DATABASE_TABLE_COUNTRIES, null, null)
}
- private String getStationOrderBy(boolean sortByDistance, Location myPos) {
- var orderBy = Constants.STATIONS.TITLE + " ASC";
-
+ private fun getStationOrderBy(sortByDistance: Boolean, myPos: Location?): String {
+ var orderBy = STATIONS.TITLE + " ASC"
if (sortByDistance) {
- var fudge = Math.pow(Math.cos(Math.toRadians(myPos.getLatitude())), 2);
- orderBy = "((" + myPos.getLatitude() + " - " + Constants.STATIONS.LAT + ") * (" + myPos.getLatitude() + " - " + Constants.STATIONS.LAT + ") + " +
- "(" + myPos.getLongitude() + " - " + Constants.STATIONS.LON + ") * (" + myPos.getLongitude() + " - " + Constants.STATIONS.LON + ") * " + fudge + ")";
- }
-
- return orderBy;
- }
-
- public Cursor getCountryList() {
- var selectCountries = "SELECT " + Constants.COUNTRIES.ROWID_COUNTRIES + " AS " + Constants.CURSOR_ADAPTER_ID + ", " +
- Constants.COUNTRIES.COUNTRYSHORTCODE + ", " + Constants.COUNTRIES.COUNTRYNAME +
- " FROM " + DATABASE_TABLE_COUNTRIES + " ORDER BY " + Constants.COUNTRIES.COUNTRYNAME + " ASC";
- Log.d(TAG, selectCountries);
-
- var cursor = db.rawQuery(selectCountries, null);
-
- if (!cursor.moveToFirst()) {
- cursor.close();
- return null;
+ val fudge = Math.pow(
+ Math.cos(
+ Math.toRadians(
+ myPos!!.latitude
+ )
+ ), 2.0
+ )
+ orderBy =
+ "((" + myPos.latitude + " - " + STATIONS.LAT + ") * (" + myPos.latitude + " - " + STATIONS.LAT + ") + " +
+ "(" + myPos.longitude + " - " + STATIONS.LON + ") * (" + myPos.longitude + " - " + STATIONS.LON + ") * " + fudge + ")"
+ }
+ return orderBy
+ }
+
+ val countryList: Cursor?
+ get() {
+ val selectCountries =
+ "SELECT " + COUNTRIES.ROWID_COUNTRIES + " AS " + Constants.CURSOR_ADAPTER_ID + ", " +
+ COUNTRIES.COUNTRYSHORTCODE + ", " + COUNTRIES.COUNTRYNAME +
+ " FROM " + DATABASE_TABLE_COUNTRIES + " ORDER BY " + COUNTRIES.COUNTRYNAME + " ASC"
+ Log.d(TAG, selectCountries)
+ val cursor = db!!.rawQuery(selectCountries, null)
+ if (!cursor.moveToFirst()) {
+ cursor.close()
+ return null
+ }
+ return cursor
}
- return cursor;
- }
-
/**
* Return a cursor on station ids where the station's title matches the given string
@@ -245,536 +198,669 @@ public class DbAdapter {
* @param myPos current location
* @return a Cursor representing the matching results
*/
- public Cursor getStationsListByKeyword(String search, StationFilter stationFilter, Set countryCodes, boolean sortByDistance, Location myPos) {
- var selectQuery = whereCountryCodeIn(countryCodes);
- var queryArgs = new ArrayList();
-
+ fun getStationsListByKeyword(
+ search: String?,
+ stationFilter: StationFilter?,
+ countryCodes: Set?,
+ sortByDistance: Boolean,
+ myPos: Location?
+ ): Cursor? {
+ var selectQuery = whereCountryCodeIn(countryCodes)
+ val queryArgs = ArrayList()
if (StringUtils.isNotBlank(search)) {
- selectQuery += String.format(" AND %s LIKE ?", Constants.STATIONS.NORMALIZED_TITLE);
- queryArgs.add("%" + StringUtils.replaceChars(StringUtils.stripAccents(StringUtils.trimToEmpty(search)), " -_()", "%%%%%") + "%");
+ selectQuery += String.format(" AND %s LIKE ?", STATIONS.NORMALIZED_TITLE)
+ queryArgs.add(
+ "%" + StringUtils.replaceChars(
+ StringUtils.stripAccents(
+ StringUtils.trimToEmpty(
+ search
+ )
+ ), " -_()", "%%%%%"
+ ) + "%"
+ )
}
-
if (stationFilter.getNickname() != null) {
- selectQuery += " AND " + Constants.STATIONS.PHOTOGRAPHER + " = ?";
- queryArgs.add(stationFilter.getNickname());
- }
- if (stationFilter.hasPhoto() != null) {
- selectQuery += " AND " + Constants.STATIONS.PHOTO_URL + " IS " + (stationFilter.hasPhoto() ? "NOT" : "") + " NULL";
- }
- if (stationFilter.isActive() != null) {
- selectQuery += " AND " + Constants.STATIONS.ACTIVE + " = ?";
- queryArgs.add(stationFilter.isActive() ? "1" : "0");
- }
-
- Log.w(TAG, selectQuery);
-
- var cursor = db.query(DATABASE_TABLE_STATIONS,
- new String[]{
- Constants.STATIONS.ROWID + " AS " + Constants.CURSOR_ADAPTER_ID,
- Constants.STATIONS.ID,
- Constants.STATIONS.TITLE,
- Constants.STATIONS.PHOTO_URL,
- Constants.STATIONS.COUNTRY
- },
- selectQuery,
- queryArgs.toArray(new String[0]), null, null, getStationOrderBy(sortByDistance, myPos));
-
+ selectQuery += " AND " + STATIONS.PHOTOGRAPHER + " = ?"
+ queryArgs.add(stationFilter.getNickname())
+ }
+ if (stationFilter!!.hasPhoto() != null) {
+ selectQuery += " AND " + STATIONS.PHOTO_URL + " IS " + (if (stationFilter.hasPhoto()!!) "NOT" else "") + " NULL"
+ }
+ if (stationFilter.isActive != null) {
+ selectQuery += " AND " + STATIONS.ACTIVE + " = ?"
+ queryArgs.add(if (stationFilter.isActive) "1" else "0")
+ }
+ Log.w(TAG, selectQuery)
+ val cursor = db!!.query(
+ DATABASE_TABLE_STATIONS, arrayOf(
+ STATIONS.ROWID + " AS " + Constants.CURSOR_ADAPTER_ID,
+ STATIONS.ID,
+ STATIONS.TITLE,
+ STATIONS.PHOTO_URL,
+ STATIONS.COUNTRY
+ ),
+ selectQuery,
+ queryArgs.toTypedArray(), null, null, getStationOrderBy(sortByDistance, myPos)
+ )
if (!cursor.moveToFirst()) {
- Log.w(TAG, String.format("Query '%s' returned no result", search));
- cursor.close();
- return null;
+ Log.w(TAG, String.format("Query '%s' returned no result", search))
+ cursor.close()
+ return null
}
- return cursor;
+ return cursor
}
- private String whereCountryCodeIn(Set countryCodes) {
- return Constants.STATIONS.COUNTRY +
+ private fun whereCountryCodeIn(countryCodes: Set?): String {
+ return STATIONS.COUNTRY +
" IN (" +
- countryCodes.stream().map(c -> "'" + c + "'").collect(joining(",")) +
- ")";
+ countryCodes!!.stream().map { c: String? -> "'$c'" }
+ .collect(Collectors.joining(",")) +
+ ")"
}
- public Statistic getStatistic(String country) {
- try (var cursor = db.rawQuery("SELECT COUNT(*), COUNT(" + Constants.STATIONS.PHOTO_URL + "), COUNT(DISTINCT(" + Constants.STATIONS.PHOTOGRAPHER + ")) FROM " + DATABASE_TABLE_STATIONS + " WHERE " + Constants.STATIONS.COUNTRY + " = ?", new String[]{country})) {
+ fun getStatistic(country: String?): Statistic? {
+ db!!.rawQuery(
+ "SELECT COUNT(*), COUNT(" + STATIONS.PHOTO_URL + "), COUNT(DISTINCT(" + STATIONS.PHOTOGRAPHER + ")) FROM " + DATABASE_TABLE_STATIONS + " WHERE " + STATIONS.COUNTRY + " = ?",
+ arrayOf(country)
+ ).use { cursor ->
if (cursor.moveToNext()) {
- return new Statistic(cursor.getInt(0),
- cursor.getInt(1),
- cursor.getInt(0) - cursor.getInt(1),
- cursor.getInt(2));
+ return Statistic(
+ cursor.getInt(0),
+ cursor.getInt(1),
+ cursor.getInt(0) - cursor.getInt(1),
+ cursor.getInt(2)
+ )
}
}
- return null;
+ return null
}
- public String[] getPhotographerNicknames() {
- var photographers = new ArrayList();
- try (var cursor = db.rawQuery("SELECT distinct " + Constants.STATIONS.PHOTOGRAPHER + " FROM " + DATABASE_TABLE_STATIONS + " WHERE " + Constants.STATIONS.PHOTOGRAPHER + " IS NOT NULL ORDER BY " + Constants.STATIONS.PHOTOGRAPHER, null)) {
- while (cursor.moveToNext()) {
- photographers.add(cursor.getString(0));
+ val photographerNicknames: Array
+ get() {
+ val photographers = ArrayList()
+ db!!.rawQuery(
+ "SELECT distinct " + STATIONS.PHOTOGRAPHER + " FROM " + DATABASE_TABLE_STATIONS + " WHERE " + STATIONS.PHOTOGRAPHER + " IS NOT NULL ORDER BY " + STATIONS.PHOTOGRAPHER,
+ null
+ ).use { cursor ->
+ while (cursor.moveToNext()) {
+ photographers.add(cursor.getString(0))
+ }
}
+ return photographers.toTypedArray()
}
- return photographers.toArray(new String[0]);
- }
- public int countStations(Set countryCodes) {
- try (var query = db.rawQuery("SELECT COUNT(*) FROM " + DATABASE_TABLE_STATIONS + " WHERE " + whereCountryCodeIn(countryCodes), null)) {
+ fun countStations(countryCodes: Set?): Int {
+ db!!.rawQuery(
+ "SELECT COUNT(*) FROM " + DATABASE_TABLE_STATIONS + " WHERE " + whereCountryCodeIn(
+ countryCodes
+ ), null
+ ).use { query ->
if (query.moveToFirst()) {
- return query.getInt(0);
+ return query.getInt(0)
}
}
- return 0;
+ return 0
}
- public void updateUpload(Upload upload) {
- db.beginTransaction();
+ fun updateUpload(upload: Upload?) {
+ db!!.beginTransaction()
try {
- db.update(DATABASE_TABLE_UPLOADS, toContentValues(upload), Constants.UPLOADS.ID + " = ?", new String[]{String.valueOf(upload.getId())});
- db.setTransactionSuccessful();
+ db!!.update(
+ DATABASE_TABLE_UPLOADS, toContentValues(upload), UPLOADS.ID + " = ?", arrayOf(
+ upload!!.id.toString()
+ )
+ )
+ db!!.setTransactionSuccessful()
} finally {
- db.endTransaction();
- }
- }
-
- private ContentValues toContentValues(Upload upload) {
- var values = new ContentValues();
- values.put(Constants.UPLOADS.COMMENT, upload.getComment());
- values.put(Constants.UPLOADS.COUNTRY, upload.getCountry());
- values.put(Constants.UPLOADS.CREATED_AT, upload.getCreatedAt());
- values.put(Constants.UPLOADS.INBOX_URL, upload.getInboxUrl());
- values.put(Constants.UPLOADS.LAT, upload.getLat());
- values.put(Constants.UPLOADS.LON, upload.getLon());
- values.put(Constants.UPLOADS.PROBLEM_TYPE, upload.getProblemType() != null ? upload.getProblemType().name() : null);
- values.put(Constants.UPLOADS.REJECTED_REASON, upload.getRejectReason());
- values.put(Constants.UPLOADS.REMOTE_ID, upload.getRemoteId());
- values.put(Constants.UPLOADS.STATION_ID, upload.getStationId());
- values.put(Constants.UPLOADS.TITLE, upload.getTitle());
- values.put(Constants.UPLOADS.UPLOAD_STATE, upload.getUploadState().name());
- values.put(Constants.UPLOADS.ACTIVE, upload.getActive());
- values.put(Constants.UPLOADS.CRC32, upload.getCrc32());
- values.put(Constants.UPLOADS.REMOTE_ID, upload.getRemoteId());
- return values;
- }
-
- public List getPendingUploadsForStation(Station station) {
- var uploads = new ArrayList();
- try (var cursor = db.query(DATABASE_TABLE_UPLOADS, null, Constants.UPLOADS.COUNTRY + " = ? AND " + Constants.UPLOADS.STATION_ID + " = ? AND " + getPendingUploadWhereClause(),
- new String[]{station.getCountry(), station.getId()}, null, null, Constants.UPLOADS.CREATED_AT + " DESC")) {
+ db!!.endTransaction()
+ }
+ }
+
+ private fun toContentValues(upload: Upload?): ContentValues {
+ val values = ContentValues()
+ values.put(UPLOADS.COMMENT, upload!!.comment)
+ values.put(UPLOADS.COUNTRY, upload.country)
+ values.put(UPLOADS.CREATED_AT, upload.createdAt)
+ values.put(UPLOADS.INBOX_URL, upload.inboxUrl)
+ values.put(UPLOADS.LAT, upload.lat)
+ values.put(UPLOADS.LON, upload.lon)
+ values.put(
+ UPLOADS.PROBLEM_TYPE,
+ if (upload.problemType != null) upload.problemType!!.name else null
+ )
+ values.put(UPLOADS.REJECTED_REASON, upload.rejectReason)
+ values.put(UPLOADS.REMOTE_ID, upload.remoteId)
+ values.put(UPLOADS.STATION_ID, upload.stationId)
+ values.put(UPLOADS.TITLE, upload.title)
+ values.put(UPLOADS.UPLOAD_STATE, upload.uploadState.name)
+ values.put(UPLOADS.ACTIVE, upload.active)
+ values.put(UPLOADS.CRC32, upload.crc32)
+ values.put(UPLOADS.REMOTE_ID, upload.remoteId)
+ return values
+ }
+
+ fun getPendingUploadsForStation(station: Station): List {
+ val uploads = ArrayList()
+ db!!.query(
+ DATABASE_TABLE_UPLOADS,
+ null,
+ UPLOADS.COUNTRY + " = ? AND " + UPLOADS.STATION_ID + " = ? AND " + pendingUploadWhereClause,
+ arrayOf(station.country, station.id),
+ null,
+ null,
+ UPLOADS.CREATED_AT + " DESC"
+ ).use { cursor ->
while (cursor.moveToNext()) {
- uploads.add(createUploadFromCursor(cursor));
+ uploads.add(createUploadFromCursor(cursor))
}
}
-
- return uploads;
+ return uploads
}
- public Upload getPendingUploadForCoordinates(double lat, double lon) {
- try (var cursor = db.query(DATABASE_TABLE_UPLOADS, null, Constants.UPLOADS.LAT + " = ? AND " + Constants.UPLOADS.LON + " = ? AND " + getPendingUploadWhereClause(),
- new String[]{String.valueOf(lat), String.valueOf(lon)}, null, null, Constants.UPLOADS.CREATED_AT + " DESC")) {
+ fun getPendingUploadForCoordinates(lat: Double, lon: Double): Upload? {
+ db!!.query(
+ DATABASE_TABLE_UPLOADS,
+ null,
+ UPLOADS.LAT + " = ? AND " + UPLOADS.LON + " = ? AND " + pendingUploadWhereClause,
+ arrayOf(lat.toString(), lon.toString()),
+ null,
+ null,
+ UPLOADS.CREATED_AT + " DESC"
+ ).use { cursor ->
if (cursor.moveToFirst()) {
- return createUploadFromCursor(cursor);
+ return createUploadFromCursor(cursor)
}
}
-
- return null;
+ return null
}
- private String getUploadWhereClause(Predicate predicate) {
- return Constants.UPLOADS.UPLOAD_STATE + " IN (" +
+ private fun getUploadWhereClause(predicate: Predicate): String {
+ return UPLOADS.UPLOAD_STATE + " IN (" +
Arrays.stream(UploadState.values())
- .filter(predicate)
- .map(s -> "'" + s.name() + "'")
- .collect(joining(",")) +
- ')';
- }
-
- private String getPendingUploadWhereClause() {
- return getUploadWhereClause(UploadState::isPending);
- }
-
- private String getCompletedUploadWhereClause() {
- return getUploadWhereClause(s -> !s.isPending());
- }
-
- public Cursor getOutbox() {
- var queryBuilder = new SQLiteQueryBuilder();
- queryBuilder.setTables(DATABASE_TABLE_UPLOADS
- + " LEFT JOIN "
- + DATABASE_TABLE_STATIONS
- + " ON "
- + DATABASE_TABLE_STATIONS + "." + Constants.STATIONS.COUNTRY
- + " = "
- + DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.COUNTRY
- + " AND "
- + DATABASE_TABLE_STATIONS + "." + Constants.STATIONS.ID
- + " = "
- + DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.STATION_ID);
- return queryBuilder.query(db, new String[]{
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.ID + " AS " + Constants.CURSOR_ADAPTER_ID,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.REMOTE_ID,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.COUNTRY,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.STATION_ID,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.TITLE,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.UPLOAD_STATE,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.PROBLEM_TYPE,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.COMMENT,
- DATABASE_TABLE_UPLOADS + "." + Constants.UPLOADS.REJECTED_REASON,
- DATABASE_TABLE_STATIONS + "." + Constants.UPLOADS.TITLE + " AS " + Constants.UPLOADS.JOIN_STATION_TITLE
- }, null, null, null, null, Constants.UPLOADS.CREATED_AT + " DESC");
- }
-
- public Upload getUploadById(long id) {
- try (var cursor = db.query(DATABASE_TABLE_UPLOADS, null, Constants.UPLOADS.ID + "=?",
- new String[]{String.valueOf(id)}, null, null, null)) {
+ .filter(predicate)
+ .map { s: UploadState -> "'" + s.name + "'" }
+ .collect(Collectors.joining(",")) +
+ ')'
+ }
+
+ private val pendingUploadWhereClause: String
+ private get() = getUploadWhereClause(UploadState::isPending)
+ private val completedUploadWhereClause: String
+ private get() = getUploadWhereClause { s: UploadState -> !s.isPending }
+ val outbox: Cursor
+ get() {
+ val queryBuilder = SQLiteQueryBuilder()
+ queryBuilder.tables = (DATABASE_TABLE_UPLOADS
+ + " LEFT JOIN "
+ + DATABASE_TABLE_STATIONS
+ + " ON "
+ + DATABASE_TABLE_STATIONS + "." + STATIONS.COUNTRY
+ + " = "
+ + DATABASE_TABLE_UPLOADS + "." + UPLOADS.COUNTRY
+ + " AND "
+ + DATABASE_TABLE_STATIONS + "." + STATIONS.ID
+ + " = "
+ + DATABASE_TABLE_UPLOADS + "." + UPLOADS.STATION_ID)
+ return queryBuilder.query(
+ db, arrayOf(
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.ID + " AS " + Constants.CURSOR_ADAPTER_ID,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.REMOTE_ID,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.COUNTRY,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.STATION_ID,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.TITLE,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.UPLOAD_STATE,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.PROBLEM_TYPE,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.COMMENT,
+ DATABASE_TABLE_UPLOADS + "." + UPLOADS.REJECTED_REASON,
+ DATABASE_TABLE_STATIONS + "." + UPLOADS.TITLE + " AS " + UPLOADS.JOIN_STATION_TITLE
+ ), null, null, null, null, UPLOADS.CREATED_AT + " DESC"
+ )
+ }
+
+ fun getUploadById(id: Long): Upload? {
+ db!!.query(
+ DATABASE_TABLE_UPLOADS,
+ null,
+ UPLOADS.ID + "=?",
+ arrayOf(id.toString()),
+ null,
+ null,
+ null
+ ).use { cursor ->
if (cursor.moveToFirst()) {
- return createUploadFromCursor(cursor);
+ return createUploadFromCursor(cursor)
}
}
-
- return null;
+ return null
}
- public void deleteUpload(long id) {
- db.delete(DATABASE_TABLE_UPLOADS, Constants.UPLOADS.ID + "=?", new String[]{String.valueOf(id)});
+ fun deleteUpload(id: Long) {
+ db!!.delete(DATABASE_TABLE_UPLOADS, UPLOADS.ID + "=?", arrayOf(id.toString()))
}
- public List getPendingUploads(boolean withRemoteId) {
- var selection = getPendingUploadWhereClause();
+ fun getPendingUploads(withRemoteId: Boolean): List {
+ var selection = pendingUploadWhereClause
if (withRemoteId) {
- selection += " AND " + Constants.UPLOADS.REMOTE_ID + " IS NOT NULL";
+ selection += " AND " + UPLOADS.REMOTE_ID + " IS NOT NULL"
}
- var uploads = new ArrayList();
- try (var cursor = db.query(DATABASE_TABLE_UPLOADS, null, selection,
- null, null, null, null)) {
+ val uploads = ArrayList()
+ db!!.query(
+ DATABASE_TABLE_UPLOADS, null, selection,
+ null, null, null, null
+ ).use { cursor ->
while (cursor.moveToNext()) {
- uploads.add(createUploadFromCursor(cursor));
+ uploads.add(createUploadFromCursor(cursor))
}
}
-
- return uploads;
+ return uploads
}
- public void updateUploadStates(List stateQueries) {
- db.beginTransaction();
+ fun updateUploadStates(stateQueries: List) {
+ db!!.beginTransaction()
try {
- stateQueries.forEach(state -> db.update(DATABASE_TABLE_UPLOADS, toUploadStatesContentValues(state), Constants.UPLOADS.REMOTE_ID + " = ?", new String[]{String.valueOf(state.getId())}));
- db.setTransactionSuccessful();
+ stateQueries.forEach(Consumer { state: InboxStateQuery ->
+ db!!.update(
+ DATABASE_TABLE_UPLOADS,
+ toUploadStatesContentValues(state),
+ UPLOADS.REMOTE_ID + " = ?",
+ arrayOf(state.id.toString())
+ )
+ })
+ db!!.setTransactionSuccessful()
} finally {
- db.endTransaction();
+ db!!.endTransaction()
}
}
- private ContentValues toUploadStatesContentValues(InboxStateQuery state) {
- var values = new ContentValues();
- values.put(Constants.UPLOADS.UPLOAD_STATE, state.getState().name());
- values.put(Constants.UPLOADS.REJECTED_REASON, state.getRejectedReason());
- values.put(Constants.UPLOADS.CRC32, state.getCrc32());
- return values;
+ private fun toUploadStatesContentValues(state: InboxStateQuery): ContentValues {
+ val values = ContentValues()
+ values.put(UPLOADS.UPLOAD_STATE, state.state.name)
+ values.put(UPLOADS.REJECTED_REASON, state.rejectedReason)
+ values.put(UPLOADS.CRC32, state.crc32)
+ return values
}
- public List getCompletedUploads() {
- var uploads = new ArrayList();
- try (var cursor = db.query(DATABASE_TABLE_UPLOADS, null,
- Constants.UPLOADS.REMOTE_ID + " IS NOT NULL AND " + getCompletedUploadWhereClause(),
- null, null, null, null)) {
- while (cursor.moveToNext()) {
- uploads.add(createUploadFromCursor(cursor));
+ val completedUploads: List
+ get() {
+ val uploads = ArrayList()
+ db!!.query(
+ DATABASE_TABLE_UPLOADS, null,
+ UPLOADS.REMOTE_ID + " IS NOT NULL AND " + completedUploadWhereClause,
+ null, null, null, null
+ ).use { cursor ->
+ while (cursor.moveToNext()) {
+ uploads.add(createUploadFromCursor(cursor))
+ }
}
+ return uploads
}
- return uploads;
- }
-
- static class DbOpenHelper extends SQLiteOpenHelper {
-
- DbOpenHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ internal class DbOpenHelper(context: Context?) :
+ SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
+ override fun onCreate(db: SQLiteDatabase) {
+ Log.i(TAG, "Creating database")
+ db.execSQL(CREATE_STATEMENT_STATIONS)
+ db.execSQL(CREATE_STATEMENT_STATIONS_IDX)
+ db.execSQL(CREATE_STATEMENT_COUNTRIES)
+ db.execSQL(CREATE_STATEMENT_PROVIDER_APPS)
+ db.execSQL(CREATE_STATEMENT_UPLOADS)
+ Log.i(TAG, "Database structure created.")
}
- @Override
- public void onCreate(SQLiteDatabase db) {
- Log.i(TAG, "Creating database");
- db.execSQL(CREATE_STATEMENT_STATIONS);
- db.execSQL(CREATE_STATEMENT_STATIONS_IDX);
- db.execSQL(CREATE_STATEMENT_COUNTRIES);
- db.execSQL(CREATE_STATEMENT_PROVIDER_APPS);
- db.execSQL(CREATE_STATEMENT_UPLOADS);
- Log.i(TAG, "Database structure created.");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.w(TAG, "Upgrade database from version" + oldVersion + " to " + newVersion);
-
- db.beginTransaction();
-
+ override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
+ Log.w(TAG, "Upgrade database from version$oldVersion to $newVersion")
+ db.beginTransaction()
if (oldVersion < 13) {
// up to version 13 we dropped all tables and recreated them
- db.execSQL(DROP_STATEMENT_STATIONS_IDX);
- db.execSQL(DROP_STATEMENT_STATIONS);
- db.execSQL(DROP_STATEMENT_COUNTRIES);
- db.execSQL(DROP_STATEMENT_PROVIDER_APPS);
- onCreate(db);
+ db.execSQL(DROP_STATEMENT_STATIONS_IDX)
+ db.execSQL(DROP_STATEMENT_STATIONS)
+ db.execSQL(DROP_STATEMENT_COUNTRIES)
+ db.execSQL(DROP_STATEMENT_PROVIDER_APPS)
+ onCreate(db)
} else {
// from now on we need to preserve user data and perform schema changes selectively
-
if (oldVersion < 14) {
- db.execSQL(CREATE_STATEMENT_UPLOADS);
+ db.execSQL(CREATE_STATEMENT_UPLOADS)
}
-
if (oldVersion < 15) {
- db.execSQL(DROP_STATEMENT_STATIONS_IDX);
- db.execSQL(CREATE_STATEMENT_STATIONS_IDX);
+ db.execSQL(DROP_STATEMENT_STATIONS_IDX)
+ db.execSQL(CREATE_STATEMENT_STATIONS_IDX)
}
-
if (oldVersion < 16) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_COUNTRIES + " ADD COLUMN " + Constants.COUNTRIES.OVERRIDE_LICENSE + " TEXT");
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_COUNTRIES + " ADD COLUMN " + COUNTRIES.OVERRIDE_LICENSE + " TEXT")
}
-
if (oldVersion < 17) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_UPLOADS + " ADD COLUMN " + Constants.UPLOADS.ACTIVE + " INTEGER");
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_UPLOADS + " ADD COLUMN " + UPLOADS.ACTIVE + " INTEGER")
}
-
if (oldVersion < 18) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + Constants.STATIONS.NORMALIZED_TITLE + " TEXT");
- db.execSQL("UPDATE " + DATABASE_TABLE_STATIONS + " SET " + Constants.STATIONS.NORMALIZED_TITLE + " = " + Constants.STATIONS.TITLE);
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + STATIONS.NORMALIZED_TITLE + " TEXT")
+ db.execSQL("UPDATE " + DATABASE_TABLE_STATIONS + " SET " + STATIONS.NORMALIZED_TITLE + " = " + STATIONS.TITLE)
}
-
if (oldVersion < 19) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_UPLOADS + " ADD COLUMN " + Constants.UPLOADS.CRC32 + " INTEGER");
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_UPLOADS + " ADD COLUMN " + UPLOADS.CRC32 + " INTEGER")
}
-
if (oldVersion < 20) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + Constants.STATIONS.OUTDATED + " INTEGER");
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + STATIONS.OUTDATED + " INTEGER")
}
-
if (oldVersion < 21) {
- db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + Constants.STATIONS.PHOTO_ID + " INTEGER");
+ db.execSQL("ALTER TABLE " + DATABASE_TABLE_STATIONS + " ADD COLUMN " + STATIONS.PHOTO_ID + " INTEGER")
}
-
}
-
- db.setTransactionSuccessful();
- db.endTransaction();
- }
- }
-
- @NonNull
- private Station createStationFromCursor(@NonNull Cursor cursor) {
- return new Station(
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.COUNTRY)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.TITLE)),
- cursor.getDouble(cursor.getColumnIndexOrThrow(Constants.STATIONS.LAT)),
- cursor.getDouble(cursor.getColumnIndexOrThrow(Constants.STATIONS.LON)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.DS100)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.PHOTO_URL)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.PHOTOGRAPHER)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.PHOTOGRAPHER_URL)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.LICENSE)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.STATIONS.LICENSE_URL)),
- Boolean.TRUE.equals(getBoolean(cursor, Constants.STATIONS.ACTIVE)),
- Boolean.TRUE.equals(getBoolean(cursor, Constants.STATIONS.OUTDATED)),
- cursor.getLong(cursor.getColumnIndexOrThrow(Constants.STATIONS.PHOTO_ID))
- );
- }
-
- @NonNull
- private Country createCountryFromCursor(@NonNull Cursor cursor) {
- return new Country(
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYSHORTCODE)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.COUNTRYNAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.EMAIL)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.TIMETABLE_URL_TEMPLATE)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.COUNTRIES.OVERRIDE_LICENSE)));
- }
-
- @NonNull
- private ProviderApp createProviderAppFromCursor(@NonNull Cursor cursor) {
- return new ProviderApp(
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.PROVIDER_APPS.PA_TYPE)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.PROVIDER_APPS.PA_NAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.PROVIDER_APPS.PA_URL)));
- }
-
- @NonNull
- private Upload createUploadFromCursor(@NonNull Cursor cursor) {
- var upload = new Upload(
- cursor.getLong(cursor.getColumnIndexOrThrow(Constants.UPLOADS.ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.COUNTRY)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.STATION_ID)),
- getLong(cursor, Constants.UPLOADS.REMOTE_ID),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.TITLE)),
- getDouble(cursor, Constants.UPLOADS.LAT),
- getDouble(cursor, Constants.UPLOADS.LON),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.COMMENT)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.INBOX_URL)),
- null,
- cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.REJECTED_REASON)),
- UploadState.UNKNOWN,
- cursor.getLong(cursor.getColumnIndexOrThrow(Constants.UPLOADS.CREATED_AT)),
- getBoolean(cursor, Constants.UPLOADS.ACTIVE),
- getLong(cursor, Constants.UPLOADS.CRC32));
-
- var problemType = cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.PROBLEM_TYPE));
+ db.setTransactionSuccessful()
+ db.endTransaction()
+ }
+ }
+
+ private fun createStationFromCursor(cursor: Cursor): Station {
+ return Station(
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.COUNTRY)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.TITLE)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(STATIONS.LAT)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(STATIONS.LON)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.DS100)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.PHOTO_URL)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.PHOTOGRAPHER)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.PHOTOGRAPHER_URL)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.LICENSE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(STATIONS.LICENSE_URL)),
+ java.lang.Boolean.TRUE == getBoolean(cursor, STATIONS.ACTIVE),
+ java.lang.Boolean.TRUE == getBoolean(cursor, STATIONS.OUTDATED),
+ cursor.getLong(cursor.getColumnIndexOrThrow(STATIONS.PHOTO_ID))
+ )
+ }
+
+ private fun createCountryFromCursor(cursor: Cursor): Country {
+ return Country(
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYSHORTCODE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.COUNTRYNAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.EMAIL)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.TIMETABLE_URL_TEMPLATE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COUNTRIES.OVERRIDE_LICENSE))
+ )
+ }
+
+ private fun createProviderAppFromCursor(cursor: Cursor): ProviderApp {
+ return ProviderApp(
+ cursor.getString(cursor.getColumnIndexOrThrow(PROVIDER_APPS.PA_TYPE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(PROVIDER_APPS.PA_NAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(PROVIDER_APPS.PA_URL))
+ )
+ }
+
+ private fun createUploadFromCursor(cursor: Cursor): Upload {
+ val upload = Upload(
+ cursor.getLong(cursor.getColumnIndexOrThrow(UPLOADS.ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.COUNTRY)),
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.STATION_ID)),
+ getLong(cursor, UPLOADS.REMOTE_ID),
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.TITLE)),
+ getDouble(cursor, UPLOADS.LAT),
+ getDouble(cursor, UPLOADS.LON),
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.COMMENT)),
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.INBOX_URL)),
+ null,
+ cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.REJECTED_REASON)),
+ UploadState.UNKNOWN,
+ cursor.getLong(cursor.getColumnIndexOrThrow(UPLOADS.CREATED_AT)),
+ getBoolean(cursor, UPLOADS.ACTIVE),
+ getLong(cursor, UPLOADS.CRC32)
+ )
+ val problemType = cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.PROBLEM_TYPE))
if (problemType != null) {
- upload.setProblemType(ProblemType.valueOf(problemType));
+ upload.problemType = ProblemType.valueOf(problemType)
}
- var uploadState = cursor.getString(cursor.getColumnIndexOrThrow(Constants.UPLOADS.UPLOAD_STATE));
+ val uploadState = cursor.getString(cursor.getColumnIndexOrThrow(UPLOADS.UPLOAD_STATE))
if (uploadState != null) {
- upload.setUploadState(UploadState.valueOf(uploadState));
+ upload.uploadState = UploadState.valueOf(uploadState)
}
-
- return upload;
+ return upload
}
- private Boolean getBoolean(Cursor cursor, String columnName) {
- if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
- return cursor.getInt(cursor.getColumnIndexOrThrow(columnName)) == 1;
- }
- return null;
+ private fun getBoolean(cursor: Cursor, columnName: String?): Boolean? {
+ return if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
+ cursor.getInt(cursor.getColumnIndexOrThrow(columnName)) == 1
+ } else null
}
- private Double getDouble(final Cursor cursor, final String columnName) {
- if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
- return cursor.getDouble(cursor.getColumnIndexOrThrow(columnName));
- }
- return null;
+ private fun getDouble(cursor: Cursor, columnName: String?): Double? {
+ return if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
+ cursor.getDouble(cursor.getColumnIndexOrThrow(columnName))
+ } else null
}
- private Long getLong(final Cursor cursor, final String columnName) {
- if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
- return cursor.getLong(cursor.getColumnIndexOrThrow(columnName));
- }
- return null;
+ private fun getLong(cursor: Cursor, columnName: String?): Long? {
+ return if (!cursor.isNull(cursor.getColumnIndexOrThrow(columnName))) {
+ cursor.getLong(cursor.getColumnIndexOrThrow(columnName))
+ } else null
}
- public Station fetchStationByRowId(long id) {
- try (var cursor = db.query(DATABASE_TABLE_STATIONS, null, Constants.STATIONS.ROWID + "=?", new String[]{
- id + ""}, null, null, null)) {
+ fun fetchStationByRowId(id: Long): Station? {
+ db!!.query(
+ DATABASE_TABLE_STATIONS, null, STATIONS.ROWID + "=?", arrayOf(
+ id.toString() + ""
+ ), null, null, null
+ ).use { cursor ->
if (cursor.moveToFirst()) {
- return createStationFromCursor(cursor);
+ return createStationFromCursor(cursor)
}
}
- return null;
+ return null
}
- public Station getStationByKey(String country, String id) {
- try (var cursor = db.query(DATABASE_TABLE_STATIONS, null, Constants.STATIONS.COUNTRY + "=? AND " + Constants.STATIONS.ID + "=?",
- new String[]{country, id}, null, null, null)) {
+ fun getStationByKey(country: String?, id: String?): Station? {
+ db!!.query(
+ DATABASE_TABLE_STATIONS,
+ null,
+ STATIONS.COUNTRY + "=? AND " + STATIONS.ID + "=?",
+ arrayOf(country, id),
+ null,
+ null,
+ null
+ ).use { cursor ->
if (cursor.moveToFirst()) {
- return createStationFromCursor(cursor);
+ return createStationFromCursor(cursor)
}
}
- return null;
+ return null
}
- public Station getStationForUpload(Upload upload) {
- try (var cursor = db.query(DATABASE_TABLE_STATIONS, null, Constants.STATIONS.COUNTRY + "=? AND " + Constants.STATIONS.ID + "=?",
- new String[]{upload.getCountry(), upload.getStationId()}, null, null, null)) {
+ fun getStationForUpload(upload: Upload): Station? {
+ db!!.query(
+ DATABASE_TABLE_STATIONS,
+ null,
+ STATIONS.COUNTRY + "=? AND " + STATIONS.ID + "=?",
+ arrayOf(upload.country, upload.stationId),
+ null,
+ null,
+ null
+ ).use { cursor ->
if (cursor.moveToFirst()) {
- return createStationFromCursor(cursor);
+ return createStationFromCursor(cursor)
}
}
- return null;
- }
-
- public Set fetchCountriesWithProviderApps(Set countryCodes) {
- var countryList = countryCodes.stream()
- .map(c -> "'" + c + "'")
- .collect(joining(","));
- var countries = new HashSet();
- try (var cursor = db.query(DATABASE_TABLE_COUNTRIES, null, Constants.COUNTRIES.COUNTRYSHORTCODE + " IN (" + countryList + ")",
- null, null, null, null)) {
+ return null
+ }
+
+ fun fetchCountriesWithProviderApps(countryCodes: Set?): Set {
+ val countryList = countryCodes!!.stream()
+ .map { c: String? -> "'$c'" }
+ .collect(Collectors.joining(","))
+ val countries = HashSet()
+ db!!.query(
+ DATABASE_TABLE_COUNTRIES,
+ null,
+ COUNTRIES.COUNTRYSHORTCODE + " IN (" + countryList + ")",
+ null,
+ null,
+ null,
+ null
+ ).use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
do {
- var country = createCountryFromCursor(cursor);
- countries.add(country);
- try (var cursorPa = db.query(DATABASE_TABLE_PROVIDER_APPS, null, Constants.PROVIDER_APPS.COUNTRYSHORTCODE + " = ?",
- new String[]{country.getCode()}, null, null, null)) {
+ val country = createCountryFromCursor(cursor)
+ countries.add(country)
+ db!!.query(
+ DATABASE_TABLE_PROVIDER_APPS,
+ null,
+ PROVIDER_APPS.COUNTRYSHORTCODE + " = ?",
+ arrayOf(country.code),
+ null,
+ null,
+ null
+ ).use { cursorPa ->
if (cursorPa != null && cursorPa.moveToFirst()) {
do {
- country.getProviderApps().add(createProviderAppFromCursor(cursorPa));
- } while (cursorPa.moveToNext());
+ country.providerApps.add(createProviderAppFromCursor(cursorPa))
+ } while (cursorPa.moveToNext())
}
}
- } while (cursor.moveToNext());
+ } while (cursor.moveToNext())
}
}
-
- return countries;
+ return countries
}
- public List getAllStations(StationFilter stationFilter, Set countryCodes) {
- var stationList = new ArrayList();
- var selectQuery = "SELECT * FROM " + DATABASE_TABLE_STATIONS + " WHERE " + whereCountryCodeIn(countryCodes);
- var queryArgs = new ArrayList();
+ fun getAllStations(stationFilter: StationFilter?, countryCodes: Set?): List {
+ val stationList = ArrayList