Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,11 +17,11 @@ android {
targetSdkVersion libs.versions.targetSdkVersion.get().toInteger()
// NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code (Android: 0, WearOS: 1)
// ex) 345100131 = (34, 5.10, 013, 0)
versionCode 375140110
versionName "5.14.0"
versionCode 375140120
versionName "5.14.1"

vectorDrawables {
useSupportLibrary = true
useSupportLibrary true
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ import androidx.core.view.ViewGroupCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePaddingRelative
import androidx.lifecycle.lifecycleScope
import com.google.android.material.R as materialRes
import com.google.android.material.search.SearchView
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.platform.MaterialContainerTransform
Expand All@@ -42,7 +41,6 @@ import com.thewizrd.shared_resources.utils.ContextUtils.getOrientation
import com.thewizrd.shared_resources.utils.ContextUtils.isSmallestWidth
import com.thewizrd.shared_resources.utils.JSONParser
import com.thewizrd.shared_resources.utils.UserThemeMode
import com.thewizrd.simpleweather.R
import com.thewizrd.simpleweather.databinding.ActivityLocationSearchBinding
import com.thewizrd.simpleweather.snackbar.SnackbarWindowAdjustCallback
import kotlinx.coroutines.Job
Expand All@@ -51,6 +49,7 @@ import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import com.google.android.material.R as materialRes

class LocationSearch : ActivityResultContract<Void?, LocationSearchResult>() {
override fun createIntent(context: Context, input: Void?): Intent {
Expand DownExpand Up@@ -138,14 +137,14 @@ class LocationSearchActivity : WindowColorActivity() {
}

// Initialize
binding.searchView.setVisible(true)
binding.searchView.addTransitionListener { _, _, newState ->
binding.locationSearchView.setVisible(true)
binding.locationSearchView.addTransitionListener { _, _, newState ->
if (newState == SearchView.TransitionState.HIDING || newState == SearchView.TransitionState.HIDDEN) {
setResult(RESULT_CANCELED)
onBackPressedDispatcher.onBackPressed()
}
}
binding.searchView.editText.addTextChangedListener(object : TextWatcher {
binding.locationSearchView.editText.addTextChangedListener(object : TextWatcher {
private var textChangedJob: Job? = null

override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
Expand DownExpand Up@@ -177,18 +176,18 @@ class LocationSearchActivity : WindowColorActivity() {
fetchLocations(newText)
}
})
binding.searchView.editText.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ ->
binding.locationSearchView.editText.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
fetchLocations(v.text.toString())
binding.searchView.clearFocusAndHideKeyboard()
binding.locationSearchView.clearFocusAndHideKeyboard()
return@OnEditorActionListener true
}
false
})
binding.searchView.onItemClickListener = recyclerClickListener
binding.locationSearchView.onItemClickListener = recyclerClickListener

val padding = dpToPx(8f).toInt()
binding.searchView.recyclerView.updatePaddingRelative(
binding.locationSearchView.recyclerView.updatePaddingRelative(
start = padding, end = padding, top = padding
)

Expand All@@ -207,13 +206,13 @@ class LocationSearchActivity : WindowColorActivity() {

lifecycleScope.launch {
locationSearchViewModel.isLoading.collect { loading ->
binding.searchView.showLoading(loading)
binding.locationSearchView.showLoading(loading)
}
}

lifecycleScope.launch {
locationSearchViewModel.locations.collectLatest {
binding.searchView.submitList(it)
binding.locationSearchView.submitList(it)
}
}

Expand DownExpand Up@@ -243,11 +242,11 @@ class LocationSearchActivity : WindowColorActivity() {

override fun onResume() {
super.onResume()
binding.searchView.requestFocusAndShowKeyboard()
binding.locationSearchView.requestFocusAndShowKeyboard()
}

override fun onPause() {
binding.searchView.clearFocusAndHideKeyboard()
binding.locationSearchView.clearFocusAndHideKeyboard()
super.onPause()
}

Expand All@@ -274,7 +273,7 @@ class LocationSearchActivity : WindowColorActivity() {
}

binding.root.setBackgroundColor(backgroundColor)
binding.searchView.setBackgroundOverlayColor(backgroundColor)
binding.locationSearchView.setBackgroundOverlayColor(backgroundColor)

window.setTransparentWindow(
backgroundColor, Colors.TRANSPARENT,
Expand All@@ -296,7 +295,7 @@ class LocationSearchActivity : WindowColorActivity() {
}

private fun onErrorMessage(error: ErrorMessage) {
binding.searchView.clearFocusAndHideKeyboard()
binding.locationSearchView.clearFocusAndHideKeyboard()

when (error) {
is ErrorMessage.Resource -> {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_location_search.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@
android:transitionName="shared_element_container">

<com.thewizrd.simpleweather.controls.LocationSearchView
android:id="@+id/search_view"
android:id="@+id/location_search_view"
style="@style/Widget.Material3Expressive.SearchView"
android:layout_width="match_parent"
android:layout_height="match_parent"
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -189,6 +189,7 @@ jjwt-api = { module = "io.jsonwebtoken:jjwt-api", version.ref = "jjwt_version" }
jjwt-impl = { module = "io.jsonwebtoken:jjwt-impl", version.ref = "jjwt_version" }
jjwt-orgjson = { module = "io.jsonwebtoken:jjwt-orgjson", version.ref = "jjwt_version" }
moshi-java-codegen = { module = "com.github.nename0:moshi-java-codegen", version = "1.1.1" }
google-maps-services = { module = "com.google.maps:google-maps-services", version = "2.2.0" }
#noinspection GradleDependency
places = { module = "com.google.android.libraries.places:places", version = "4.4.1" }
volley = { module = "com.android.volley:volley", version = "1.2.1" }
Expand Down
4 changes: 2 additions & 2 deletions wearapp/build.gradle
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,8 +16,8 @@ android {
targetSdkVersion libs.versions.wearTargetSdkVersion.get()
// NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code [Android: 0, WearOS: 1])
// ex) 345100131 = (34, 5.10, 013, 1)
versionCode 365140111
versionName "5.14.0"
versionCode 365140121
versionName "5.14.1"

vectorDrawables {
useSupportLibrary true
Expand Down
5 changes: 5 additions & 0 deletions wearapp/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,11 @@
# -keep class com.crashlytics.** { *; }
# -dontwarn com.crashlytics.**

# ConfirmationData
-keep public enum com.thewizrd.simpleweather.viewmodels.ConfirmationType {
public *;
}

# Moshi
# Keep name of @JsonClass type to lookup generated adapter
-keepnames @com.squareup.moshi.JsonClass class *
Expand Down
1 change: 1 addition & 0 deletions weather-api/build.gradle
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,6 +139,7 @@ dependencies {
implementation libs.moshi.adapters
kapt libs.moshi.java.codegen

fullgmsImplementation libs.google.maps.services
fullgmsImplementation libs.places
fullgmsImplementation libs.volley // Required by Places API ^^^
fullgmsImplementation libs.kotlinx.coroutines.play.services
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,6 +12,12 @@ import com.google.android.libraries.places.api.net.FetchPlaceRequest
import com.google.android.libraries.places.api.net.FetchPlaceResponse
import com.google.android.libraries.places.api.net.FindAutocompletePredictionsRequest
import com.google.android.libraries.places.api.net.PlacesClient
import com.google.maps.GeoApiContext
import com.google.maps.GeocodingApi
import com.google.maps.model.AddressType
import com.google.maps.model.GeocodingResult
import com.google.maps.model.LatLng
import com.google.maps.model.LocationType
import com.thewizrd.shared_resources.exceptions.ErrorStatus
import com.thewizrd.shared_resources.exceptions.WeatherException
import com.thewizrd.shared_resources.locationdata.LocationQuery
Expand DownExpand Up@@ -60,7 +66,7 @@ class GoogleLocationProvider : WeatherLocationProviderImpl() {
}

override fun needsLocationFromName(): Boolean {
return true
return false // Location from ID takes precedence, so this is not required
}

private fun refreshToken() {
Expand All@@ -76,6 +82,10 @@ class GoogleLocationProvider : WeatherLocationProviderImpl() {
return Places.createClient(ctx)
}

private val geoApiContext: GeoApiContext by lazy {
GeoApiContext.Builder().apiKey(getAPIKey()).build()
}

@Throws(WeatherException::class)
override suspend fun getLocations(
ac_query: String?, weatherAPI: String?
Expand DownExpand Up@@ -200,89 +210,101 @@ class GoogleLocationProvider : WeatherLocationProviderImpl() {
return@withContext location
}

override suspend fun getLocationFromName(model: LocationQuery): LocationQuery? {
return null
}

@Throws(WeatherException::class)
override suspend fun getLocationFromName(
model: LocationQuery
override suspend fun getLocation(
coordinate: Coordinate, weatherAPI: String?
): LocationQuery = withContext(Dispatchers.IO) {
if (!isGeocoderAvailable()) {
throw WeatherException(ErrorStatus.NETWORKERROR).apply {
initCause(Exception("Geocoder unavailable"))
}
}

val location: LocationQuery
var result: Address?
var location: LocationQuery? = null
var wEx: WeatherException? = null

try {
val addresses = weatherModule.geocoder.getFromLocationNameAsync(model.locationName!!, 1)

result = addresses[0]
} catch (ex: Exception) {
result = null
if (ex is IOException) {
wEx = WeatherException(ErrorStatus.NETWORKERROR, ex)
} else if (ex is IllegalArgumentException) {
wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex)
}
Logger.writeLine(Log.ERROR, ex, "GoogleLocationProvider: error getting location")
}
if (isGeocoderAvailable()) {
var result: Address?

if (wEx != null) throw wEx
try {
val addresses =
weatherModule.geocoder.getFromLocationAsync(
coordinate.latitude,
coordinate.longitude,
1
)

location = result?.let {
createLocationModel(
it,
model.weatherSource!!
)
}
?: LocationQuery()
result = addresses.firstOrNull()
} catch (ex: Exception) {
result = null
if (ex is IOException) {
wEx = WeatherException(ErrorStatus.NETWORKERROR, ex)
} else if (ex is IllegalArgumentException) {
wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex)
}
Logger.writeLine(
Log.ERROR,
ex,
"GoogleLocationProvider: error getting geocoder location"
)
}

return@withContext location
}
if (wEx != null) throw wEx

@Throws(WeatherException::class)
override suspend fun getLocation(
coordinate: Coordinate, weatherAPI: String?
): LocationQuery = withContext(Dispatchers.IO) {
if (!isGeocoderAvailable()) {
throw WeatherException(ErrorStatus.NETWORKERROR).apply {
initCause(Exception("Geocoder unavailable"))
location = result?.let {
createLocationModel(
it,
weatherAPI
)
}
}

val location: LocationQuery
var result: Address?
var wEx: WeatherException? = null
if (location == null) {
// Fallback to Geocoding API
var result: GeocodingResult?

try {
val addresses =
weatherModule.geocoder.getFromLocationAsync(
coordinate.latitude,
coordinate.longitude,
1
try {
val response = GeocodingApi.reverseGeocode(
geoApiContext,
LatLng(coordinate.latitude, coordinate.longitude)
)
.locationType(LocationType.GEOMETRIC_CENTER)
.resultType(
AddressType.STREET_ADDRESS,
AddressType.ROUTE,
AddressType.NEIGHBORHOOD,
AddressType.SUBLOCALITY,
AddressType.LOCALITY,
AddressType.ADMINISTRATIVE_AREA_LEVEL_1,
AddressType.ADMINISTRATIVE_AREA_LEVEL_2,
AddressType.ADMINISTRATIVE_AREA_LEVEL_3,
AddressType.ADMINISTRATIVE_AREA_LEVEL_4,
AddressType.ADMINISTRATIVE_AREA_LEVEL_5
)
.await()

result = addresses[0]
} catch (ex: Exception) {
result = null
if (ex is IOException) {
wEx = WeatherException(ErrorStatus.NETWORKERROR, ex)
} else if (ex is IllegalArgumentException) {
wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex)
result = response.firstOrNull()
} catch (ex: Exception) {
result = null
if (ex is IOException) {
wEx = WeatherException(ErrorStatus.NETWORKERROR, ex)
} else if (ex is IllegalArgumentException) {
wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex)
}
Logger.writeLine(
Log.ERROR,
ex,
"GoogleLocationProvider: error getting geocoding result"
)
}
Logger.writeLine(Log.ERROR, ex, "GoogleLocationProvider: error getting location")
}

if (wEx != null) throw wEx
if (wEx != null) throw wEx

location = result?.let {
createLocationModel(
it,
weatherAPI
)
location = result?.let {
createLocationModel(
it,
weatherAPI
)
} ?: LocationQuery()
}
?: LocationQuery()

return@withContext location
}
Expand Down
Loading