Skip to content

Commit

Permalink
Add support for celestia.completion
Browse files Browse the repository at this point in the history
  • Loading branch information
levinli303 committed Oct 9, 2024
1 parent b0d197b commit de4c56a
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 101 deletions.
2 changes: 2 additions & 0 deletions Celestia/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Celestia/src/main/cpp/CelestiaAppCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -122,6 +125,9 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
selectionGetObjectTypeMethodID = env->GetMethodID(selectionClz, "getObjectType", "()I");
selectionInitMethodID = env->GetMethodID(selectionClz, "<init>", "(JI)V");

completionClz = (jclass)env->NewGlobalRef(env->FindClass("space/celestia/celestia/Completion"));
completionInitMethodID = env->GetMethodID(completionClz, "<init>", "(Ljava/lang/String;Lspace/celestia/celestia/Selection;)V");

return JNI_VERSION_1_6;
}
}
Expand Down
4 changes: 4 additions & 0 deletions Celestia/src/main/cpp/CelestiaJNI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
13 changes: 9 additions & 4 deletions Celestia/src/main/cpp/CelestiaSimulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,22 @@ JNIEXPORT jobject JNICALL
Java_space_celestia_celestia_Simulation_c_1completionForText(JNIEnv *env, jclass clazz, jlong pointer, jstring text, jint limit) {
auto sim = reinterpret_cast<Simulation *>(pointer);
const char *str = env->GetStringUTFChars(text, nullptr);
std::vector<std::string> results;
std::vector<celestia::engine::Completion> results;
sim->getObjectCompletion(results, str, true);
env->ReleaseStringUTFChars(text, str);
jobject arrayObject = env->NewObject(alClz, aliMethodID, (int)results.size());
int count = 0;
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;
Expand Down
26 changes: 26 additions & 0 deletions Celestia/src/main/java/space/celestia/celestia/Completion.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
30 changes: 29 additions & 1 deletion Celestia/src/main/java/space/celestia/celestia/Selection.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Selection> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void setSelection(@NonNull Selection selection) {
c_setSelection(pointer, selection);
}

public @NonNull List<String> completionForText(@NonNull String text, int limit) {
public @NonNull List<Completion> completionForText(@NonNull String text, int limit) {
return c_completionForText(pointer, text, limit);
}

Expand Down Expand Up @@ -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<String> c_completionForText(long pointer, String text, int limit);
private static native List<Completion> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T: Serializable> Bundle.getSerializableValue(key: String, clazz: Class<T>): T? {
Expand All @@ -13,4 +14,15 @@ fun <T: Serializable> Bundle.getSerializableValue(key: String, clazz: Class<T>):
@Suppress("UNCHECKED_CAST")
return value as? T
}
}

fun <T: Parcelable> Bundle.getParcelableValue(key: String, clazz: Class<T>): 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
}
}
12 changes: 5 additions & 7 deletions app/src/main/java/space/celestia/mobilecelestia/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>())
mutableStateOf(listOf<Completion>())
}
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<String> = listOf()): ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line) {
fun updateContent(content: List<String>) {
class StringArrayAdapter(context: Context, var content: List<Completion> = listOf()): ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line) {
fun updateContent(content: List<Completion>) {
this.content = content
}

Expand All @@ -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
}
}

Expand All @@ -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<String>() 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)
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)))
}
Expand All @@ -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", ""))
}
Expand All @@ -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) {
Expand Down
Loading

0 comments on commit de4c56a

Please sign in to comment.