diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a9e08b..f3fd50d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ - + () private val viewModel: MainViewModel by activityViewModels() - private val editor: NoteEditorViewModel by viewModels { - NoteEditorViewModelFactory( - args.note - ) - } + private val editor: NoteEditorViewModel by viewModels() + + private val gpsRequestCode = 1337 override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View = DataBindingUtil.inflate( - inflater, - R.layout.fragment_note_editor, - container, - false + inflater, + R.layout.fragment_note_editor, + container, + false ).apply { + editor.setInitialNote(args.note) + lifecycleOwner = this@NoteEditorFragment fragment = this@NoteEditorFragment layoutViewModel = this@NoteEditorFragment.editor - }.also { binding -> + enterTransition = MaterialContainerTransform().apply { startView = requireActivity().findViewById(R.id.floatingActionButton) - endView = binding.root + endView = root duration = resources.getInteger(R.integer.notian_animation_time).toLong() scrimColor = Color.TRANSPARENT containerColor = requireContext().themeColor(R.attr.colorSurface) @@ -58,10 +67,50 @@ class NoteEditorFragment : Fragment() { } returnTransition = Slide().apply { duration = resources.getInteger(R.integer.notian_animation_time).toLong() - addTarget(binding.root) + addTarget(root) + } + + noteEditorLocationContainer.setEndIconOnClickListener { + val permission = requireContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + + if (permission != PackageManager.PERMISSION_GRANTED) { + requireActivity().requestPermissions( + arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), + gpsRequestCode + ) + } else { + searchGPS() + } } }.root + @Suppress("JoinDeclarationAndAssignment") // IntelliJ Bug + @SuppressLint("MissingPermission") // Only called if permission is granted + private fun searchGPS() { + val locationManager = requireContext().getSystemService()!! + + lateinit var locationListener: LocationListener + locationListener = LocationListener { + Log.i("NoteEditorFragment", "Received location $it") + editor.receivedGPS(it.latitude, it.longitude) + locationManager.removeUpdates(locationListener) + } + + val provider = locationManager.getBestProvider(Criteria().apply { + this.isCostAllowed = false + this.accuracy = Criteria.ACCURACY_FINE + }, true)!! + Log.i("NoteEditorFragment", "Using provider $provider") + locationManager.requestLocationUpdates(provider, 0L, 0.0f, locationListener) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (requestCode != gpsRequestCode) return + + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) + searchGPS() + } + fun saveNote() { if (editor.localID == 0) viewModel.addNote(editor.note) @@ -73,11 +122,11 @@ class NoteEditorFragment : Fragment() { fun openTimePicker(view: View) { val calendar = Calendar.getInstance() val dialog = TimePickerDialog( - requireContext(), - { _, hour, minute -> editor.setTime(hour, minute) }, - calendar.get(Calendar.HOUR_OF_DAY), - calendar.get(Calendar.MINUTE), - false + requireContext(), + { _, hour, minute -> editor.setTime(hour, minute) }, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + false ) dialog.show() } @@ -85,11 +134,11 @@ class NoteEditorFragment : Fragment() { fun openDatePicker(view: View) { val calendar = Calendar.getInstance() val dialog = DatePickerDialog( - requireContext(), - { _, year, month, day -> editor.setDate(day, month + 1, year) }, - calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.get(Calendar.DAY_OF_MONTH) + requireContext(), + { _, year, month, day -> editor.setDate(day, month + 1, year) }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH) ) dialog.show() } diff --git a/app/src/main/java/me/profiluefter/profinote/models/NoteEditorViewModel.kt b/app/src/main/java/me/profiluefter/profinote/models/NoteEditorViewModel.kt index 61cad50..61f707c 100644 --- a/app/src/main/java/me/profiluefter/profinote/models/NoteEditorViewModel.kt +++ b/app/src/main/java/me/profiluefter/profinote/models/NoteEditorViewModel.kt @@ -2,19 +2,15 @@ package me.profiluefter.profinote.models import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import me.profiluefter.profinote.data.GeocodingService import me.profiluefter.profinote.data.entities.* +import javax.inject.Inject -class NoteEditorViewModelFactory(private val note: Note) : ViewModelProvider.Factory { - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T { - if (!modelClass.isAssignableFrom(NoteEditorViewModel::class.java)) - throw IllegalArgumentException("Unknown ViewModel") - return NoteEditorViewModel(note) as T - } -} - -class NoteEditorViewModel(note: Note) : ViewModel() { +@HiltViewModel +class NoteEditorViewModel @Inject constructor(private val geocodingService: GeocodingService) : ViewModel() { fun setTime(hour: Int, minute: Int) { time.value = formatTime(hour, minute) } @@ -23,19 +19,40 @@ class NoteEditorViewModel(note: Note) : ViewModel() { date.value = formatDate(day, month, year) } - val localID: Int = note.localID - val title: MutableLiveData = MutableLiveData(note.title) - val done: MutableLiveData = MutableLiveData(note.done) - val date: MutableLiveData = MutableLiveData(note.date) - val time: MutableLiveData = MutableLiveData(note.time) - val description: MutableLiveData = MutableLiveData(note.description) + fun receivedGPS(latitude: Double, longitude: Double) { + viewModelScope.launch { + val location = geocodingService.reverse(latitude, longitude) + this@NoteEditorViewModel.location.value = location + this@NoteEditorViewModel.longitude.value = longitude + this@NoteEditorViewModel.latitude.value = latitude + } + } + + fun setInitialNote(note: Note) { + localID = note.localID + title.value = note.title + done.value = note.done + date.value = note.date + time.value = note.time + description.value = note.description + } + + var localID: Int? = null + val title: MutableLiveData = MutableLiveData() + val done: MutableLiveData = MutableLiveData() + val date: MutableLiveData = MutableLiveData() + val time: MutableLiveData = MutableLiveData() + val description: MutableLiveData = MutableLiveData() + val latitude: MutableLiveData = MutableLiveData() + val longitude: MutableLiveData = MutableLiveData() + val location: MutableLiveData = MutableLiveData() val note: Note get() { val (day, month, year) = date.value!!.split(".").map { it.toInt() } val (hour, minute) = time.value!!.split(":").map { it.toInt() } return Note( - localID, + localID!!, title.value!!, done.value!!, minute, @@ -44,9 +61,9 @@ class NoteEditorViewModel(note: Note) : ViewModel() { month, year, description.value!!, - 0.0, - 0.0, - "", + latitude.value!!, + longitude.value!!, + location.value!! ) } } \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/baseline_my_location_black_18.png b/app/src/main/res/drawable-hdpi/baseline_my_location_black_18.png new file mode 100644 index 0000000..4306ce8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_my_location_black_18.png differ diff --git a/app/src/main/res/drawable-hdpi/baseline_my_location_black_20.png b/app/src/main/res/drawable-hdpi/baseline_my_location_black_20.png new file mode 100644 index 0000000..13996da Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_my_location_black_20.png differ diff --git a/app/src/main/res/drawable-hdpi/baseline_my_location_black_24.png b/app/src/main/res/drawable-hdpi/baseline_my_location_black_24.png new file mode 100644 index 0000000..5112422 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_my_location_black_24.png differ diff --git a/app/src/main/res/drawable-hdpi/baseline_my_location_black_36.png b/app/src/main/res/drawable-hdpi/baseline_my_location_black_36.png new file mode 100644 index 0000000..2cbfeec Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_my_location_black_36.png differ diff --git a/app/src/main/res/drawable-hdpi/baseline_my_location_black_48.png b/app/src/main/res/drawable-hdpi/baseline_my_location_black_48.png new file mode 100644 index 0000000..b94a313 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/baseline_my_location_black_48.png differ diff --git a/app/src/main/res/drawable-mdpi/baseline_my_location_black_18.png b/app/src/main/res/drawable-mdpi/baseline_my_location_black_18.png new file mode 100644 index 0000000..def8ab6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_my_location_black_18.png differ diff --git a/app/src/main/res/drawable-mdpi/baseline_my_location_black_20.png b/app/src/main/res/drawable-mdpi/baseline_my_location_black_20.png new file mode 100644 index 0000000..454e126 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_my_location_black_20.png differ diff --git a/app/src/main/res/drawable-mdpi/baseline_my_location_black_24.png b/app/src/main/res/drawable-mdpi/baseline_my_location_black_24.png new file mode 100644 index 0000000..056bbd4 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_my_location_black_24.png differ diff --git a/app/src/main/res/drawable-mdpi/baseline_my_location_black_36.png b/app/src/main/res/drawable-mdpi/baseline_my_location_black_36.png new file mode 100644 index 0000000..5112422 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_my_location_black_36.png differ diff --git a/app/src/main/res/drawable-mdpi/baseline_my_location_black_48.png b/app/src/main/res/drawable-mdpi/baseline_my_location_black_48.png new file mode 100644 index 0000000..5c76e06 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/baseline_my_location_black_48.png differ diff --git a/app/src/main/res/drawable-xhdpi/baseline_my_location_black_18.png b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_18.png new file mode 100644 index 0000000..5112422 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_18.png differ diff --git a/app/src/main/res/drawable-xhdpi/baseline_my_location_black_20.png b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_20.png new file mode 100644 index 0000000..35ac7e9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_20.png differ diff --git a/app/src/main/res/drawable-xhdpi/baseline_my_location_black_24.png b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_24.png new file mode 100644 index 0000000..5c76e06 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_24.png differ diff --git a/app/src/main/res/drawable-xhdpi/baseline_my_location_black_36.png b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_36.png new file mode 100644 index 0000000..b94a313 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_36.png differ diff --git a/app/src/main/res/drawable-xhdpi/baseline_my_location_black_48.png b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_48.png new file mode 100644 index 0000000..746bf58 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/baseline_my_location_black_48.png differ diff --git a/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_18.png b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_18.png new file mode 100644 index 0000000..2cbfeec Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_18.png differ diff --git a/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_20.png b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_20.png new file mode 100644 index 0000000..cb98fc6 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_20.png differ diff --git a/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_24.png b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_24.png new file mode 100644 index 0000000..b94a313 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_24.png differ diff --git a/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_36.png b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_36.png new file mode 100644 index 0000000..1621efd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_36.png differ diff --git a/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_48.png b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_48.png new file mode 100644 index 0000000..58e017d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/baseline_my_location_black_48.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_18.png b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_18.png new file mode 100644 index 0000000..b94a313 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_18.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_20.png b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_20.png new file mode 100644 index 0000000..6df8533 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_20.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_24.png b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_24.png new file mode 100644 index 0000000..746bf58 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_24.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_36.png b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_36.png new file mode 100644 index 0000000..58e017d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_36.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_48.png b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_48.png new file mode 100644 index 0000000..0b8f21e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/baseline_my_location_black_48.png differ diff --git a/app/src/main/res/drawable/baseline_my_location_24.xml b/app/src/main/res/drawable/baseline_my_location_24.xml new file mode 100644 index 0000000..b050330 --- /dev/null +++ b/app/src/main/res/drawable/baseline_my_location_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_note_details.xml b/app/src/main/res/layout/fragment_note_details.xml index acf6b01..2a2978c 100644 --- a/app/src/main/res/layout/fragment_note_details.xml +++ b/app/src/main/res/layout/fragment_note_details.xml @@ -5,6 +5,8 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_note_editor.xml b/app/src/main/res/layout/fragment_note_editor.xml index 5f3af8d..df2db18 100644 --- a/app/src/main/res/layout/fragment_note_editor.xml +++ b/app/src/main/res/layout/fragment_note_editor.xml @@ -84,6 +84,29 @@ app:layout_constraintStart_toEndOf="@+id/noteEditorDate" app:layout_constraintTop_toBottomOf="@+id/noteEditorTitleContainer" /> + + + + + Cancel recycler_view_item_transition_name_%1$s Logout + Location \ No newline at end of file diff --git a/build.gradle b/build.gradle index 32fe0fa..69a092a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext.kotlin_version = "1.4.32" - ext.hilt_version = "2.34-beta" - ext.room_version = "2.2.6" + ext.hilt_version = '2.35' + ext.room_version = '2.3.0' ext.nav_version = "2.3.5" repositories { diff --git a/data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/LocationIQGeocodingService.kt b/data-lib/src/main/java/me/profiluefter/profinote/data/GeocodingService.kt similarity index 77% rename from data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/LocationIQGeocodingService.kt rename to data-lib/src/main/java/me/profiluefter/profinote/data/GeocodingService.kt index ba4d1aa..07f946e 100644 --- a/data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/LocationIQGeocodingService.kt +++ b/data-lib/src/main/java/me/profiluefter/profinote/data/GeocodingService.kt @@ -1,4 +1,4 @@ -package me.profiluefter.profinote.data.geocoding +package me.profiluefter.profinote.data import com.google.gson.Gson import com.google.gson.annotations.SerializedName @@ -16,6 +16,10 @@ import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton +interface GeocodingService { + suspend fun reverse(latitude: Double, longitude: Double): String +} + class LocationIQGeocodingService @Inject constructor( private val api: LocationIQAPI, @Named("locationIQ") @@ -51,4 +55,12 @@ object LocationIQModule { .addConverterFactory(GsonConverterFactory.create(gson)) .build() .create() + + @Provides + @Singleton + fun locationIQGeocoder(locationIQGeocodingService: LocationIQGeocodingService): GeocodingService = locationIQGeocodingService + + @Provides + @Named("locationIQ") + fun apiKeyLocationIQ(): String = "pk.c84c8c163dcf39e91bbfdb75c757ead0" // Throwaway account, not secret } \ No newline at end of file diff --git a/data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/GeocodingService.kt b/data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/GeocodingService.kt deleted file mode 100644 index 249fc48..0000000 --- a/data-lib/src/main/java/me/profiluefter/profinote/data/geocoding/GeocodingService.kt +++ /dev/null @@ -1,5 +0,0 @@ -package me.profiluefter.profinote.data.geocoding - -interface GeocodingService { - suspend fun reverse(latitude: Double, longitude: Double): String -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 98bed16..0bc9d91 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true +org.gradle.parallel=true # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app"s APK # https://developer.android.com/topic/libraries/support-library/androidx-rn