android :: ui $ Android_app_Fragment
Java class: android.app.Fragmentandroid :: ui $ Android_widget_ArrayAdapter
Java class: android.widget.ArrayAdapterandroid :: ui $ NativeActivity
An activity, a single, focused thing a user can do on Androidandroid :: ui $ NativeButton
android :: ui $ NativeEditText
android :: ui $ Android_app_Fragment
Java class: android.app.Fragmentandroid :: ui $ Android_widget_ArrayAdapter
Java class: android.widget.ArrayAdapterandroid :: ui $ NativeActivity
An activity, a single, focused thing a user can do on Androidandroid :: ui $ NativeButton
android :: ui $ NativeEditText
Serializable::inspect
to show more useful information
app.nit
on Android using a custom Java entry point
serialization :: serialization_core
Abstract services to serialize Nit objects to different formatsdeserialize_json
and JsonDeserializer
serialize_to_json
and JsonSerializer
core :: union_find
union–find algorithm using an efficient disjoint-set data structure
# Views and services to use the Android native user interface
module ui is
# `adjustPan` allows to use EditText in a ListLayout
android_manifest_activity """android:windowSoftInputMode="adjustPan""""
end
# Implementation note:
#
# We cannot rely on `Activity::on_restore_instance_state` to implement
# `on_restore_state` is it only invoked if there is a bundled state,
# and we don't use the Android bundled state.
import native_ui
import log
import nit_activity
import app::ui
private import data_store
import assets
redef class Control
# The Android element used to implement `self`
fun native: NATIVE is abstract
# Type of `native`
type NATIVE: JavaObject
end
redef class NativeActivity
private fun remove_title_bar in "Java" `{
self.requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
`}
# Insert a single layout as the root of the activity window
private fun insert_root_layout(root_layout_id: Int)
in "Java" `{
android.widget.FrameLayout layout = new android.widget.FrameLayout(self);
layout.setId((int)root_layout_id);
self.setContentView(layout);
`}
# Replace the currently visible fragment, if any, with `native_fragment`
private fun show_fragment(root_layout_id: Int, native_fragment: Android_app_Fragment)
in "Java" `{
android.app.FragmentTransaction transaction = self.getFragmentManager().beginTransaction();
transaction.replace((int)root_layout_id, native_fragment);
transaction.commit();
`}
end
redef class App
redef fun on_create
do
app.native_activity.remove_title_bar
native_activity.insert_root_layout(root_layout_id)
super
end
# Identifier of the container holding the fragments
private var root_layout_id = 0xFFFF
redef fun window=(window)
do
native_activity.show_fragment(root_layout_id, window.native)
super
end
redef fun on_start do window.on_start
redef fun on_destroy do window.on_destroy
end
redef class CompositeControl
redef fun on_start do for i in items do i.on_start
redef fun on_destroy do for i in items do i.on_destroy
end
redef class Activity
redef fun on_back_pressed
do
var window = app.window
if window.enable_back_button then
window.on_back_button
return true
end
return false
end
end
# On Android, a window is implemented with the fragment `native`
redef class Window
redef var native = (new Android_app_Fragment(self)).new_global_ref
redef type NATIVE: Android_app_Fragment
# Root high-level view of this window
var view: nullable View = null
redef fun add(item)
do
if item isa View then view = item
super
end
private fun on_create_fragment: NativeView
do
on_create
var view = view
assert view != null else print_error "{class_name} needs a `view` after `Window::on_create` returns"
return view.native
end
end
redef class View
redef type NATIVE: NativeView
redef fun enabled=(enabled) do native.enabled = enabled or else true
redef fun enabled do return native.enabled
end
redef class Layout
redef type NATIVE: NativeViewGroup
redef fun add(item)
do
super
assert item isa View
# FIXME abstract the use either homogeneous or weight to balance views size in a layout
native.add_view_with_weight(item.native, 1.0)
end
redef fun remove(item)
do
super
if item isa View then native.remove_view item.native
end
end
redef class HorizontalLayout
redef var native do
var layout = new NativeLinearLayout(app.native_activity)
layout = layout.new_global_ref
layout.set_horizontal
return layout
end
end
redef class VerticalLayout
redef var native do
var layout = new NativeLinearLayout(app.native_activity)
layout = layout.new_global_ref
layout.set_vertical
return layout
end
end
redef class ListLayout
redef type NATIVE: Android_widget_ListView
redef var native do
var layout = new Android_widget_ListView(app.native_activity)
layout = layout.new_global_ref
return layout
end
private var adapter: Android_widget_ArrayAdapter do
var adapter = new Android_widget_ArrayAdapter(app.native_activity,
android_r_layout_simple_list_item_1, self)
native.set_adapter adapter
return adapter.new_global_ref
end
redef fun add(item)
do
super
if item isa View then adapter.add item.native
end
private fun create_view(position: Int): NativeView
do
var ctrl = items[position]
assert ctrl isa View
return ctrl.native
end
end
redef class Android_widget_ArrayAdapter
private new (context: NativeContext, res: Int, sender: ListLayout)
import ListLayout.create_view in "Java" `{
final nit.app.NitObject final_sender_object = sender;
ListLayout_incr_ref(sender);
return new android.widget.ArrayAdapter(context, (int)res) {
@Override
public android.view.View getView(int position, android.view.View convertView, android.view.ViewGroup parent) {
return ListLayout_create_view(final_sender_object, position);
}
};
`}
end
redef class TextView
redef type NATIVE: NativeTextView
redef fun text do return native.text.to_s
redef fun text=(value) do
if value == null then value = ""
native.text = value.to_java_string
end
redef fun size=(size) do set_size_native(app.native_activity, native, size or else 1.0)
private fun set_size_native(context: NativeContext, view: NativeTextView, size: Float)
in "Java" `{
int s;
if (size == 1.0d)
s = android.R.style.TextAppearance_Medium;
else if (size < 1.0d)
s = android.R.style.TextAppearance_Small;
else // if (size > 1.0d)
s = android.R.style.TextAppearance_Large;
view.setTextAppearance(context, s);
`}
redef fun align=(align) do set_align_native(native, align or else 0.0)
private fun set_align_native(view: NativeTextView, align: Float)
in "Java" `{
int g;
if (align == 0.5d)
g = android.view.Gravity.CENTER_HORIZONTAL;
else if (align < 0.5d)
g = android.view.Gravity.LEFT;
else // if (align > 0.5d)
g = android.view.Gravity.RIGHT;
view.setGravity(g | android.view.Gravity.CENTER_VERTICAL);
`}
end
redef class Label
redef type NATIVE: NativeTextView
redef var native do return (new NativeTextView(app.native_activity)).new_global_ref
end
redef class CheckBox
redef type NATIVE: Android_widget_CompoundButton
redef var native do return (new Android_widget_CheckBox(app.native_activity)).new_global_ref
init do set_callback_on_toggle(native)
redef fun is_checked do return native.is_checked
redef fun is_checked=(value) do native.set_checked(value)
private fun on_toggle do notify_observers new ToggleEvent(self)
private fun set_callback_on_toggle(view: NATIVE)
import on_toggle in "Java" `{
final nit.app.NitObject final_sender_object = self;
CheckBox_incr_ref(final_sender_object);
view.setOnCheckedChangeListener(
new android.widget.CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(android.widget.CompoundButton buttonView, boolean isChecked) {
CheckBox_on_toggle(final_sender_object);
}
});
`}
end
redef class TextInput
redef type NATIVE: NativeEditText
redef var native = (new NativeEditText(app.native_activity)).new_global_ref
redef fun is_password=(value)
do
native.is_password = value or else false
super
end
end
redef class NativeEditText
# Configure this view to hide passwords
fun is_password=(value: Bool) in "Java" `{
if (value) {
self.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD);
self.setTransformationMethod(android.text.method.PasswordTransformationMethod.getInstance());
} else {
self.setInputType(android.text.InputType.TYPE_CLASS_TEXT);
self.setTransformationMethod(null);
}
`}
end
redef class Button
super Finalizable
redef type NATIVE: NativeButton
redef var native = (new NativeButton(app.native_activity, self)).new_global_ref
private fun on_click do notify_observers new ButtonPressEvent(self)
redef fun finalize do native.delete_global_ref
end
redef class NativeButton
private new (context: NativeActivity, sender_object: Button)
import Button.on_click in "Java" `{
final nit.app.NitObject final_sender_object = sender_object;
Button_incr_ref(final_sender_object);
return new android.widget.Button(context) {
@Override
public boolean onTouchEvent(android.view.MotionEvent event) {
if (event.getAction() == android.view.MotionEvent.ACTION_UP) {
Button_on_click(final_sender_object);
return true;
} else if (event.getAction() == android.view.MotionEvent.ACTION_DOWN) {
return true;
}
return false;
}
};
`}
end
redef class Android_app_Fragment
private new (nit_window: Window)
import Window.on_create_fragment in "Java" `{
final nit.app.NitObject final_nit_window = nit_window;
Window_incr_ref(nit_window);
return new android.app.Fragment(){
@Override
public android.view.View onCreateView(android.view.LayoutInflater inflater,
android.view.ViewGroup container, android.os.Bundle state) {
return Window_on_create_fragment(final_nit_window);
}
};
`}
end
redef class Text
redef fun open_in_browser
do to_java_string.native_open_in_browser(app.native_activity)
end
redef class JavaString
private fun native_open_in_browser(context: NativeContext)
in "Java" `{
android.content.Intent intent = new android.content.Intent(
android.content.Intent.ACTION_VIEW,
android.net.Uri.parse(self));
context.startActivity(intent);
`}
end
lib/android/ui/ui.nit:15,1--379,3