diff --git a/Celestia/src/main/cpp/CMakeLists.txt b/Celestia/src/main/cpp/CMakeLists.txt index 0d21e941..81c33af1 100644 --- a/Celestia/src/main/cpp/CMakeLists.txt +++ b/Celestia/src/main/cpp/CMakeLists.txt @@ -260,6 +260,8 @@ list(APPEND CELESTIA_SOURCES ${CELESTIA_SRC_DIR}/celengine/boundaries.h ${CELESTIA_SRC_DIR}/celengine/category.cpp ${CELESTIA_SRC_DIR}/celengine/category.h + ${CELESTIA_SRC_DIR}/celengine/completion.cpp + ${CELESTIA_SRC_DIR}/celengine/completion.h ${CELESTIA_SRC_DIR}/celengine/console.cpp ${CELESTIA_SRC_DIR}/celengine/console.h ${CELESTIA_SRC_DIR}/celengine/constellation.cpp diff --git a/Celestia/src/main/cpp/CelestiaAppCore.cpp b/Celestia/src/main/cpp/CelestiaAppCore.cpp index 6966b2de..d911a922 100644 --- a/Celestia/src/main/cpp/CelestiaAppCore.cpp +++ b/Celestia/src/main/cpp/CelestiaAppCore.cpp @@ -69,6 +69,9 @@ jmethodID selectionGetObjectPointerMethodID = nullptr; jmethodID selectionGetObjectTypeMethodID = nullptr; jmethodID selectionInitMethodID = nullptr; +jclass completionClz = nullptr; +jmethodID completionInitMethodID = nullptr; + extern "C" { jint JNI_OnLoad(JavaVM *vm, void *reserved) { @@ -122,6 +125,9 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) selectionGetObjectTypeMethodID = env->GetMethodID(selectionClz, "getObjectType", "()I"); selectionInitMethodID = env->GetMethodID(selectionClz, "", "(JI)V"); + completionClz = (jclass)env->NewGlobalRef(env->FindClass("space/celestia/celestia/Completion")); + completionInitMethodID = env->GetMethodID(completionClz, "", "(Ljava/lang/String;Lspace/celestia/celestia/Selection;)V"); + return JNI_VERSION_1_6; } } diff --git a/Celestia/src/main/cpp/CelestiaJNI.h b/Celestia/src/main/cpp/CelestiaJNI.h index 3a8a4408..845026ba 100644 --- a/Celestia/src/main/cpp/CelestiaJNI.h +++ b/Celestia/src/main/cpp/CelestiaJNI.h @@ -55,6 +55,10 @@ extern jmethodID selectionGetObjectPointerMethodID; extern jmethodID selectionGetObjectTypeMethodID; extern jmethodID selectionInitMethodID; +// completion +extern jclass completionClz; +extern jmethodID completionInitMethodID; + extern pthread_key_t javaEnvKey; } diff --git a/Celestia/src/main/cpp/CelestiaSimulation.cpp b/Celestia/src/main/cpp/CelestiaSimulation.cpp index 2318456e..5cc5094e 100644 --- a/Celestia/src/main/cpp/CelestiaSimulation.cpp +++ b/Celestia/src/main/cpp/CelestiaSimulation.cpp @@ -42,7 +42,7 @@ JNIEXPORT jobject JNICALL Java_space_celestia_celestia_Simulation_c_1completionForText(JNIEnv *env, jclass clazz, jlong pointer, jstring text, jint limit) { auto sim = reinterpret_cast(pointer); const char *str = env->GetStringUTFChars(text, nullptr); - std::vector results; + std::vector results; sim->getObjectCompletion(results, str, true); env->ReleaseStringUTFChars(text, str); jobject arrayObject = env->NewObject(alClz, aliMethodID, (int)results.size()); @@ -50,9 +50,14 @@ Java_space_celestia_celestia_Simulation_c_1completionForText(JNIEnv *env, jclass for (const auto& result : results) { if (count > limit) break; - jstring resultString = env->NewStringUTF(result.c_str()); - env->CallBooleanMethod(arrayObject, alaMethodID, resultString); - env->DeleteLocalRef(resultString); + + auto selection = selectionAsJavaSelection(env, result.getSelection()); + auto name = env->NewStringUTF(result.getName().c_str()); + auto completion = env->NewObject(completionClz, completionInitMethodID, name, selection); + env->DeleteLocalRef(selection); + env->DeleteLocalRef(name); + env->CallBooleanMethod(arrayObject, alaMethodID, completion); + env->DeleteLocalRef(completion); count += 1; } return arrayObject; diff --git a/Celestia/src/main/java/space/celestia/celestia/Completion.java b/Celestia/src/main/java/space/celestia/celestia/Completion.java new file mode 100644 index 00000000..2cdfedb1 --- /dev/null +++ b/Celestia/src/main/java/space/celestia/celestia/Completion.java @@ -0,0 +1,26 @@ +/* + * Completion.java + * + * Copyright (C) 2024-present, Celestia Development Team + * + * 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 2 + * of the License, or (at your option) any later version. + */ + +package space.celestia.celestia; + +import androidx.annotation.NonNull; + +public class Completion { + @NonNull + public final String name; + @NonNull + public final Selection selection; + + private Completion(@NonNull String name, @NonNull Selection selection) { + this.name = name; + this.selection = selection; + } +} diff --git a/Celestia/src/main/java/space/celestia/celestia/Selection.java b/Celestia/src/main/java/space/celestia/celestia/Selection.java index 02901cfb..6cda9c51 100644 --- a/Celestia/src/main/java/space/celestia/celestia/Selection.java +++ b/Celestia/src/main/java/space/celestia/celestia/Selection.java @@ -11,9 +11,12 @@ package space.celestia.celestia; +import android.os.Parcel; +import android.os.Parcelable; + import androidx.annotation.Nullable; -public class Selection { +public class Selection implements Parcelable { private final static int SELECTION_TYPE_NIL = 0; private final static int SELECTION_TYPE_STAR = 1; private final static int SELECTION_TYPE_BODY = 2; @@ -64,6 +67,31 @@ public Selection(@Nullable AstroObject object) { this(object, typeForObject(object)); } + @Override + public int describeContents(){ + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(getObjectPointer()); + dest.writeInt(getObjectType()); + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public Selection createFromParcel(Parcel in) { + long objectPointer = in.readLong(); + int objectType = in.readInt(); + return new Selection(objectPointer, objectType); + } + + @Override + public Selection[] newArray(int size) { + return new Selection[size]; + } + }; + private static int typeForObject(AstroObject object) { if (object == null) { return SELECTION_TYPE_NIL; diff --git a/Celestia/src/main/java/space/celestia/celestia/Simulation.java b/Celestia/src/main/java/space/celestia/celestia/Simulation.java index 47f21089..5acf9248 100644 --- a/Celestia/src/main/java/space/celestia/celestia/Simulation.java +++ b/Celestia/src/main/java/space/celestia/celestia/Simulation.java @@ -28,7 +28,7 @@ public void setSelection(@NonNull Selection selection) { c_setSelection(pointer, selection); } - public @NonNull List completionForText(@NonNull String text, int limit) { + public @NonNull List completionForText(@NonNull String text, int limit) { return c_completionForText(pointer, text, limit); } @@ -91,7 +91,7 @@ public void goToLocation(@NonNull GoToLocation location) { private static native Selection c_getSelection(long pointer); private static native void c_setSelection(long pointer, Selection selection); private static native long c_getUniverse(long pointer); - private static native List c_completionForText(long pointer, String text, int limit); + private static native List c_completionForText(long pointer, String text, int limit); private static native Selection c_findObject(long pointer, String name); private static native void c_reverseObserverOrientation(long pointer); private static native double c_getTime(long pointer); diff --git a/CelestiaFoundation/src/main/java/space/celestia/celestiafoundation/utils/Bundle.kt b/CelestiaFoundation/src/main/java/space/celestia/celestiafoundation/utils/Bundle.kt index 2ae7b862..2f6a909d 100644 --- a/CelestiaFoundation/src/main/java/space/celestia/celestiafoundation/utils/Bundle.kt +++ b/CelestiaFoundation/src/main/java/space/celestia/celestiafoundation/utils/Bundle.kt @@ -2,6 +2,7 @@ package space.celestia.celestiafoundation.utils import android.os.Build import android.os.Bundle +import android.os.Parcelable import java.io.Serializable fun Bundle.getSerializableValue(key: String, clazz: Class): T? { @@ -13,4 +14,15 @@ fun Bundle.getSerializableValue(key: String, clazz: Class): @Suppress("UNCHECKED_CAST") return value as? T } +} + +fun Bundle.getParcelableValue(key: String, clazz: Class): T? { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + return getParcelable(key, clazz) + } else { + @Suppress("DEPRECATION") + val value = getSerializable(key) ?: return null + @Suppress("UNCHECKED_CAST") + return value as? T + } } \ No newline at end of file diff --git a/app/src/main/java/space/celestia/mobilecelestia/MainActivity.kt b/app/src/main/java/space/celestia/mobilecelestia/MainActivity.kt index 57762dc7..b2f0e86b 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/MainActivity.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/MainActivity.kt @@ -1980,20 +1980,18 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), } } - private fun showGoTo(data: GoToInputFragment.GoToData? = null) = lifecycleScope.launch { - val inputData = data ?: GoToInputFragment.GoToData( - objectName = AppCore.getLocalizedStringDomain("Earth", "celestia-data"), - objectPath = "Sol/Earth", + private fun showGoTo() = lifecycleScope.launch { + val inputData = GoToInputFragment.GoToData( + objectName = "", 0.0f, 0.0f, 8.0, GoToLocation.DistanceUnit.radii ) - showBottomSheetFragment(GoToContainerFragment.newInstance(inputData)) + showBottomSheetFragment(GoToContainerFragment.newInstance(inputData, Selection())) } - override fun onGoToObject(goToData: GoToInputFragment.GoToData) { - val selection = appCore.simulation.findObject(goToData.objectPath) + override fun onGoToObject(goToData: GoToInputFragment.GoToData, selection: Selection) { if (selection.isEmpty) { showAlert(CelestiaString("Object not found", "")) return diff --git a/app/src/main/java/space/celestia/mobilecelestia/compose/ObjectNameAutoComplete.kt b/app/src/main/java/space/celestia/mobilecelestia/compose/ObjectNameAutoComplete.kt index c4fd1ebb..675843c7 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/compose/ObjectNameAutoComplete.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/compose/ObjectNameAutoComplete.kt @@ -15,26 +15,28 @@ import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import space.celestia.celestia.AppCore +import space.celestia.celestia.Completion +import space.celestia.celestia.Selection import space.celestia.mobilecelestia.R import space.celestia.mobilecelestia.common.CelestiaExecutor import java.lang.ref.WeakReference @SuppressLint("InflateParams") @Composable -fun ObjectNameAutoComplete(executor: CelestiaExecutor, core: AppCore, name: String, modifier: Modifier = Modifier, path: String, inputUpdated: (String) -> Unit, objectPathUpdated: (String) -> Unit) { +fun ObjectNameAutoComplete(executor: CelestiaExecutor, core: AppCore, name: String, modifier: Modifier = Modifier, selection: Selection, inputUpdated: (String) -> Unit, selectionUpdated: (Selection) -> Unit) { val coroutineScope = rememberCoroutineScope() var savedCompletions by rememberSaveable { - mutableStateOf(listOf()) + mutableStateOf(listOf()) } var savedName by rememberSaveable { mutableStateOf(name) } - var savedPath by rememberSaveable { - mutableStateOf(path) + var savedObject by rememberSaveable { + mutableStateOf(selection) } - class StringArrayAdapter(context: Context, var content: List = listOf()): ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line) { - fun updateContent(content: List) { + class StringArrayAdapter(context: Context, var content: List = listOf()): ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line) { + fun updateContent(content: List) { this.content = content } @@ -43,7 +45,7 @@ fun ObjectNameAutoComplete(executor: CelestiaExecutor, core: AppCore, name: Stri } override fun getItem(position: Int): String { - return content[position] + return content[position].name } } @@ -57,13 +59,17 @@ fun ObjectNameAutoComplete(executor: CelestiaExecutor, core: AppCore, name: Stri val autoCompleteAction: (String) -> Unit = { text -> savedName = text inputUpdated(savedName) - objectPathUpdated(savedName) coroutineScope.launch { val strongView = weakView.get() ?: return@launch - val completions = if (text.isEmpty()) listOf() else withContext(executor.asCoroutineDispatcher()) { - core.simulation.completionForText(text, 10) + val results = if (text.isEmpty()) Pair(listOf(), Selection()) else withContext(executor.asCoroutineDispatcher()) { + val completions = core.simulation.completionForText(text, 10) + val fullMatch = core.simulation.findObject(text) + return@withContext Pair(completions, fullMatch) } if (text != savedName) return@launch + val completions = results.first + val fullMatch = results.second + selectionUpdated(fullMatch) if (savedCompletions != completions) { savedCompletions = completions adapter.updateContent(completions) @@ -90,15 +96,9 @@ fun ObjectNameAutoComplete(executor: CelestiaExecutor, core: AppCore, name: Stri } autoCompleteTextView.setOnItemClickListener { _, _, position, _ -> if (position >= 0 && position < adapter.count) { - val result = adapter.getItem(position) - val lastSeparator = savedName.lastIndexOf('/') - val objectPath: String = if (lastSeparator != -1) { - savedName.substring(startIndex = 0, endIndex = lastSeparator + 1) + result - } else { - result - } - savedPath = objectPath - objectPathUpdated(objectPath) + val selected = savedCompletions[position].selection + savedObject = selected + selectionUpdated(selected) } } return@AndroidView view diff --git a/app/src/main/java/space/celestia/mobilecelestia/control/ObserverModeFragment.kt b/app/src/main/java/space/celestia/mobilecelestia/control/ObserverModeFragment.kt index c8b37ad5..8a682856 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/control/ObserverModeFragment.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/control/ObserverModeFragment.kt @@ -72,17 +72,17 @@ class ObserverModeFragment: NavigationFragment.SubFragment() { var referenceObjectName by remember { mutableStateOf("") } - var referenceObjectPath by remember { - mutableStateOf("") + var referenceObject by remember { + mutableStateOf(Selection()) } var targetObjectName by remember { mutableStateOf("") } var selectedCoordinateIndex by remember { - mutableStateOf(0) + mutableIntStateOf(0) } - var targetObjectPath by remember { - mutableStateOf("") + var targetObject by remember { + mutableStateOf(Selection()) } val selectedCoordinateSystem = coordinateSystems[selectedCoordinateIndex].first val nestedScrollInterop = rememberNestedScrollInteropConnection() @@ -97,20 +97,20 @@ class ObserverModeFragment: NavigationFragment.SubFragment() { if (selectedCoordinateSystem != Observer.COORDINATE_SYSTEM_UNIVERSAL) { Header(text = CelestiaString("Reference Object", "Used in Flight Mode")) - ObjectNameAutoComplete(executor = executor, core = appCore, name = referenceObjectName, path = referenceObjectPath, inputUpdated = { + ObjectNameAutoComplete(executor = executor, core = appCore, name = referenceObjectName, selection = referenceObject, inputUpdated = { referenceObjectName = it - }, objectPathUpdated = { - referenceObjectPath = it + }, selectionUpdated = { + referenceObject = it }, modifier = internalViewModifier) Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.list_spacing_short))) } if (selectedCoordinateSystem == Observer.COORDINATE_SYSTEM_PHASE_LOCK) { Header(text = CelestiaString("Target Object", "Used in Flight Mode")) - ObjectNameAutoComplete(executor = executor, core = appCore, name = targetObjectName, path = targetObjectPath, inputUpdated = { + ObjectNameAutoComplete(executor = executor, core = appCore, name = targetObjectName, selection = targetObject, inputUpdated = { targetObjectName = it - }, objectPathUpdated = { - targetObjectPath = it + }, selectionUpdated = { + targetObject = it }, modifier = internalViewModifier) Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.list_spacing_short))) } @@ -122,7 +122,7 @@ class ObserverModeFragment: NavigationFragment.SubFragment() { }) FilledTonalButton(modifier = internalViewModifier, onClick = { - applyObserverMode(referenceObjectPath = referenceObjectPath, targetObjectPath = targetObjectPath, coordinateSystem = selectedCoordinateSystem) + applyObserverMode(referenceObject = referenceObject, targetObject = targetObject, coordinateSystem = selectedCoordinateSystem) }) { Text(text = CelestiaString("OK", "")) } @@ -136,10 +136,8 @@ class ObserverModeFragment: NavigationFragment.SubFragment() { title = CelestiaString("Flight Mode", "") } - private fun applyObserverMode(referenceObjectPath: String, targetObjectPath: String, coordinateSystem: Int) = lifecycleScope.launch(executor.asCoroutineDispatcher()) { - val ref = if (referenceObjectPath.isEmpty()) Selection() else appCore.simulation.findObject(referenceObjectPath) - val target = if (targetObjectPath.isEmpty()) Selection() else appCore.simulation.findObject(targetObjectPath) - appCore.simulation.activeObserver.setFrame(coordinateSystem, ref, target) + private fun applyObserverMode(referenceObject: Selection, targetObject: Selection, coordinateSystem: Int) = lifecycleScope.launch(executor.asCoroutineDispatcher()) { + appCore.simulation.activeObserver.setFrame(coordinateSystem, referenceObject, targetObject) } override fun onAttach(context: Context) { diff --git a/app/src/main/java/space/celestia/mobilecelestia/info/InfoFragment.kt b/app/src/main/java/space/celestia/mobilecelestia/info/InfoFragment.kt index b4d33348..0725286f 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/info/InfoFragment.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/info/InfoFragment.kt @@ -21,6 +21,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import dagger.hilt.android.AndroidEntryPoint import space.celestia.celestia.AppCore import space.celestia.celestia.Selection +import space.celestia.celestiafoundation.utils.getParcelableValue +import space.celestia.celestiafoundation.utils.getSerializableValue import space.celestia.mobilecelestia.common.NavigationFragment import space.celestia.mobilecelestia.compose.Mdc3Theme import space.celestia.mobilecelestia.info.model.InfoActionItem @@ -42,7 +44,7 @@ class InfoFragment : NavigationFragment.SubFragment() { super.onCreate(savedInstanceState) arguments?.let { - selection = Selection(it.getLong(ARG_OBJECT_POINTER), it.getInt(ARG_OBJECT_TYPE)) + selection = it.getParcelableValue(ARG_OBJECT, Selection::class.java)!! embeddedInNavigation = it.getBoolean(ARG_EMBEDDED_IN_NAVIGATION, false) } } @@ -95,16 +97,14 @@ class InfoFragment : NavigationFragment.SubFragment() { } companion object { - const val ARG_OBJECT_POINTER = "object" - const val ARG_OBJECT_TYPE = "type" + const val ARG_OBJECT = "object" const val ARG_EMBEDDED_IN_NAVIGATION = "embedded-in-navigation" @JvmStatic fun newInstance(selection: Selection, embeddedInNavigation: Boolean = false) = InfoFragment().apply { arguments = Bundle().apply { - this.putLong(ARG_OBJECT_POINTER, selection.objectPointer) - this.putInt(ARG_OBJECT_TYPE, selection.type) + this.putParcelable(ARG_OBJECT, selection) this.putBoolean(ARG_EMBEDDED_IN_NAVIGATION, embeddedInNavigation) } } diff --git a/app/src/main/java/space/celestia/mobilecelestia/search/SearchScreen.kt b/app/src/main/java/space/celestia/mobilecelestia/search/SearchScreen.kt index e760aa61..1a3d8830 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/search/SearchScreen.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/search/SearchScreen.kt @@ -48,6 +48,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import space.celestia.celestia.Completion import space.celestia.celestia.Selection import space.celestia.mobilecelestia.R import space.celestia.mobilecelestia.compose.EmptyHint @@ -66,7 +67,7 @@ fun SearchScreen(objectNotFoundHandler: () -> Unit, linkHandler: (URL) -> Unit, mutableStateOf("") } var searchResults by rememberSaveable { - mutableStateOf(listOf()) + mutableStateOf(listOf()) } var isSearchActive by rememberSaveable { mutableStateOf(false) @@ -90,7 +91,7 @@ fun SearchScreen(objectNotFoundHandler: () -> Unit, linkHandler: (URL) -> Unit, searchKey = it isSearching = true scope.launch { - val result = if (it.isEmpty()) listOf() else withContext(viewModel.executor.asCoroutineDispatcher()) { viewModel.appCore.simulation.completionForText(it, 100) } + val result = if (it.isEmpty()) listOf() else withContext(viewModel.executor.asCoroutineDispatcher()) { viewModel.appCore.simulation.completionForText(it, 100) } if (searchKey == it) { searchResults = result isSearching = false @@ -146,14 +147,11 @@ fun SearchScreen(objectNotFoundHandler: () -> Unit, linkHandler: (URL) -> Unit, isSearchActive = false isLoadingPage = true scope.launch { - val selection = withContext(viewModel.executor.asCoroutineDispatcher()) { - viewModel.appCore.simulation.findObject(it) - } isLoadingPage = false - if (selection.isEmpty) + if (it.isEmpty) objectNotFoundHandler() else - currentSelection = selection + currentSelection = it } } }, @@ -180,7 +178,7 @@ private fun SearchContent(selection: Selection?, isLoadingPage: Boolean, linkHan } @Composable -private fun SearchResult(key: String, results: List, isSearching: Boolean, selectionHandler: (String) -> Unit) { +private fun SearchResult(key: String, results: List, isSearching: Boolean, selectionHandler: (Selection) -> Unit) { if (results.isEmpty() && isSearching) { Box(modifier = Modifier .fillMaxSize() @@ -202,14 +200,8 @@ private fun SearchResult(key: String, results: List, isSearching: Boolea .background(color = MaterialTheme.colorScheme.background) ) { items(results) { - TextRow(primaryText = it, modifier = Modifier.clickable { - val lastSeparator = key.lastIndexOf('/') - val name = if (lastSeparator != -1) { - key.substring(startIndex = 0, endIndex = lastSeparator + 1) + it - } else { - it - } - selectionHandler(name) + TextRow(primaryText = it.name, modifier = Modifier.clickable { + selectionHandler(it.selection) }) } } diff --git a/app/src/main/java/space/celestia/mobilecelestia/travel/GoToContainerFragment.kt b/app/src/main/java/space/celestia/mobilecelestia/travel/GoToContainerFragment.kt index 80f7fb04..fabc9bcc 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/travel/GoToContainerFragment.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/travel/GoToContainerFragment.kt @@ -12,6 +12,8 @@ package space.celestia.mobilecelestia.travel import android.os.Bundle +import space.celestia.celestia.Selection +import space.celestia.celestiafoundation.utils.getParcelableValue import space.celestia.mobilecelestia.common.NavigationFragment import space.celestia.celestiafoundation.utils.getSerializableValue @@ -20,36 +22,32 @@ class GoToContainerFragment : NavigationFragment() { get() = requireNotNull(_goToData) private var _goToData: GoToInputFragment.GoToData? = null + private val selection: Selection + get() = requireNotNull(_selection) + private var _selection: Selection? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (_goToData == null) { - if (savedInstanceState != null) { - _goToData = savedInstanceState.getSerializableValue(ARG_DATA, GoToInputFragment.GoToData::class.java) - } else { - arguments?.let { - _goToData = it.getSerializableValue(ARG_DATA, GoToInputFragment.GoToData::class.java) - } - } + arguments?.let { + _selection = it.getParcelableValue(ARG_OBJECT, Selection::class.java) + _goToData = it.getSerializableValue(ARG_DATA, GoToInputFragment.GoToData::class.java) } } - override fun onSaveInstanceState(outState: Bundle) { - outState.putSerializable(ARG_DATA, goToData) - super.onSaveInstanceState(outState) - } - override fun createInitialFragment(savedInstanceState: Bundle?): SubFragment { - return GoToInputFragment.newInstance(goToData) + return GoToInputFragment.newInstance(goToData, selection) } companion object { private const val ARG_DATA = "data" + private const val ARG_OBJECT = "object" @JvmStatic - fun newInstance(goToData: GoToInputFragment.GoToData) = + fun newInstance(goToData: GoToInputFragment.GoToData, selection: Selection) = GoToContainerFragment().apply { arguments = Bundle().apply { + putParcelable(ARG_OBJECT, selection) putSerializable(ARG_DATA, goToData) } } diff --git a/app/src/main/java/space/celestia/mobilecelestia/travel/GoToInputFragment.kt b/app/src/main/java/space/celestia/mobilecelestia/travel/GoToInputFragment.kt index fa6a851a..13b31401 100644 --- a/app/src/main/java/space/celestia/mobilecelestia/travel/GoToInputFragment.kt +++ b/app/src/main/java/space/celestia/mobilecelestia/travel/GoToInputFragment.kt @@ -40,6 +40,8 @@ import androidx.compose.ui.res.dimensionResource import dagger.hilt.android.AndroidEntryPoint import space.celestia.celestia.AppCore import space.celestia.celestia.GoToLocation +import space.celestia.celestia.Selection +import space.celestia.celestiafoundation.utils.getParcelableValue import space.celestia.mobilecelestia.R import space.celestia.mobilecelestia.common.CelestiaExecutor import space.celestia.mobilecelestia.common.NavigationFragment @@ -56,13 +58,16 @@ import javax.inject.Inject @AndroidEntryPoint class GoToInputFragment : NavigationFragment.SubFragment() { - class GoToData(var objectName: String, var objectPath: String, var longitude: Float, var latitude: Float, var distance: Double, var distanceUnit: GoToLocation.DistanceUnit) : + class GoToData(var objectName: String, var longitude: Float, var latitude: Float, var distance: Double, var distanceUnit: GoToLocation.DistanceUnit) : Serializable private var listener: Listener? = null private val goToData: GoToData get() = requireNotNull(_goToData) private var _goToData: GoToData? = null + private val selection: Selection + get() = requireNotNull(_selection) + private var _selection: Selection? = null private lateinit var displayNumberFormat: NumberFormat private lateinit var parseNumberFormat: NumberFormat @@ -76,10 +81,9 @@ class GoToInputFragment : NavigationFragment.SubFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (_goToData == null) { - arguments?.let { - _goToData = it.getSerializableValue(ARG_DATA, GoToData::class.java) - } + arguments?.let { + _selection = it.getParcelableValue(ARG_OBJECT, Selection::class.java) + _goToData = it.getSerializableValue(ARG_DATA, GoToData::class.java) } } @@ -99,19 +103,19 @@ class GoToInputFragment : NavigationFragment.SubFragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { Mdc3Theme { - MainScreen(goToData) + MainScreen(goToData, selection) } } } } @Composable - fun MainScreen(initialData: GoToData) { + fun MainScreen(initialData: GoToData, selection: Selection) { var objectName by remember { mutableStateOf(initialData.objectName) } - var objectPath by remember { - mutableStateOf(initialData.objectPath) + var selectedObject by remember { + mutableStateOf(selection) } var longitudeString by rememberSaveable { mutableStateOf(displayNumberFormat.format(initialData.longitude)) @@ -143,10 +147,10 @@ class GoToInputFragment : NavigationFragment.SubFragment() { .verticalScroll(state = rememberScrollState(), enabled = true) .systemBarsPadding()) { Header(text = CelestiaString("Object", "In eclipse finder, object to find eclipse with, or in go to")) - ObjectNameAutoComplete(executor = executor, core = appCore, name = objectName, path = objectPath, modifier = textViewModifier, inputUpdated = { + ObjectNameAutoComplete(executor = executor, core = appCore, name = objectName, selection = selectedObject, modifier = textViewModifier, inputUpdated = { objectName = it - }, objectPathUpdated = { - objectPath = it + }, selectionUpdated = { + selectedObject = it }) Header(text = CelestiaString("Coordinates", "Longitude and latitude (in Go to)")) Row(modifier = textViewModifier, horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.list_item_gap_horizontal))) { @@ -192,7 +196,7 @@ class GoToInputFragment : NavigationFragment.SubFragment() { val longitude = currentLongitudeValue ?: return@FilledTonalButton val latitude = currentLatitudeValue ?: return@FilledTonalButton val distance = currentDistanceValue ?: return@FilledTonalButton - listener?.onGoToObject(GoToData(objectName, objectPath, longitude = longitude.toFloat(), latitude = latitude.toFloat(), distance = distance, distanceUnit = distanceUnit)) + listener?.onGoToObject(GoToData(objectName, longitude = longitude.toFloat(), latitude = latitude.toFloat(), distance = distance, distanceUnit = distanceUnit), selectedObject) } ) { Text(text = CelestiaString("Go", "Go to an object")) @@ -221,11 +225,12 @@ class GoToInputFragment : NavigationFragment.SubFragment() { } interface Listener { - fun onGoToObject(goToData: GoToData) + fun onGoToObject(goToData: GoToData, selection: Selection) } companion object { private const val ARG_DATA = "data" + private const val ARG_OBJECT = "object" private val distanceUnits = listOf( GoToLocation.DistanceUnit.radii, @@ -233,10 +238,10 @@ class GoToInputFragment : NavigationFragment.SubFragment() { GoToLocation.DistanceUnit.au ) - @JvmStatic - fun newInstance(goToData: GoToData) = + fun newInstance(goToData: GoToData, selection: Selection) = GoToInputFragment().apply { arguments = Bundle().apply { + putParcelable(ARG_OBJECT, selection) putSerializable(ARG_DATA, goToData) } }