Merge pull request #2891 from nextcloud/refactoring/noid/locationRemoveConductor

Replace Controllers with Activities for location+geocoding
This commit is contained in:
Marcel Hibbe 2023-03-30 10:23:54 +02:00 committed by GitHub
commit 9e68be74d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 382 additions and 219 deletions

View File

@ -194,6 +194,14 @@
android:name=".messagesearch.MessageSearchActivity" android:name=".messagesearch.MessageSearchActivity"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity
android:name=".location.LocationPickerActivity"
android:theme="@style/AppTheme" />
<activity
android:name=".location.GeocodingActivity"
android:theme="@style/AppTheme" />
<receiver android:name=".receivers.PackageReplacedReceiver" <receiver android:name=".receivers.PackageReplacedReceiver"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>

View File

@ -134,6 +134,7 @@ import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
import com.nextcloud.talk.jobs.ShareOperationWorker import com.nextcloud.talk.jobs.ShareOperationWorker
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
import com.nextcloud.talk.location.LocationPickerActivity
import com.nextcloud.talk.messagesearch.MessageSearchActivity import com.nextcloud.talk.messagesearch.MessageSearchActivity
import com.nextcloud.talk.models.domain.ReactionAddedModel import com.nextcloud.talk.models.domain.ReactionAddedModel
import com.nextcloud.talk.models.domain.ReactionDeletedModel import com.nextcloud.talk.models.domain.ReactionDeletedModel
@ -1767,13 +1768,9 @@ class ChatController(args: Bundle) :
fun showShareLocationScreen() { fun showShareLocationScreen() {
Log.d(TAG, "showShareLocationScreen") Log.d(TAG, "showShareLocationScreen")
val bundle = Bundle() val intent = Intent(activity, LocationPickerActivity::class.java)
bundle.putString(KEY_ROOM_TOKEN, roomToken) intent.putExtra(KEY_ROOM_TOKEN, roomToken)
router.pushController( activity!!.startActivity(intent)
RouterTransaction.with(LocationPickerController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} }
private fun showConversationInfoScreen() { private fun showConversationInfoScreen() {

View File

@ -18,32 +18,33 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.nextcloud.talk.controllers package com.nextcloud.talk.location
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.InputType import android.text.InputType
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.MenuItemCompat import androidx.core.view.MenuItemCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import autodagger.AutoInjector import autodagger.AutoInjector
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.adapters.GeocodingAdapter import com.nextcloud.talk.adapters.GeocodingAdapter
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.base.BaseController import com.nextcloud.talk.databinding.ActivityGeocodingBinding
import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.databinding.ControllerGeocodingBinding
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import fr.dudie.nominatim.client.TalkJsonNominatimClient import fr.dudie.nominatim.client.TalkJsonNominatimClient
import fr.dudie.nominatim.model.Address import fr.dudie.nominatim.model.Address
@ -57,13 +58,11 @@ import org.osmdroid.config.Configuration
import javax.inject.Inject import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class GeocodingController(args: Bundle) : class GeocodingActivity :
BaseController( BaseActivity(),
R.layout.controller_geocoding,
args
),
SearchView.OnQueryTextListener { SearchView.OnQueryTextListener {
private val binding: ControllerGeocodingBinding? by viewBinding(ControllerGeocodingBinding::bind)
private lateinit var binding: ActivityGeocodingBinding
@Inject @Inject
lateinit var ncApi: NcApi lateinit var ncApi: NcApi
@ -71,7 +70,7 @@ class GeocodingController(args: Bundle) :
@Inject @Inject
lateinit var okHttpClient: OkHttpClient lateinit var okHttpClient: OkHttpClient
var roomToken: String? lateinit var roomToken: String
var nominatimClient: TalkJsonNominatimClient? = null var nominatimClient: TalkJsonNominatimClient? = null
var searchItem: MenuItem? = null var searchItem: MenuItem? = null
@ -81,52 +80,89 @@ class GeocodingController(args: Bundle) :
lateinit var adapter: GeocodingAdapter lateinit var adapter: GeocodingAdapter
private var geocodingResults: List<Address> = ArrayList() private var geocodingResults: List<Address> = ArrayList()
constructor(args: Bundle, listener: LocationPickerController) : this(args) { override fun onCreate(savedInstanceState: Bundle?) {
targetController = listener super.onCreate(savedInstanceState)
}
init {
setHasOptionsMenu(true)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
binding = ActivityGeocodingBinding.inflate(layoutInflater)
setupActionBar()
setupSystemColors()
setContentView(binding.root)
Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context)) Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
query = args.getString(BundleKeys.KEY_GEOCODING_QUERY)
roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN) roomToken = intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN)!!
query = intent.getStringExtra(BundleKeys.KEY_GEOCODING_QUERY)
} }
private fun initAdapter(addresses: List<Address>) { override fun onStart() {
adapter = GeocodingAdapter(binding?.geocodingResults?.context!!, addresses) super.onStart()
binding?.geocodingResults?.adapter = adapter
}
override fun onAttach(view: View) {
super.onAttach(view)
initAdapter(geocodingResults) initAdapter(geocodingResults)
initGeocoder() initGeocoder()
}
override fun onResume() {
super.onResume()
if (!query.isNullOrEmpty()) { if (!query.isNullOrEmpty()) {
searchLocation() searchLocation()
} else { } else {
Log.e(TAG, "search string that was passed to GeocodingController was null or empty") Log.e(TAG, "search string that was passed to GeocodingController was null or empty")
} }
binding?.geocodingResults?.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> binding.geocodingResults.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
val address: Address = adapter.getItem(position) as Address val address: Address = adapter.getItem(position) as Address
val listener: GeocodingResultListener? = targetController as GeocodingResultListener? val geocodingResult = GeocodingResult(address.latitude, address.longitude, address.displayName)
listener?.receiveChosenGeocodingResult(address.latitude, address.longitude, address.displayName)
router.popCurrentController() val intent = Intent(this, LocationPickerActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken)
intent.putExtra(BundleKeys.KEY_GEOCODING_RESULT, geocodingResult)
startActivity(intent)
} }
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { private fun setupActionBar() {
super.onCreateOptionsMenu(menu, inflater) setSupportActionBar(binding.geocodingToolbar)
inflater.inflate(R.menu.menu_geocoding, menu) binding.geocodingToolbar.setNavigationOnClickListener {
onBackPressed()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(R.color.transparent)))
supportActionBar?.title = ""
}
private fun setupSystemColors() {
DisplayUtils.applyColorToStatusBar(
this,
ResourcesCompat.getColor(
resources,
R.color.appbar,
null
)
)
DisplayUtils.applyColorToNavigationBar(
this.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null)
)
}
private fun initAdapter(addresses: List<Address>) {
adapter = GeocodingAdapter(binding.geocodingResults.context!!, addresses)
binding.geocodingResults.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.menu_geocoding, menu)
searchItem = menu.findItem(R.id.geocoding_action_search) searchItem = menu.findItem(R.id.geocoding_action_search)
initSearchView() initSearchView()
searchItem?.expandActionView() searchItem?.expandActionView()
searchView?.setQuery(query, false) searchView?.setQuery(query, false)
searchView?.clearFocus() searchView?.clearFocus()
return true
} }
override fun onQueryTextSubmit(query: String?): Boolean { override fun onQueryTextSubmit(query: String?): Boolean {
@ -141,38 +177,39 @@ class GeocodingController(args: Bundle) :
} }
private fun initSearchView() { private fun initSearchView() {
if (activity != null) { val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager if (searchItem != null) {
if (searchItem != null) { searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView = MenuItemCompat.getActionView(searchItem) as SearchView searchView?.maxWidth = Int.MAX_VALUE
searchView?.maxWidth = Int.MAX_VALUE searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) { imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
}
searchView?.imeOptions = imeOptions
searchView?.queryHint = resources!!.getString(R.string.nc_search)
searchView?.setSearchableInfo(searchManager.getSearchableInfo(activity!!.componentName))
searchView?.setOnQueryTextListener(this)
searchItem?.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
return true
}
override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
router.popCurrentController()
return true
}
})
} }
searchView?.imeOptions = imeOptions
searchView?.queryHint = resources!!.getString(R.string.nc_search)
searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView?.setOnQueryTextListener(this)
searchItem?.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
return true
}
override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
val intent = Intent(context, LocationPickerActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra(BundleKeys.KEY_ROOM_TOKEN, roomToken)
startActivity(intent)
return true
}
})
} }
} }
private fun initGeocoder() { private fun initGeocoder() {
val baseUrl = context!!.getString(R.string.osm_geocoder_url) val baseUrl = getString(R.string.osm_geocoder_url)
val email = context!!.getString(R.string.osm_geocoder_contact) val email = context.getString(R.string.osm_geocoder_contact)
nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email) nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email)
} }
@ -206,11 +243,7 @@ class GeocodingController(args: Bundle) :
} }
} }
interface GeocodingResultListener {
fun receiveChosenGeocodingResult(lat: Double, lon: Double, name: String)
}
companion object { companion object {
private const val TAG = "GeocodingController" private val TAG = GeocodingActivity::class.java.simpleName
} }
} }

View File

@ -0,0 +1,31 @@
/*
* Nextcloud Talk application
*
* @author Marcel Hibbe
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.location
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class GeocodingResult(
val lat: Double,
val lon: Double,
var displayName: String
) : Parcelable

View File

@ -18,11 +18,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.nextcloud.talk.controllers package com.nextcloud.talk.location
import android.Manifest import android.Manifest
import android.app.Activity
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.location.Location import android.location.Location
@ -33,7 +35,6 @@ import android.os.Bundle
import android.text.InputType import android.text.InputType
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
@ -44,19 +45,17 @@ import androidx.core.content.res.ResourcesCompat
import androidx.core.view.MenuItemCompat import androidx.core.view.MenuItemCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import autodagger.AutoInjector import autodagger.AutoInjector
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.base.BaseController import com.nextcloud.talk.databinding.ActivityLocationBinding
import com.nextcloud.talk.controllers.util.viewBinding
import com.nextcloud.talk.databinding.ControllerLocationBinding
import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_GEOCODING_RESULT
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import fr.dudie.nominatim.client.TalkJsonNominatimClient import fr.dudie.nominatim.client.TalkJsonNominatimClient
import fr.dudie.nominatim.model.Address import fr.dudie.nominatim.model.Address
@ -82,15 +81,12 @@ import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
import javax.inject.Inject import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class LocationPickerController(args: Bundle) : class LocationPickerActivity :
BaseController( BaseActivity(),
R.layout.controller_location,
args
),
SearchView.OnQueryTextListener, SearchView.OnQueryTextListener,
LocationListener, LocationListener {
GeocodingController.GeocodingResultListener {
private val binding: ControllerLocationBinding? by viewBinding(ControllerLocationBinding::bind) private lateinit var binding: ActivityLocationBinding
@Inject @Inject
lateinit var ncApi: NcApi lateinit var ncApi: NcApi
@ -103,38 +99,121 @@ class LocationPickerController(args: Bundle) :
var nominatimClient: TalkJsonNominatimClient? = null var nominatimClient: TalkJsonNominatimClient? = null
var roomToken: String? lateinit var roomToken: String
var geocodingResult: GeocodingResult? = null
var myLocation: GeoPoint = GeoPoint(COORDINATE_ZERO, COORDINATE_ZERO) var myLocation: GeoPoint = GeoPoint(COORDINATE_ZERO, COORDINATE_ZERO)
private var locationManager: LocationManager? = null private var locationManager: LocationManager? = null
private lateinit var locationOverlay: MyLocationNewOverlay private lateinit var locationOverlay: MyLocationNewOverlay
var moveToCurrentLocationWasClicked: Boolean = true var moveToCurrentLocation: Boolean = true
var readyToShareLocation: Boolean = false var readyToShareLocation: Boolean = false
private var mapCenterLat: Double = 0.0
private var mapCenterLon: Double = 0.0
var searchItem: MenuItem? = null var searchItem: MenuItem? = null
var searchView: SearchView? = null var searchView: SearchView? = null
var receivedChosenGeocodingResult: Boolean = false override fun onCreate(savedInstanceState: Bundle?) {
var geocodedLat: Double = 0.0 super.onCreate(savedInstanceState)
var geocodedLon: Double = 0.0
var geocodedName: String = ""
init {
setHasOptionsMenu(true)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
roomToken = args.getString(KEY_ROOM_TOKEN) roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!!
geocodingResult = intent.getParcelableExtra(KEY_GEOCODING_RESULT)
if (savedInstanceState != null) {
moveToCurrentLocation = savedInstanceState.getBoolean("moveToCurrentLocation") == true
mapCenterLat = savedInstanceState.getDouble("mapCenterLat")
mapCenterLon = savedInstanceState.getDouble("mapCenterLon")
geocodingResult = savedInstanceState.getParcelable("geocodingResult")
}
binding = ActivityLocationBinding.inflate(layoutInflater)
setupActionBar()
setupSystemColors()
setContentView(binding.root)
getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
} }
override fun onAttach(view: View) { override fun onStart() {
super.onAttach(view) super.onStart()
initMap() initMap()
} }
override fun onResume() {
super.onResume()
if (geocodingResult != null) {
moveToCurrentLocation = false
}
setLocationDescription(false, geocodingResult != null)
binding.shareLocation.isClickable = false
binding.shareLocation.setOnClickListener {
if (readyToShareLocation) {
shareLocation(
binding.map.mapCenter?.latitude,
binding.map.mapCenter?.longitude,
binding.placeName.text.toString()
)
} else {
Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
}
}
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putBoolean("moveToCurrentLocation", moveToCurrentLocation)
bundle.putDouble("mapCenterLat", binding.map.mapCenter.latitude)
bundle.putDouble("mapCenterLon", binding.map.mapCenter.longitude)
bundle.putParcelable("geocodingResult", geocodingResult)
}
private fun setupActionBar() {
setSupportActionBar(binding.locationPickerToolbar)
binding.locationPickerToolbar.setNavigationOnClickListener {
onBackPressed()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent)))
supportActionBar?.title = context.getString(R.string.nc_share_location)
}
private fun setupSystemColors() {
DisplayUtils.applyColorToStatusBar(
this,
ResourcesCompat.getColor(
resources,
R.color.appbar,
null
)
)
DisplayUtils.applyColorToNavigationBar(
this.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null)
)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.menu_locationpicker, menu)
return true
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
super.onPrepareOptionsMenu(menu)
searchItem = menu.findItem(R.id.location_action_search)
initSearchView()
return true
}
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
override fun onDetach(view: View) { override fun onStop() {
super.onDetach(view) super.onStop()
try { try {
locationManager!!.removeUpdates(this) locationManager!!.removeUpdates(this)
@ -145,68 +224,29 @@ class LocationPickerController(args: Bundle) :
locationOverlay.disableMyLocation() locationOverlay.disableMyLocation()
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_locationpicker, menu)
searchItem = menu.findItem(R.id.location_action_search)
initSearchView()
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
actionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent)))
actionBar?.title = context!!.getString(R.string.nc_share_location)
}
override val title: String
get() =
resources!!.getString(R.string.nc_share_location)
override fun onViewBound(view: View) {
setLocationDescription(false, receivedChosenGeocodingResult)
binding?.shareLocation?.isClickable = false
binding?.shareLocation?.setOnClickListener {
if (readyToShareLocation) {
shareLocation(
binding?.map?.mapCenter?.latitude,
binding?.map?.mapCenter?.longitude,
binding?.placeName?.text.toString()
)
} else {
Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
}
}
}
private fun initSearchView() { private fun initSearchView() {
if (activity != null) { val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager if (searchItem != null) {
if (searchItem != null) { searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView = MenuItemCompat.getActionView(searchItem) as SearchView searchView?.maxWidth = Int.MAX_VALUE
searchView?.maxWidth = Int.MAX_VALUE searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) { imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
}
searchView?.imeOptions = imeOptions
searchView?.queryHint = resources!!.getString(R.string.nc_search)
searchView?.setSearchableInfo(searchManager.getSearchableInfo(activity!!.componentName))
searchView?.setOnQueryTextListener(this)
} }
searchView?.imeOptions = imeOptions
searchView?.queryHint = resources!!.getString(R.string.nc_search)
searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView?.setOnQueryTextListener(this)
} }
} }
override fun onQueryTextSubmit(query: String?): Boolean { override fun onQueryTextSubmit(query: String?): Boolean {
if (!query.isNullOrEmpty()) { if (!query.isNullOrEmpty()) {
val bundle = Bundle() val intent = Intent(this, GeocodingActivity::class.java)
bundle.putString(BundleKeys.KEY_GEOCODING_QUERY, query) intent.putExtra(BundleKeys.KEY_GEOCODING_QUERY, query)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) intent.putExtra(KEY_ROOM_TOKEN, roomToken)
router.pushController( startActivity(intent)
RouterTransaction.with(GeocodingController(bundle, this))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} }
return true return true
} }
@ -217,10 +257,10 @@ class LocationPickerController(args: Bundle) :
@Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod") @Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod")
private fun initMap() { private fun initMap() {
binding?.map?.setTileSource(TileSourceFactory.MAPNIK) binding.map.setTileSource(TileSourceFactory.MAPNIK)
binding?.map?.onResume() binding.map.onResume()
locationManager = activity!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!isLocationPermissionsGranted()) { if (!isLocationPermissionsGranted()) {
requestLocationPermissions() requestLocationPermissions()
@ -229,12 +269,12 @@ class LocationPickerController(args: Bundle) :
} }
val copyrightOverlay = CopyrightOverlay(context) val copyrightOverlay = CopyrightOverlay(context)
binding?.map?.overlays?.add(copyrightOverlay) binding.map.overlays.add(copyrightOverlay)
binding?.map?.setMultiTouchControls(true) binding.map.setMultiTouchControls(true)
binding?.map?.isTilesScaledToDpi = true binding.map.isTilesScaledToDpi = true
locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding?.map) locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding.map)
locationOverlay.enableMyLocation() locationOverlay.enableMyLocation()
locationOverlay.setPersonHotspot(PERSON_HOT_SPOT_X, PERSON_HOT_SPOT_Y) locationOverlay.setPersonHotspot(PERSON_HOT_SPOT_X, PERSON_HOT_SPOT_Y)
locationOverlay.setPersonIcon( locationOverlay.setPersonIcon(
@ -242,24 +282,28 @@ class LocationPickerController(args: Bundle) :
ResourcesCompat.getDrawable(resources!!, R.drawable.current_location_circle, null) ResourcesCompat.getDrawable(resources!!, R.drawable.current_location_circle, null)
) )
) )
binding?.map?.overlays?.add(locationOverlay) binding.map.overlays.add(locationOverlay)
val mapController = binding?.map?.controller val mapController = binding.map.controller
if (receivedChosenGeocodingResult) { if (geocodingResult != null) {
mapController?.setZoom(ZOOM_LEVEL_RECEIVED_RESULT) mapController.setZoom(ZOOM_LEVEL_RECEIVED_RESULT)
} else { } else {
mapController?.setZoom(ZOOM_LEVEL_DEFAULT) mapController.setZoom(ZOOM_LEVEL_DEFAULT)
} }
val zoomToCurrentPositionOnFirstFix = !receivedChosenGeocodingResult if (mapCenterLat != 0.0 && mapCenterLon != 0.0) {
mapController.setCenter(GeoPoint(mapCenterLat, mapCenterLon))
}
val zoomToCurrentPositionOnFirstFix = geocodingResult == null && moveToCurrentLocation
locationOverlay.runOnFirstFix { locationOverlay.runOnFirstFix {
if (locationOverlay.myLocation != null) { if (locationOverlay.myLocation != null) {
myLocation = locationOverlay.myLocation myLocation = locationOverlay.myLocation
if (zoomToCurrentPositionOnFirstFix) { if (zoomToCurrentPositionOnFirstFix) {
activity!!.runOnUiThread { runOnUiThread {
mapController?.setZoom(ZOOM_LEVEL_DEFAULT) mapController.setZoom(ZOOM_LEVEL_DEFAULT)
mapController?.setCenter(myLocation) mapController.setCenter(myLocation)
} }
} }
} else { } else {
@ -269,20 +313,22 @@ class LocationPickerController(args: Bundle) :
} }
} }
if (receivedChosenGeocodingResult && geocodedLat != COORDINATE_ZERO && geocodedLon != COORDINATE_ZERO) { geocodingResult?.let {
mapController?.setCenter(GeoPoint(geocodedLat, geocodedLon)) if (it.lat != COORDINATE_ZERO && it.lon != COORDINATE_ZERO) {
} mapController.setCenter(GeoPoint(it.lat, it.lon))
binding?.centerMapButton?.setOnClickListener {
if (myLocation.latitude == COORDINATE_ZERO && myLocation.longitude == COORDINATE_ZERO) {
Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
} else {
mapController?.animateTo(myLocation)
moveToCurrentLocationWasClicked = true
} }
} }
binding?.map?.addMapListener( binding.centerMapButton.setOnClickListener {
if (myLocation.latitude == COORDINATE_ZERO && myLocation.longitude == COORDINATE_ZERO) {
Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
} else {
mapController.animateTo(myLocation)
moveToCurrentLocation = true
}
}
binding.map.addMapListener(
delayedMapListener() delayedMapListener()
) )
} }
@ -293,17 +339,17 @@ class LocationPickerController(args: Bundle) :
override fun onScroll(paramScrollEvent: ScrollEvent): Boolean { override fun onScroll(paramScrollEvent: ScrollEvent): Boolean {
try { try {
when { when {
moveToCurrentLocationWasClicked -> { moveToCurrentLocation -> {
setLocationDescription(isGpsLocation = true, isGeocodedResult = false) setLocationDescription(isGpsLocation = true, isGeocodedResult = false)
moveToCurrentLocationWasClicked = false moveToCurrentLocation = false
} }
receivedChosenGeocodingResult -> { geocodingResult != null -> {
binding?.shareLocation?.isClickable = true binding.shareLocation.isClickable = true
setLocationDescription(isGpsLocation = false, isGeocodedResult = true) setLocationDescription(isGpsLocation = false, isGeocodedResult = true)
receivedChosenGeocodingResult = false geocodingResult = null
} }
else -> { else -> {
binding?.shareLocation?.isClickable = true binding.shareLocation.isClickable = true
setLocationDescription(isGpsLocation = false, isGeocodedResult = false) setLocationDescription(isGpsLocation = false, isGeocodedResult = false)
} }
} }
@ -349,35 +395,35 @@ class LocationPickerController(args: Bundle) :
" and there is no alternative like UnifiedNlp installed. Furthermore no GPS is " + " and there is no alternative like UnifiedNlp installed. Furthermore no GPS is " +
"supported." "supported."
) )
Toast.makeText(context, context?.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG) Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG)
.show() .show()
} }
} }
} catch (e: SecurityException) { } catch (e: SecurityException) {
Log.e(TAG, "Error when requesting location updates. Permissions may be missing.", e) Log.e(TAG, "Error when requesting location updates. Permissions may be missing.", e)
Toast.makeText(context, context?.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show() Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Error when requesting location updates.", e) Log.e(TAG, "Error when requesting location updates.", e)
Toast.makeText(context, context?.getString(R.string.nc_common_error_sorry), Toast.LENGTH_LONG).show() Toast.makeText(context, context.getString(R.string.nc_common_error_sorry), Toast.LENGTH_LONG).show()
} }
} }
private fun setLocationDescription(isGpsLocation: Boolean, isGeocodedResult: Boolean) { private fun setLocationDescription(isGpsLocation: Boolean, isGeocodedResult: Boolean) {
when { when {
isGpsLocation -> { isGpsLocation -> {
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_current_location) binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_current_location)
binding?.placeName?.visibility = View.GONE binding.placeName.visibility = View.GONE
binding?.placeName?.text = "" binding.placeName.text = ""
} }
isGeocodedResult -> { isGeocodedResult -> {
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location) binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
binding?.placeName?.visibility = View.VISIBLE binding.placeName.visibility = View.VISIBLE
binding?.placeName?.text = geocodedName binding.placeName.text = geocodingResult?.displayName
} }
else -> { else -> {
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location) binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
binding?.placeName?.visibility = View.GONE binding.placeName.visibility = View.GONE
binding?.placeName?.text = "" binding.placeName.text = ""
} }
} }
} }
@ -395,11 +441,14 @@ class LocationPickerController(args: Bundle) :
} }
private fun executeShareLocation(selectedLat: Double?, selectedLon: Double?, locationName: String?) { private fun executeShareLocation(selectedLat: Double?, selectedLon: Double?, locationName: String?) {
binding.roundedImageView.visibility = View.GONE
binding.sendingLocationProgressbar.visibility = View.VISIBLE
val objectId = "geo:$selectedLat,$selectedLon" val objectId = "geo:$selectedLat,$selectedLon"
var locationNameToShare = locationName var locationNameToShare = locationName
if (locationNameToShare.isNullOrBlank()) { if (locationNameToShare.isNullOrBlank()) {
locationNameToShare = resources?.getString(R.string.nc_shared_location) locationNameToShare = resources.getString(R.string.nc_shared_location)
} }
val metaData: String = val metaData: String =
@ -410,8 +459,8 @@ class LocationPickerController(args: Bundle) :
val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1)) val apiVersion = ApiUtils.getChatApiVersion(currentUser, intArrayOf(1))
ncApi.sendLocation( ncApi.sendLocation(
ApiUtils.getCredentials(currentUser?.username, currentUser?.token), ApiUtils.getCredentials(currentUser.username, currentUser.token),
ApiUtils.getUrlToSendLocation(apiVersion, currentUser?.baseUrl, roomToken), ApiUtils.getUrlToSendLocation(apiVersion, currentUser.baseUrl, roomToken),
"geo-location", "geo-location",
objectId, objectId,
metaData metaData
@ -424,13 +473,13 @@ class LocationPickerController(args: Bundle) :
} }
override fun onNext(t: GenericOverall) { override fun onNext(t: GenericOverall) {
router.popCurrentController() finish()
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
Log.e(TAG, "error when trying to share location", e) Log.e(TAG, "error when trying to share location", e)
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show() Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
router.popCurrentController() finish()
} }
override fun onComplete() { override fun onComplete() {
@ -472,6 +521,8 @@ class LocationPickerController(args: Bundle) :
permissions: Array<out String>, permissions: Array<out String>,
grantResults: IntArray grantResults: IntArray
) { ) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
fun areAllGranted(grantResults: IntArray): Boolean { fun areAllGranted(grantResults: IntArray): Boolean {
grantResults.forEach { grantResults.forEach {
if (it == PackageManager.PERMISSION_DENIED) return false if (it == PackageManager.PERMISSION_DENIED) return false
@ -487,13 +538,6 @@ class LocationPickerController(args: Bundle) :
} }
} }
override fun receiveChosenGeocodingResult(lat: Double, lon: Double, name: String) {
receivedChosenGeocodingResult = true
geocodedLat = lat
geocodedLon = lon
geocodedName = name
}
private fun initGeocoder() { private fun initGeocoder() {
val baseUrl = context!!.getString(R.string.osm_geocoder_url) val baseUrl = context!!.getString(R.string.osm_geocoder_url)
val email = context!!.getString(R.string.osm_geocoder_contact) val email = context!!.getString(R.string.osm_geocoder_contact)
@ -542,8 +586,13 @@ class LocationPickerController(args: Bundle) :
// empty // empty
} }
override fun onBackPressed() {
setResult(Activity.RESULT_CANCELED)
finish()
}
companion object { companion object {
private const val TAG = "LocPicker" private val TAG = LocationPickerActivity::class.java.simpleName
private const val REQUEST_PERMISSIONS_REQUEST_CODE = 1 private const val REQUEST_PERMISSIONS_REQUEST_CODE = 1
private const val PERSON_HOT_SPOT_X: Float = 20.0F private const val PERSON_HOT_SPOT_X: Float = 20.0F
private const val PERSON_HOT_SPOT_Y: Float = 20.0F private const val PERSON_HOT_SPOT_Y: Float = 20.0F

View File

@ -85,4 +85,5 @@ object BundleKeys {
const val KEY_NOTIFICATION_RESTRICT_DELETION = "KEY_NOTIFICATION_RESTRICT_DELETION" const val KEY_NOTIFICATION_RESTRICT_DELETION = "KEY_NOTIFICATION_RESTRICT_DELETION"
const val KEY_DISMISS_RECORDING_URL = "KEY_DISMISS_RECORDING_URL" const val KEY_DISMISS_RECORDING_URL = "KEY_DISMISS_RECORDING_URL"
const val KEY_SHARE_RECORDING_TO_CHAT_URL = "KEY_SHARE_RECORDING_TO_CHAT_URL" const val KEY_SHARE_RECORDING_TO_CHAT_URL = "KEY_SHARE_RECORDING_TO_CHAT_URL"
const val KEY_GEOCODING_RESULT = "KEY_GEOCODING_RESULT"
} }

View File

@ -20,11 +20,30 @@
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent_container" android:id="@+id/parent_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/geocoding_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/geocoding_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/appbar"
android:theme="?attr/actionBarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways"
app:navigationIconTint="@color/fontAppbar"
app:popupTheme="@style/appActionBarPopupMenu"
app:titleTextColor="@color/fontAppbar"
tools:title="@string/nc_app_product_name" />
</com.google.android.material.appbar.AppBarLayout>
<ListView <ListView
android:id="@+id/geocoding_results" android:id="@+id/geocoding_results"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -29,6 +29,23 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/location_picker_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/location_picker_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/appbar"
android:theme="?attr/actionBarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways"
app:navigationIconTint="@color/fontAppbar"
app:popupTheme="@style/appActionBarPopupMenu"
app:titleTextColor="@color/fontAppbar"
tools:title="@string/nc_app_product_name" />
</com.google.android.material.appbar.AppBarLayout>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
@ -92,6 +109,14 @@
android:contentDescription="@null" android:contentDescription="@null"
android:src="@drawable/ic_circular_location" /> android:src="@drawable/ic_circular_location" />
<ProgressBar
android:id="@+id/sending_location_progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone">
</ProgressBar>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"