commit
33800840c4
14 changed files with 1489 additions and 411 deletions
52
OsmAnd/res/layout-land/empty_state_av_notes.xml
Normal file
52
OsmAnd/res/layout-land/empty_state_av_notes.xml
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/empty_state_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/empty_state_image_margin_bottom"
|
||||
android:layout_marginLeft="@dimen/empty_state_image_margin_left"
|
||||
android:layout_marginStart="@dimen/empty_state_image_margin_left"
|
||||
android:layout_marginTop="@dimen/empty_state_image_margin_top"
|
||||
android:adjustViewBounds="true"
|
||||
tools:src="@drawable/ic_empty_state_av_notes_night"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="@dimen/empty_state_text_button_padding_right"
|
||||
android:paddingLeft="@dimen/empty_state_text_button_padding_left"
|
||||
android:paddingRight="@dimen/empty_state_text_button_padding_right"
|
||||
android:paddingStart="@dimen/empty_state_text_button_padding_left"
|
||||
android:paddingTop="@dimen/empty_state_text_button_padding_top">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/empty_state_text_interval"
|
||||
android:background="@null"
|
||||
android:text="@string/empty_state_av_notes"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/empty_state_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:text="@string/empty_state_av_notes_desc"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/empty_state_text_desc_size"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
40
OsmAnd/res/layout/empty_state_av_notes.xml
Normal file
40
OsmAnd/res/layout/empty_state_av_notes.xml
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/empty_state_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/empty_state_image_margin_bottom"
|
||||
android:layout_marginTop="@dimen/empty_state_image_margin_top"
|
||||
tools:src="@drawable/ic_empty_state_av_notes_night"/>
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/empty_state_text_interval"
|
||||
android:background="@null"
|
||||
android:text="@string/empty_state_av_notes"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/empty_state_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/empty_state_text_desc_margin"
|
||||
android:layout_marginRight="@dimen/empty_state_text_desc_margin"
|
||||
android:background="@null"
|
||||
android:gravity="center"
|
||||
android:text="@string/empty_state_av_notes_desc"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="@dimen/empty_state_text_desc_size"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,220 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?attr/bg_color"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/bottom_sheet_content_padding_small">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_title_height"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:text="Paris Hotel"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/play_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_play_dark"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/play_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"
|
||||
tools:text="Play"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/share_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/share_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_action_gshare_dark"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="@string/shared_string_share"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/show_on_map_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/show_on_map_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_show_on_map"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/shared_string_show_on_map"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/show_on_map_descr_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
tools:text="52.23423, 14.34578"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="@dimen/bottom_sheet_divider_margin_bottom"
|
||||
android:layout_marginLeft="@dimen/bottom_sheet_divider_margin_start"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_divider_margin_start"
|
||||
android:layout_marginTop="@dimen/bottom_sheet_divider_margin_top"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/rename_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/rename_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_action_edit_dark"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="@string/shared_string_rename"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/delete_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/delete_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_action_delete_dark"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="@string/shared_string_delete"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/close_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_cancel_button_height"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/shared_string_close"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/color_dialog_buttons"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
android:textStyle="bold"/>
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
111
OsmAnd/res/layout/fragment_notes_sort_bottom_sheet_dialog.xml
Normal file
111
OsmAnd/res/layout/fragment_notes_sort_bottom_sheet_dialog.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?attr/bg_color"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/bottom_sheet_content_padding_small">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_title_height"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:text="@string/shared_string_sort"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"
|
||||
osmand:typeface="@string/font_roboto_medium"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/by_type_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/by_type_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_groped_by_type"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="@string/by_type"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/by_date_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/bottom_sheet_list_item_height"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/by_date_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_icon_margin"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_icon_margin"
|
||||
tools:src="@drawable/ic_action_sort_by_date"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="@string/by_date"
|
||||
android:textAppearance="@style/TextAppearance.ListItemTitle"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/dashboard_divider"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/close_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_cancel_button_height"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/shared_string_cancel"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/color_dialog_buttons"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
android:textStyle="bold"/>
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
48
OsmAnd/res/layout/list_item_header.xml
Normal file
48
OsmAnd/res/layout/list_item_header.xml
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/list_item_divider"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/bg_color">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/header_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_list_item_height"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_box"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<android.support.v7.widget.AppCompatTextView
|
||||
android:id="@+id/title_text_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
tools:text="Header"/>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
90
OsmAnd/res/layout/note_list_item.xml
Normal file
90
OsmAnd/res/layout/note_list_item.xml
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/bg_color"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_selected_item_title_height"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_box"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:focusable="false"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:src="@drawable/ic_type_audio"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/map_marker_title_height"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/searchbar_text"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
tools:text="Nov 17, 2017 Audio Note"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="@dimen/default_sub_text_size"
|
||||
tools:text="Oct 13, 2017 * 3 MB * 01:14"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/options"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:contentDescription="@string/shared_string_more"
|
||||
android:focusable="false"
|
||||
android:padding="@dimen/content_padding"
|
||||
android:src="@drawable/ic_overflow_menu_white"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/bottom_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginLeft="@dimen/bottom_sheet_selected_item_title_height"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_selected_item_title_height"
|
||||
android:background="?attr/dashboard_divider"
|
||||
android:focusable="false"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -36,4 +36,9 @@
|
|||
android:layout_marginRight="0dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_weight="1"/>
|
||||
`
|
||||
<ViewStub
|
||||
android:id="@+id/empty_view_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
|
@ -12,6 +12,11 @@
|
|||
<string name="marker_activated">Marker %s activated.</string>
|
||||
<string name="one_tap_active_descr">Tap on marker on the map, move it to the first place in active markers, without opening context menu.</string>
|
||||
<string name="one_tap_active">One tap active</string>
|
||||
<string name="empty_state_av_notes">Take notes!</string>
|
||||
<string name="empty_state_av_notes_desc">Add audio, video or photo note to every point on the map, using widget or context menu.</string>
|
||||
<string name="notes_by_date">Notes by date</string>
|
||||
<string name="by_date">By date</string>
|
||||
<string name="by_type">By type</string>
|
||||
<string name="looking_for_tracks_with_waypoints">Looking for tracks with waypoints</string>
|
||||
<string name="shared_string_more_without_dots">More</string>
|
||||
<string name="appearance_on_the_map">Appearance on the map</string>
|
||||
|
|
|
@ -1335,6 +1335,8 @@ public class OsmandSettings {
|
|||
MAP_MARKERS_MODE.setModeDefaultValue(ApplicationMode.PEDESTRIAN, MapMarkersMode.TOOLBAR);
|
||||
}
|
||||
|
||||
public final CommonPreference<NotesSortByMode> NOTES_SORT_BY_MODE = new EnumIntPreference<>("notes_sort_by_mode", NotesSortByMode.BY_DATE, NotesSortByMode.values());
|
||||
|
||||
public final OsmandPreference<Boolean> ANIMATE_MY_LOCATION = new BooleanPreference("animate_my_location", true).makeGlobal().cache();
|
||||
|
||||
public final OsmandPreference<Boolean> ROUTE_MAP_MARKERS_START_MY_LOC = new BooleanPreference("route_map_markers_start_my_loc", false).makeGlobal().cache();
|
||||
|
@ -3159,6 +3161,19 @@ public class OsmandSettings {
|
|||
}
|
||||
}
|
||||
|
||||
public enum NotesSortByMode {
|
||||
BY_TYPE,
|
||||
BY_DATE;
|
||||
|
||||
public boolean isByType() {
|
||||
return this == BY_TYPE;
|
||||
}
|
||||
|
||||
public boolean isByDate() {
|
||||
return this == BY_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MapMarkersOrderByMode {
|
||||
CUSTOM,
|
||||
DISTANCE_DESC,
|
||||
|
|
|
@ -59,6 +59,7 @@ import net.osmand.plus.activities.MapActivity;
|
|||
import net.osmand.plus.activities.SavingTrackHelper;
|
||||
import net.osmand.plus.activities.TabActivity.TabItem;
|
||||
import net.osmand.plus.dashboard.tools.DashFragmentData;
|
||||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.mapcontextmenu.MapContextMenu;
|
||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||
|
@ -457,6 +458,29 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
|
||||
}
|
||||
|
||||
public String getNewSmallDescription(Context ctx) {
|
||||
DateFormat dateFormat = android.text.format.DateFormat.getMediumDateFormat(ctx);
|
||||
String date = dateFormat.format(file.lastModified());
|
||||
int size = (int) ((file.length() + 512) >> 10);
|
||||
String sz = "";
|
||||
if (size > 0) {
|
||||
if (size > 1 << 20) {
|
||||
sz = DownloadActivity.formatGb.format(new Object[]{(float) size / (1 << 20)});
|
||||
} else {
|
||||
if (file.length() > (100 * (1 << 10))) {
|
||||
sz = DownloadActivity.formatMb.format(new Object[]{(float) file.length() / (1 << 20)});
|
||||
} else {
|
||||
sz = DownloadActivity.formatKb.format(new Object[]{(float) file.length() / (1 << 10)});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPhoto()) {
|
||||
return date + " • " + sz;
|
||||
}
|
||||
updateInternalDescription();
|
||||
return date + " • " + sz + " • " + getDuration(ctx);
|
||||
}
|
||||
|
||||
public String getPlainDuration(boolean accessibilityEnabled) {
|
||||
updateInternalDescription();
|
||||
if (duration > 0) {
|
||||
|
@ -1616,11 +1640,9 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
|||
|
||||
@Override
|
||||
public void addMyPlacesTab(FavoritesActivity favoritesActivity, List<TabItem> mTabs, Intent intent) {
|
||||
if (getAllRecordings().size() > 0) {
|
||||
mTabs.add(favoritesActivity.getTabIndicator(NOTES_TAB, NotesFragment.class));
|
||||
if (intent != null && "AUDIO".equals(intent.getStringExtra("TAB"))) {
|
||||
app.getSettings().FAVORITES_TAB.set(NOTES_TAB);
|
||||
}
|
||||
mTabs.add(favoritesActivity.getTabIndicator(NOTES_TAB, NotesFragment.class));
|
||||
if (intent != null && "AUDIO".equals(intent.getStringExtra("TAB"))) {
|
||||
app.getSettings().FAVORITES_TAB.set(NOTES_TAB);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package net.osmand.plus.audionotes;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
|
||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
|
||||
public class ItemMenuBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
|
||||
|
||||
public static final String TAG = "ItemMenuBottomSheetDialogFragment";
|
||||
|
||||
private ItemMenuFragmentListener listener;
|
||||
private Recording recording;
|
||||
|
||||
public void setListener(ItemMenuFragmentListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setRecording(Recording recording) {
|
||||
this.recording = recording;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
|
||||
|
||||
final View mainView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
|
||||
R.layout.fragment_notes_item_menu_bottom_sheet_dialog, null);
|
||||
|
||||
if (recording != null) {
|
||||
NumberFormat f = new DecimalFormat("#0.00000");
|
||||
((TextView) mainView.findViewById(R.id.title_text_view))
|
||||
.setText(recording.getName(getActivity(), true));
|
||||
((TextView) mainView.findViewById(R.id.play_text_view))
|
||||
.setText(recording.isPhoto() ? R.string.watch : R.string.recording_context_menu_play);
|
||||
((TextView) mainView.findViewById(R.id.show_on_map_descr_text_view))
|
||||
.setText(f.format(recording.getLatitude()) + ", " + f.format(recording.getLongitude()));
|
||||
((ImageView) mainView.findViewById(R.id.play_icon))
|
||||
.setImageDrawable(getContentIcon(recording.isPhoto() ? R.drawable.ic_action_view : R.drawable.ic_play_dark));
|
||||
}
|
||||
|
||||
((ImageView) mainView.findViewById(R.id.share_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_gshare_dark));
|
||||
((ImageView) mainView.findViewById(R.id.show_on_map_icon)).setImageDrawable(getContentIcon(R.drawable.ic_show_on_map));
|
||||
((ImageView) mainView.findViewById(R.id.rename_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_edit_dark));
|
||||
((ImageView) mainView.findViewById(R.id.delete_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_delete_dark));
|
||||
|
||||
mainView.findViewById(R.id.play_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null && recording != null) {
|
||||
listener.playOnClick(recording);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.share_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null && recording != null) {
|
||||
listener.shareOnClick(recording);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.show_on_map_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null && recording != null) {
|
||||
listener.showOnMapOnClick(recording);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.rename_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null && recording != null) {
|
||||
listener.renameOnClick(recording);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.delete_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null && recording != null) {
|
||||
listener.deleteOnClick(recording);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.close_row).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
setupHeightAndBackground(mainView, R.id.scroll_view);
|
||||
|
||||
return mainView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (getDialog() != null) {
|
||||
getDialog().setDismissMessage(null);
|
||||
}
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
interface ItemMenuFragmentListener {
|
||||
|
||||
void playOnClick(Recording recording);
|
||||
|
||||
void shareOnClick(Recording recording);
|
||||
|
||||
void showOnMapOnClick(Recording recording);
|
||||
|
||||
void renameOnClick(Recording recording);
|
||||
|
||||
void deleteOnClick(Recording recording);
|
||||
}
|
||||
}
|
|
@ -3,28 +3,27 @@ package net.osmand.plus.audionotes;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.PopupMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStub;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
|
@ -32,119 +31,292 @@ import net.osmand.data.PointDescription;
|
|||
import net.osmand.plus.GPXUtilities;
|
||||
import net.osmand.plus.GPXUtilities.GPXFile;
|
||||
import net.osmand.plus.GPXUtilities.WptPt;
|
||||
import net.osmand.plus.IconsCache;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.OsmandSettings.NotesSortByMode;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.ActionBarProgressActivity;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.activities.OsmandActionBarActivity;
|
||||
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
|
||||
import net.osmand.plus.audionotes.ItemMenuBottomSheetDialogFragment.ItemMenuFragmentListener;
|
||||
import net.osmand.plus.audionotes.SortByMenuBottomSheetDialogFragment.SortFragmentListener;
|
||||
import net.osmand.plus.audionotes.adapters.NotesAdapter;
|
||||
import net.osmand.plus.audionotes.adapters.NotesAdapter.NotesAdapterListener;
|
||||
import net.osmand.plus.base.OsmAndListFragment;
|
||||
import net.osmand.plus.dialogs.DirectionsDialogs;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.myplaces.FavoritesActivity;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class NotesFragment extends OsmAndListFragment {
|
||||
|
||||
public static final Recording SHARE_LOCATION_FILE = new Recording(new File("."));
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(NotesFragment.class);
|
||||
private static final int MODE_DELETE = 100;
|
||||
private static final int MODE_SHARE = 101;
|
||||
|
||||
private AudioVideoNotesPlugin plugin;
|
||||
private NotesAdapter listAdapter;
|
||||
private Set<Recording> selected = new HashSet<>();
|
||||
|
||||
AudioVideoNotesPlugin plugin;
|
||||
List<AudioVideoNotesPlugin.Recording> items;
|
||||
NotesAdapter listAdapter;
|
||||
private View footerView;
|
||||
private View emptyView;
|
||||
|
||||
private boolean selectionMode = false;
|
||||
private boolean selectionMode;
|
||||
|
||||
private final static int MODE_DELETE = 100;
|
||||
private final static int MODE_SHARE = 101;
|
||||
|
||||
private ActionMode actionMode;
|
||||
|
||||
private ArrayList<AudioVideoNotesPlugin.Recording> selected = new ArrayList<>();
|
||||
Recording shareLocationFile = new Recording(new File("."));
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
setHasOptionsMenu(true);
|
||||
plugin = OsmandPlugin.getEnabledPlugin(AudioVideoNotesPlugin.class);
|
||||
View view = getActivity().getLayoutInflater().inflate(R.layout.update_index, container, false);
|
||||
view.findViewById(R.id.select_all).setVisibility(View.GONE);
|
||||
((TextView) view.findViewById(R.id.header)).setText(R.string.notes);
|
||||
final CheckBox selectAll = (CheckBox) view.findViewById(R.id.select_all);
|
||||
selectAll.setVisibility(View.GONE);
|
||||
selectAll.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (selectAll.isChecked()) {
|
||||
selectAll();
|
||||
} else {
|
||||
deselectAll();
|
||||
}
|
||||
updateSelectionTitle(actionMode);
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayAdapter<?> getAdapter() {
|
||||
return listAdapter;
|
||||
}
|
||||
|
||||
private void selectAll() {
|
||||
for (int i = 0; i < listAdapter.getCount(); i++) {
|
||||
Recording point = listAdapter.getItem(i);
|
||||
if (!selected.contains(point)) {
|
||||
selected.add(point);
|
||||
}
|
||||
// Handle screen rotation:
|
||||
FragmentManager fm = getChildFragmentManager();
|
||||
Fragment sortByMenu = fm.findFragmentByTag(SortByMenuBottomSheetDialogFragment.TAG);
|
||||
if (sortByMenu != null) {
|
||||
((SortByMenuBottomSheetDialogFragment) sortByMenu).setListener(createSortFragmentListener());
|
||||
}
|
||||
Fragment itemMenu = fm.findFragmentByTag(ItemMenuBottomSheetDialogFragment.TAG);
|
||||
if (itemMenu != null) {
|
||||
((ItemMenuBottomSheetDialogFragment) itemMenu).setListener(createItemMenuFragmentListener());
|
||||
}
|
||||
listAdapter.notifyDataSetInvalidated();
|
||||
}
|
||||
|
||||
private void deselectAll(){
|
||||
selected.clear();
|
||||
listAdapter.notifyDataSetInvalidated();
|
||||
plugin = OsmandPlugin.getEnabledPlugin(AudioVideoNotesPlugin.class);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View view = getActivity().getLayoutInflater().inflate(R.layout.update_index, container, false);
|
||||
view.findViewById(R.id.header_layout).setVisibility(View.GONE);
|
||||
ViewStub emptyStub = (ViewStub) view.findViewById(R.id.empty_view_stub);
|
||||
emptyStub.setLayoutResource(R.layout.empty_state_av_notes);
|
||||
emptyView = emptyStub.inflate();
|
||||
int icRes = getMyApplication().getSettings().isLightContent()
|
||||
? R.drawable.ic_empty_state_av_notes_day : R.drawable.ic_empty_state_av_notes_night;
|
||||
((ImageView) emptyView.findViewById(R.id.empty_state_image_view)).setImageResource(icRes);
|
||||
emptyView.setBackgroundColor(getResources().getColor(getMyApplication().getSettings()
|
||||
.isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
getListView().setBackgroundColor(
|
||||
getResources().getColor(
|
||||
getMyApplication().getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light
|
||||
: R.color.ctx_menu_info_view_bg_dark));
|
||||
getListView().setBackgroundColor(getResources().getColor(getMyApplication().getSettings()
|
||||
.isLightContent() ? R.color.ctx_menu_info_view_bg_light : R.color.ctx_menu_info_view_bg_dark));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
items = new ArrayList<>(plugin.getAllRecordings());
|
||||
sortItemsDescending();
|
||||
List<Object> items = createItemsList();
|
||||
ListView listView = getListView();
|
||||
listView.setDivider(null);
|
||||
listView.setEmptyView(emptyView);
|
||||
if (items.size() > 0 && footerView == null) {
|
||||
//listView.addHeaderView(getActivity().getLayoutInflater().inflate(R.layout.list_shadow_header, null, false));
|
||||
footerView = getActivity().getLayoutInflater().inflate(R.layout.list_shadow_footer, null, false);
|
||||
listView.addFooterView(footerView);
|
||||
listView.setHeaderDividersEnabled(false);
|
||||
listView.setFooterDividersEnabled(false);
|
||||
}
|
||||
listAdapter = new NotesAdapter(items);
|
||||
listAdapter = new NotesAdapter(getMyApplication(), items);
|
||||
listAdapter.setSelectionMode(selectionMode);
|
||||
listAdapter.setSelected(selected);
|
||||
listAdapter.setListener(createAdapterListener());
|
||||
listView.setAdapter(listAdapter);
|
||||
}
|
||||
|
||||
private void sortItemsDescending() {
|
||||
Collections.sort(items, new Comparator<Recording>() {
|
||||
@Override
|
||||
public ArrayAdapter<?> getAdapter() {
|
||||
return listAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
menu.clear();
|
||||
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
|
||||
menu = ((ActionBarProgressActivity) getActivity()).getClearToolbar(true).getMenu();
|
||||
} else {
|
||||
((ActionBarProgressActivity) getActivity()).getClearToolbar(false);
|
||||
}
|
||||
((ActionBarProgressActivity) getActivity()).updateListViewFooter(footerView);
|
||||
|
||||
MenuItem item = menu.add(R.string.shared_string_sort).setIcon(R.drawable.ic_action_list_sort);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
showSortMenuFragment();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
item = menu.add(R.string.shared_string_share).setIcon(R.drawable.ic_action_gshare_dark);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
enterSelectionMode(MODE_SHARE);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
item = menu.add(R.string.shared_string_delete_all).setIcon(R.drawable.ic_action_delete_dark);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
enterSelectionMode(MODE_DELETE);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
|
||||
public OsmandActionBarActivity getActionBarActivity() {
|
||||
if (getActivity() instanceof OsmandActionBarActivity) {
|
||||
return (OsmandActionBarActivity) getActivity();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Object> createItemsList() {
|
||||
List<Recording> recs = new LinkedList<>(plugin.getAllRecordings());
|
||||
List<Object> res = new LinkedList<>();
|
||||
if (!recs.isEmpty()) {
|
||||
NotesSortByMode sortByMode = getMyApplication().getSettings().NOTES_SORT_BY_MODE.get();
|
||||
if (sortByMode.isByDate()) {
|
||||
res.add(NotesAdapter.TYPE_DATE_HEADER);
|
||||
res.addAll(sortItemsByDateDescending(recs));
|
||||
} else if (sortByMode.isByType()) {
|
||||
List<Recording> audios = new LinkedList<>();
|
||||
List<Recording> photos = new LinkedList<>();
|
||||
List<Recording> videos = new LinkedList<>();
|
||||
for (Recording rec : recs) {
|
||||
if (rec.isAudio()) {
|
||||
audios.add(rec);
|
||||
} else if (rec.isPhoto()) {
|
||||
photos.add(rec);
|
||||
} else {
|
||||
videos.add(rec);
|
||||
}
|
||||
}
|
||||
addToResIfNotEmpty(res, audios, NotesAdapter.TYPE_AUDIO_HEADER);
|
||||
addToResIfNotEmpty(res, photos, NotesAdapter.TYPE_PHOTO_HEADER);
|
||||
addToResIfNotEmpty(res, videos, NotesAdapter.TYPE_VIDEO_HEADER);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void addToResIfNotEmpty(List<Object> res, List<Recording> recs, int header) {
|
||||
if (!recs.isEmpty()) {
|
||||
res.add(header);
|
||||
res.addAll(recs);
|
||||
}
|
||||
}
|
||||
|
||||
private NotesAdapterListener createAdapterListener() {
|
||||
return new NotesAdapterListener() {
|
||||
|
||||
@Override
|
||||
public void onHeaderClick(int type, boolean checked) {
|
||||
if (checked) {
|
||||
selectAll(type);
|
||||
} else {
|
||||
deselectAll(type);
|
||||
}
|
||||
updateSelectionTitle(actionMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckBoxClick(Recording rec, boolean checked) {
|
||||
if (selectionMode) {
|
||||
if (checked) {
|
||||
selected.add(rec);
|
||||
} else {
|
||||
selected.remove(rec);
|
||||
}
|
||||
updateSelectionMode(actionMode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(Recording rec) {
|
||||
showOnMap(rec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOptionsClick(Recording rec) {
|
||||
ItemMenuBottomSheetDialogFragment fragment = new ItemMenuBottomSheetDialogFragment();
|
||||
fragment.setUsedOnMap(false);
|
||||
fragment.setListener(createItemMenuFragmentListener());
|
||||
fragment.setRecording(rec);
|
||||
fragment.setRetainInstance(true);
|
||||
fragment.show(getChildFragmentManager(), ItemMenuBottomSheetDialogFragment.TAG);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void showSortMenuFragment() {
|
||||
SortByMenuBottomSheetDialogFragment fragment = new SortByMenuBottomSheetDialogFragment();
|
||||
fragment.setUsedOnMap(false);
|
||||
fragment.setListener(createSortFragmentListener());
|
||||
fragment.show(getChildFragmentManager(), SortByMenuBottomSheetDialogFragment.TAG);
|
||||
}
|
||||
|
||||
private List<Recording> getRecordingsByType(int type) {
|
||||
List<Recording> allRecs = new LinkedList<>(plugin.getAllRecordings());
|
||||
List<Recording> res = new LinkedList<>();
|
||||
for (Recording rec : allRecs) {
|
||||
if (isAppropriate(rec, type)) {
|
||||
res.add(rec);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean isAppropriate(Recording rec, int type) {
|
||||
if (type == NotesAdapter.TYPE_AUDIO_HEADER) {
|
||||
return rec.isAudio();
|
||||
} else if (type == NotesAdapter.TYPE_PHOTO_HEADER) {
|
||||
return rec.isPhoto();
|
||||
}
|
||||
return rec.isVideo();
|
||||
}
|
||||
|
||||
private void selectAll(int type) {
|
||||
if (type == NotesAdapter.TYPE_DATE_HEADER) {
|
||||
for (int i = 0; i < listAdapter.getCount(); i++) {
|
||||
Object item = listAdapter.getItem(i);
|
||||
if (item instanceof Recording) {
|
||||
selected.add((Recording) item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected.addAll(getRecordingsByType(type));
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void deselectAll(int type) {
|
||||
if (type == NotesAdapter.TYPE_DATE_HEADER) {
|
||||
selected.clear();
|
||||
} else {
|
||||
selected.removeAll(getRecordingsByType(type));
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private List<Recording> sortItemsByDateDescending(List<Recording> recs) {
|
||||
Collections.sort(recs, new Comparator<Recording>() {
|
||||
@Override
|
||||
public int compare(Recording first, Recording second) {
|
||||
long firstTime = first.getLastModified();
|
||||
|
@ -158,197 +330,51 @@ public class NotesFragment extends OsmAndListFragment {
|
|||
}
|
||||
}
|
||||
});
|
||||
return recs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
menu.clear();
|
||||
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
|
||||
menu = ((ActionBarProgressActivity) getActivity()).getClearToolbar(true).getMenu();
|
||||
} else {
|
||||
((ActionBarProgressActivity) getActivity()).getClearToolbar(false);
|
||||
}
|
||||
((ActionBarProgressActivity) getActivity()).updateListViewFooter(footerView);
|
||||
|
||||
MenuItem item = menu.add(R.string.shared_string_share).
|
||||
setIcon(R.drawable.ic_action_export);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
private SortFragmentListener createSortFragmentListener() {
|
||||
return new SortFragmentListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
enterSelectionMode(MODE_SHARE);
|
||||
return true;
|
||||
public void onSortModeChanged() {
|
||||
recreateAdapterData();
|
||||
}
|
||||
});
|
||||
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
item = menu.add(R.string.shared_string_delete_all).
|
||||
setIcon(R.drawable.ic_action_delete_dark);
|
||||
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
enterSelectionMode(MODE_DELETE);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void enterSelectionMode(int type){
|
||||
enterDeleteMode(type);
|
||||
}
|
||||
|
||||
public OsmandActionBarActivity getActionBarActivity() {
|
||||
if (getActivity() instanceof OsmandActionBarActivity) {
|
||||
return (OsmandActionBarActivity) getActivity();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void enableSelectionMode(boolean selectionMode) {
|
||||
this.selectionMode = selectionMode;
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
view.findViewById(R.id.select_all).setVisibility(selectionMode ? View.VISIBLE : View.GONE);
|
||||
((FavoritesActivity) getActivity()).setToolbarVisibility(!selectionMode &&
|
||||
AndroidUiHelper.isOrientationPortrait(getActivity()));
|
||||
((FavoritesActivity) getActivity()).updateListViewFooter(footerView);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSelectionTitle(ActionMode m){
|
||||
if(selected.size() > 0) {
|
||||
m.setTitle(selected.size() + " " + getMyApplication().getString(R.string.shared_string_selected_lowercase));
|
||||
} else{
|
||||
m.setTitle("");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSelectionMode(ActionMode m) {
|
||||
updateSelectionTitle(m);
|
||||
refreshSelectAll();
|
||||
}
|
||||
|
||||
private void refreshSelectAll() {
|
||||
View view = getView();
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
CheckBox selectAll = (CheckBox) view.findViewById(R.id.select_all);
|
||||
for (int i = 0; i < listAdapter.getCount(); i++) {
|
||||
Recording point = listAdapter.getItem(i);
|
||||
if (!selected.contains(point)) {
|
||||
selectAll.setChecked(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
selectAll.setChecked(true);
|
||||
}
|
||||
|
||||
private void deleteItems(final ArrayList<Recording> selected) {
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
|
||||
b.setMessage(getString(R.string.local_recordings_delete_all_confirm, selected.size()));
|
||||
b.setPositiveButton(R.string.shared_string_delete, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Iterator<Recording> it = selected.iterator();
|
||||
while (it.hasNext()) {
|
||||
Recording pnt = it.next();
|
||||
plugin.deleteRecording(pnt, true);
|
||||
it.remove();
|
||||
listAdapter.delete(pnt);
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
|
||||
}
|
||||
});
|
||||
b.setNegativeButton(R.string.shared_string_cancel, null);
|
||||
b.show();
|
||||
}
|
||||
|
||||
private void shareItems(ArrayList<Recording> selected) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
|
||||
intent.setType("image/*"); /* This example is sharing jpeg images. */
|
||||
ArrayList<Uri> files = new ArrayList<Uri>();
|
||||
for(Recording path : selected) {
|
||||
if(path == shareLocationFile) {
|
||||
File fl = generateGPXForRecordings(selected);
|
||||
if(fl != null) {
|
||||
files.add(FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", fl));
|
||||
}
|
||||
} else {
|
||||
File src = path.getFile();
|
||||
File dst = new File(getActivity().getCacheDir(), "share/"+src.getName());
|
||||
try {
|
||||
Algorithms.fileCopy(src, dst);
|
||||
files.add(FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", dst));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.share_note)));
|
||||
}
|
||||
|
||||
private File generateGPXForRecordings(ArrayList<Recording> selected) {
|
||||
// File tmpFile = getMyApplication().getAppPath("cache/noteLocations.gpx");
|
||||
File tmpFile = new File(getActivity().getCacheDir(), "share/noteLocations.gpx");
|
||||
tmpFile.getParentFile().mkdirs();
|
||||
GPXFile file = new GPXFile();
|
||||
for(Recording r : selected) {
|
||||
if(r != shareLocationFile) {
|
||||
String desc = r.getDescriptionName(r.getFileName());
|
||||
if(desc == null) {
|
||||
desc = r.getFileName();
|
||||
}
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = r.getLatitude();
|
||||
wpt.lon = r.getLongitude();
|
||||
wpt.name = desc;
|
||||
wpt.link = r.getFileName();
|
||||
wpt.time = r.getFile().lastModified();
|
||||
wpt.category = r.getSearchHistoryType();
|
||||
getMyApplication().getSelectedGpxHelper().addPoint(wpt, file);
|
||||
}
|
||||
}
|
||||
GPXUtilities.writeGpxFile(tmpFile, file, getMyApplication());
|
||||
return tmpFile;
|
||||
};
|
||||
}
|
||||
|
||||
private void enterDeleteMode(final int type) {
|
||||
private void recreateAdapterData() {
|
||||
listAdapter.clear();
|
||||
listAdapter.addAll(createItemsList());
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void enterSelectionMode(final int type) {
|
||||
actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() {
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(final ActionMode mode, Menu menu) {
|
||||
LOG.debug("onCreateActionMode");
|
||||
if(type == MODE_SHARE) {
|
||||
listAdapter.insert(shareLocationFile, 0);
|
||||
}
|
||||
enableSelectionMode(true);
|
||||
MenuItem item;
|
||||
if(type == MODE_DELETE) {
|
||||
item = menu.add(R.string.shared_string_delete_all).setIcon(R.drawable.ic_action_delete_dark);
|
||||
} else {
|
||||
item = menu.add(R.string.shared_string_share).setIcon(R.drawable.ic_action_export);
|
||||
if (type == MODE_SHARE) {
|
||||
listAdapter.insert(SHARE_LOCATION_FILE, 0);
|
||||
}
|
||||
switchSelectionMode(true);
|
||||
int titleRes = type == MODE_DELETE ? R.string.shared_string_delete_all : R.string.shared_string_share;
|
||||
int iconRes = type == MODE_DELETE ? R.drawable.ic_action_delete_dark : R.drawable.ic_action_gshare_dark;
|
||||
MenuItem item = menu.add(titleRes).setIcon(iconRes);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if(type == MODE_DELETE) {
|
||||
if (type == MODE_DELETE) {
|
||||
deleteItems(selected);
|
||||
} else if(type == MODE_SHARE) {
|
||||
} else if (type == MODE_SHARE) {
|
||||
shareItems(selected);
|
||||
}
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
selected.clear();
|
||||
listAdapter.notifyDataSetInvalidated();
|
||||
updateSelectionMode(mode);
|
||||
return true;
|
||||
}
|
||||
|
@ -368,196 +394,154 @@ public class NotesFragment extends OsmAndListFragment {
|
|||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
LOG.debug("onDestroyActionMode");
|
||||
if(type == MODE_SHARE) {
|
||||
listAdapter.remove(shareLocationFile);
|
||||
if (type == MODE_SHARE) {
|
||||
listAdapter.remove(SHARE_LOCATION_FILE);
|
||||
}
|
||||
enableSelectionMode(false);
|
||||
switchSelectionMode(false);
|
||||
listAdapter.notifyDataSetInvalidated();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public OsmandApplication getMyApplication() {
|
||||
return (OsmandApplication) getActivity().getApplication();
|
||||
private void switchSelectionMode(boolean enable) {
|
||||
selectionMode = enable;
|
||||
listAdapter.setSelectionMode(enable);
|
||||
((FavoritesActivity) getActivity()).setToolbarVisibility(!enable && AndroidUiHelper.isOrientationPortrait(getActivity()));
|
||||
((FavoritesActivity) getActivity()).updateListViewFooter(footerView);
|
||||
}
|
||||
|
||||
class NotesAdapter extends ArrayAdapter<AudioVideoNotesPlugin.Recording> {
|
||||
|
||||
NotesAdapter(List<AudioVideoNotesPlugin.Recording> recordingList) {
|
||||
super(getActivity(), R.layout.note, recordingList);
|
||||
private void updateSelectionTitle(ActionMode m) {
|
||||
if (selected.size() > 0) {
|
||||
m.setTitle(selected.size() + " " + getString(R.string.shared_string_selected_lowercase));
|
||||
} else {
|
||||
m.setTitle("");
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(Recording pnt) {
|
||||
remove(pnt);
|
||||
|
||||
}
|
||||
private void updateSelectionMode(ActionMode m) {
|
||||
updateSelectionTitle(m);
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View row = convertView;
|
||||
if (row == null) {
|
||||
row = inflater.inflate(R.layout.note, parent, false);
|
||||
}
|
||||
|
||||
final AudioVideoNotesPlugin.Recording recording = getItem(position);
|
||||
if (recording == shareLocationFile) {
|
||||
((TextView) row.findViewById(R.id.name)).setText(R.string.av_locations);
|
||||
((TextView) row.findViewById(R.id.description)).setText(R.string.av_locations_descr);
|
||||
} else {
|
||||
DashAudioVideoNotesFragment.getNoteView(recording, row, getMyApplication());
|
||||
}
|
||||
// ((ImageView) row.findViewById(R.id.play)).setImageDrawable(getMyApplication().getIconsCache()
|
||||
// .getIcon(R.drawable.ic_play_dark));
|
||||
row.findViewById(R.id.play).setVisibility(View.GONE);
|
||||
|
||||
|
||||
final CheckBox ch = (CheckBox) row.findViewById(R.id.check_local_index);
|
||||
ImageButton options = (ImageButton) row.findViewById(R.id.options);
|
||||
options.setImageDrawable(getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_overflow_menu_white));
|
||||
if(selectionMode) {
|
||||
options.setVisibility(View.GONE);
|
||||
ch.setVisibility(View.VISIBLE);
|
||||
ch.setChecked(selected.contains(recording));
|
||||
row.findViewById(R.id.icon).setVisibility(View.GONE);
|
||||
ch.setOnClickListener(new View.OnClickListener() {
|
||||
private void deleteItems(final Set<Recording> selected) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(getString(R.string.local_recordings_delete_all_confirm, selected.size()))
|
||||
.setPositiveButton(R.string.shared_string_delete, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onItemSelect(ch, recording);
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Iterator<Recording> it = selected.iterator();
|
||||
while (it.hasNext()) {
|
||||
Recording rec = it.next();
|
||||
plugin.deleteRecording(rec, true);
|
||||
it.remove();
|
||||
}
|
||||
recreateAdapterData();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.shared_string_cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void shareItems(Set<Recording> selected) {
|
||||
ArrayList<Uri> files = new ArrayList<>();
|
||||
for (Recording rec : selected) {
|
||||
File file = rec == SHARE_LOCATION_FILE ? generateGPXForRecordings(selected) : rec.getFile();
|
||||
if (file != null) {
|
||||
files.add(Uri.parse(file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
|
||||
intent.setType("*/*");
|
||||
intent.putExtra(Intent.EXTRA_STREAM, files);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
if (Build.VERSION.SDK_INT > 18) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.share_note)));
|
||||
}
|
||||
|
||||
private File generateGPXForRecordings(Set<Recording> selected) {
|
||||
File tmpFile = new File(getActivity().getCacheDir(), "share/noteLocations.gpx");
|
||||
tmpFile.getParentFile().mkdirs();
|
||||
GPXFile file = new GPXFile();
|
||||
for (Recording r : selected) {
|
||||
if (r != SHARE_LOCATION_FILE) {
|
||||
String desc = r.getDescriptionName(r.getFileName());
|
||||
if (desc == null) {
|
||||
desc = r.getFileName();
|
||||
}
|
||||
WptPt wpt = new WptPt();
|
||||
wpt.lat = r.getLatitude();
|
||||
wpt.lon = r.getLongitude();
|
||||
wpt.name = desc;
|
||||
wpt.link = r.getFileName();
|
||||
wpt.time = r.getFile().lastModified();
|
||||
wpt.category = r.getSearchHistoryType();
|
||||
getMyApplication().getSelectedGpxHelper().addPoint(wpt, file);
|
||||
}
|
||||
}
|
||||
GPXUtilities.writeGpxFile(tmpFile, file, getMyApplication());
|
||||
return tmpFile;
|
||||
}
|
||||
|
||||
private ItemMenuFragmentListener createItemMenuFragmentListener() {
|
||||
return new ItemMenuFragmentListener() {
|
||||
@Override
|
||||
public void playOnClick(Recording recording) {
|
||||
plugin.playRecording(getActivity(), recording);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shareOnClick(Recording recording) {
|
||||
shareNote(recording);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showOnMapOnClick(Recording recording) {
|
||||
showOnMap(recording);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameOnClick(Recording recording) {
|
||||
editNote(recording);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteOnClick(final Recording recording) {
|
||||
deleteNote(recording);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void shareNote(final Recording recording) {
|
||||
if (!recording.getFile().exists()) {
|
||||
return;
|
||||
}
|
||||
MediaScannerConnection.scanFile(getActivity(), new String[]{recording.getFile().getAbsolutePath()},
|
||||
null, new MediaScannerConnection.OnScanCompletedListener() {
|
||||
public void onScanCompleted(String path, Uri uri) {
|
||||
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
if (recording.isPhoto()) {
|
||||
shareIntent.setType("image/*");
|
||||
} else if (recording.isAudio()) {
|
||||
shareIntent.setType("audio/*");
|
||||
} else if (recording.isVideo()) {
|
||||
shareIntent.setType("video/*");
|
||||
}
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_note)));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
row.findViewById(R.id.icon).setVisibility(View.VISIBLE);
|
||||
options.setVisibility(View.VISIBLE);
|
||||
ch.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
options.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openPopUpMenu(v, recording);
|
||||
}
|
||||
});
|
||||
row.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (selectionMode) {
|
||||
ch.setChecked(!ch.isChecked());
|
||||
onItemSelect(ch, recording);
|
||||
} else {
|
||||
showOnMap(recording);
|
||||
}
|
||||
}
|
||||
});
|
||||
return row;
|
||||
}
|
||||
|
||||
public void onItemSelect(CheckBox ch, Recording child) {
|
||||
if (ch.isChecked()) {
|
||||
selected.add(child);
|
||||
} else {
|
||||
selected.remove(child);
|
||||
}
|
||||
updateSelectionMode(actionMode);
|
||||
}
|
||||
}
|
||||
|
||||
private void showOnMap(Recording recording) {
|
||||
getMyApplication().getSettings().setMapLocationToShow(recording.getLatitude(), recording.getLongitude(), 15,
|
||||
new PointDescription(recording.getSearchHistoryType(), recording.getName(getActivity(), true)), true,
|
||||
recording); //$NON-NLS-1$
|
||||
new PointDescription(recording.getSearchHistoryType(), recording.getName(getActivity(), true)),
|
||||
true, recording);
|
||||
MapActivity.launchMapActivityMoveToTop(getActivity());
|
||||
}
|
||||
|
||||
private void openPopUpMenu(View v, final AudioVideoNotesPlugin.Recording recording) {
|
||||
IconsCache iconsCache = getMyApplication().getIconsCache();
|
||||
final PopupMenu optionsMenu = new PopupMenu(getActivity(), v);
|
||||
DirectionsDialogs.setupPopUpMenuIcon(optionsMenu);
|
||||
MenuItem item;
|
||||
boolean isPhoto = recording.isPhoto();
|
||||
Drawable playIcon;
|
||||
if (isPhoto) {
|
||||
playIcon = getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_action_view);
|
||||
} else {
|
||||
playIcon = getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_play_dark);
|
||||
}
|
||||
item = optionsMenu.getMenu().add(isPhoto ? R.string.watch : R.string.recording_context_menu_play)
|
||||
.setIcon(playIcon);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
plugin.playRecording(getActivity(), recording);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
item = optionsMenu.getMenu().add(R.string.shared_string_show_on_map).setIcon(
|
||||
iconsCache.getThemedIcon(R.drawable.ic_show_on_map));
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
showOnMap(recording);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
item = optionsMenu.getMenu().add(R.string.shared_string_share)
|
||||
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_gshare_dark));
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
|
||||
if (recording.isPhoto()) {
|
||||
Uri screenshotUri = Uri.parse(recording.getFile().getAbsolutePath());
|
||||
sharingIntent.setType("image/*");
|
||||
sharingIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
|
||||
} else if (recording.isAudio()) {
|
||||
Uri audioUri = Uri.parse(recording.getFile().getAbsolutePath());
|
||||
sharingIntent.setType("audio/*");
|
||||
sharingIntent.putExtra(Intent.EXTRA_STREAM, audioUri);
|
||||
} else if (recording.isVideo()) {
|
||||
Uri videoUri = Uri.parse(recording.getFile().getAbsolutePath());
|
||||
sharingIntent.setType("video/*");
|
||||
sharingIntent.putExtra(Intent.EXTRA_STREAM, videoUri);
|
||||
}
|
||||
startActivity(Intent.createChooser(sharingIntent, getString(R.string.share_note)));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
item = optionsMenu.getMenu().add(R.string.shared_string_rename)
|
||||
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark));
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
editNote(recording);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
item = optionsMenu.getMenu().add(R.string.recording_context_menu_delete)
|
||||
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_delete_dark));
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage(R.string.recording_delete_confirm);
|
||||
builder.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
plugin.deleteRecording(recording, true);
|
||||
listAdapter.remove(recording);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.shared_string_cancel, null);
|
||||
builder.show();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
optionsMenu.show();
|
||||
}
|
||||
|
||||
private void editNote(final Recording recording) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.shared_string_rename);
|
||||
|
@ -581,4 +565,17 @@ public class NotesFragment extends OsmAndListFragment {
|
|||
editText.requestFocus();
|
||||
}
|
||||
|
||||
private void deleteNote(final Recording recording) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.recording_delete_confirm)
|
||||
.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
plugin.deleteRecording(recording, true);
|
||||
listAdapter.remove(recording);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.shared_string_cancel, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package net.osmand.plus.audionotes;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import net.osmand.plus.OsmandSettings;
|
||||
import net.osmand.plus.OsmandSettings.NotesSortByMode;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
||||
|
||||
public class SortByMenuBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
|
||||
|
||||
public static final String TAG = "SortByMenuBottomSheetDialogFragment";
|
||||
|
||||
private SortFragmentListener listener;
|
||||
|
||||
public void setListener(SortFragmentListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
|
||||
|
||||
final View mainView = View.inflate(new ContextThemeWrapper(getContext(), themeRes),
|
||||
R.layout.fragment_notes_sort_bottom_sheet_dialog, null);
|
||||
|
||||
((ImageView) mainView.findViewById(R.id.by_type_icon)).setImageDrawable(getContentIcon(R.drawable.ic_groped_by_type));
|
||||
((ImageView) mainView.findViewById(R.id.by_date_icon)).setImageDrawable(getContentIcon(R.drawable.ic_action_sort_by_date));
|
||||
|
||||
mainView.findViewById(R.id.by_type_row).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
selectSortByMode(NotesSortByMode.BY_TYPE);
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.by_date_row).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
selectSortByMode(NotesSortByMode.BY_DATE);
|
||||
}
|
||||
});
|
||||
mainView.findViewById(R.id.close_row).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
setupHeightAndBackground(mainView, R.id.scroll_view);
|
||||
|
||||
return mainView;
|
||||
}
|
||||
|
||||
private void selectSortByMode(NotesSortByMode mode) {
|
||||
final OsmandSettings.CommonPreference<NotesSortByMode> sortByMode = getMyApplication().getSettings().NOTES_SORT_BY_MODE;
|
||||
if (sortByMode.get() != mode) {
|
||||
sortByMode.set(mode);
|
||||
if (listener != null) {
|
||||
listener.onSortModeChanged();
|
||||
}
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
interface SortFragmentListener {
|
||||
void onSortModeChanged();
|
||||
}
|
||||
}
|
260
OsmAnd/src/net/osmand/plus/audionotes/adapters/NotesAdapter.java
Normal file
260
OsmAnd/src/net/osmand/plus/audionotes/adapters/NotesAdapter.java
Normal file
|
@ -0,0 +1,260 @@
|
|||
package net.osmand.plus.audionotes.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
|
||||
import net.osmand.plus.audionotes.NotesFragment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class NotesAdapter extends ArrayAdapter<Object> {
|
||||
|
||||
public static final int TYPE_DATE_HEADER = 0;
|
||||
public static final int TYPE_AUDIO_HEADER = 1;
|
||||
public static final int TYPE_PHOTO_HEADER = 2;
|
||||
public static final int TYPE_VIDEO_HEADER = 3;
|
||||
private static final int TYPE_ITEM = 4;
|
||||
private static final int TYPE_COUNT = 5;
|
||||
|
||||
private OsmandApplication app;
|
||||
private NotesAdapterListener listener;
|
||||
|
||||
private boolean selectionMode;
|
||||
private Set<Recording> selected;
|
||||
|
||||
public void setListener(NotesAdapterListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setSelectionMode(boolean selectionMode) {
|
||||
this.selectionMode = selectionMode;
|
||||
}
|
||||
|
||||
public void setSelected(Set<Recording> selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public NotesAdapter(OsmandApplication app, List<Object> items) {
|
||||
super(app, R.layout.note, items);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(final int position, View row, @NonNull ViewGroup parent) {
|
||||
final int type = getItemViewType(position);
|
||||
boolean header = type == TYPE_DATE_HEADER
|
||||
|| type == TYPE_AUDIO_HEADER
|
||||
|| type == TYPE_PHOTO_HEADER
|
||||
|| type == TYPE_VIDEO_HEADER;
|
||||
|
||||
if (row == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) app.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
if (header) {
|
||||
row = inflater.inflate(R.layout.list_item_header, parent, false);
|
||||
HeaderViewHolder hHolder = new HeaderViewHolder(row);
|
||||
row.setTag(hHolder);
|
||||
} else {
|
||||
row = inflater.inflate(R.layout.note_list_item, parent, false);
|
||||
ItemViewHolder iHolder = new ItemViewHolder(row);
|
||||
row.setTag(iHolder);
|
||||
}
|
||||
}
|
||||
|
||||
if (header) {
|
||||
final HeaderViewHolder holder = (HeaderViewHolder) row.getTag();
|
||||
holder.checkBox.setVisibility(selectionMode ? View.VISIBLE : View.GONE);
|
||||
holder.headerRow.setEnabled(selectionMode);
|
||||
if (selectionMode) {
|
||||
holder.checkBox.setChecked(isSelectAllChecked(type));
|
||||
holder.checkBox.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
listener.onHeaderClick(type, holder.checkBox.isChecked());
|
||||
}
|
||||
}
|
||||
});
|
||||
holder.headerRow.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
holder.checkBox.performClick();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
holder.view.setOnClickListener(null);
|
||||
}
|
||||
int titleId;
|
||||
if (type == TYPE_DATE_HEADER) {
|
||||
titleId = R.string.notes_by_date;
|
||||
} else if (type == TYPE_AUDIO_HEADER) {
|
||||
titleId = R.string.shared_string_audio;
|
||||
} else if (type == TYPE_PHOTO_HEADER) {
|
||||
titleId = R.string.shared_string_photo;
|
||||
} else {
|
||||
titleId = R.string.shared_string_video;
|
||||
}
|
||||
holder.title.setText(titleId);
|
||||
} else {
|
||||
final Object item = getItem(position);
|
||||
if (item instanceof Recording) {
|
||||
final Recording recording = (Recording) item;
|
||||
final ItemViewHolder holder = (ItemViewHolder) row.getTag();
|
||||
|
||||
if (recording == NotesFragment.SHARE_LOCATION_FILE) {
|
||||
holder.title.setText(R.string.av_locations);
|
||||
holder.description.setText(R.string.av_locations_descr);
|
||||
} else {
|
||||
holder.title.setText(recording.getName(app, true));
|
||||
holder.description.setText(recording.getNewSmallDescription(app));
|
||||
int iconRes = recording.isAudio() ? R.drawable.ic_type_audio
|
||||
: (recording.isVideo() ? R.drawable.ic_type_video : R.drawable.ic_type_img);
|
||||
int colorRes = app.getSettings().isLightContent() ? R.color.icon_color : R.color.ctx_menu_info_text_dark;
|
||||
holder.icon.setImageDrawable(app.getIconsCache().getIcon(iconRes, colorRes));
|
||||
}
|
||||
|
||||
holder.bottomDivider.setVisibility(hideBottomDivider(position) ? View.GONE : View.VISIBLE);
|
||||
holder.icon.setVisibility(selectionMode ? View.GONE : View.VISIBLE);
|
||||
holder.checkBox.setVisibility(selectionMode ? View.VISIBLE : View.GONE);
|
||||
holder.options.setVisibility(selectionMode ? View.GONE : View.VISIBLE);
|
||||
if (selectionMode) {
|
||||
holder.checkBox.setChecked(selected.contains(recording));
|
||||
holder.checkBox.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
listener.onCheckBoxClick(recording, holder.checkBox.isChecked());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
holder.options.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_overflow_menu_white));
|
||||
holder.options.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
listener.onOptionsClick(recording);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
holder.view.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (selectionMode) {
|
||||
holder.checkBox.performClick();
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onItemClick(recording);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Object item = getItem(position);
|
||||
if (item instanceof Recording) {
|
||||
return TYPE_ITEM;
|
||||
}
|
||||
return (int) item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return TYPE_COUNT;
|
||||
}
|
||||
|
||||
private boolean hideBottomDivider(int pos) {
|
||||
return pos == getCount() - 1 || !(getItem(pos + 1) instanceof Recording);
|
||||
}
|
||||
|
||||
private boolean isSelectAllChecked(int type) {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
Object item = getItem(i);
|
||||
if (item instanceof Recording) {
|
||||
if (type != TYPE_DATE_HEADER && !isAppropriate((Recording) item, type)) {
|
||||
continue;
|
||||
}
|
||||
if (!selected.contains(item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isAppropriate(Recording rec, int type) {
|
||||
if (type == NotesAdapter.TYPE_AUDIO_HEADER) {
|
||||
return rec.isAudio();
|
||||
} else if (type == NotesAdapter.TYPE_PHOTO_HEADER) {
|
||||
return rec.isPhoto();
|
||||
}
|
||||
return rec.isVideo();
|
||||
}
|
||||
|
||||
private class HeaderViewHolder {
|
||||
|
||||
final View view;
|
||||
final View headerRow;
|
||||
final CheckBox checkBox;
|
||||
final TextView title;
|
||||
|
||||
HeaderViewHolder(View view) {
|
||||
this.view = view;
|
||||
headerRow = view.findViewById(R.id.header_row);
|
||||
checkBox = (CheckBox) view.findViewById(R.id.check_box);
|
||||
title = (TextView) view.findViewById(R.id.title_text_view);
|
||||
}
|
||||
}
|
||||
|
||||
private class ItemViewHolder {
|
||||
|
||||
final View view;
|
||||
final ImageView icon;
|
||||
final CheckBox checkBox;
|
||||
final TextView title;
|
||||
final TextView description;
|
||||
final ImageButton options;
|
||||
final View bottomDivider;
|
||||
|
||||
ItemViewHolder(View view) {
|
||||
this.view = view;
|
||||
icon = (ImageView) view.findViewById(R.id.icon);
|
||||
checkBox = (CheckBox) view.findViewById(R.id.check_box);
|
||||
title = (TextView) view.findViewById(R.id.title);
|
||||
description = (TextView) view.findViewById(R.id.description);
|
||||
options = (ImageButton) view.findViewById(R.id.options);
|
||||
bottomDivider = view.findViewById(R.id.bottom_divider);
|
||||
}
|
||||
}
|
||||
|
||||
public interface NotesAdapterListener {
|
||||
|
||||
void onHeaderClick(int type, boolean checked);
|
||||
|
||||
void onCheckBoxClick(Recording rec, boolean checked);
|
||||
|
||||
void onItemClick(Recording rec);
|
||||
|
||||
void onOptionsClick(Recording rec);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue