Reorder app modes initial commit

This commit is contained in:
Chumva 2019-12-12 14:05:56 +02:00
parent 349212bbc7
commit d453b1e6fc
7 changed files with 442 additions and 14 deletions

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/activity_background_color"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/global_preference_toolbar" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/profiles_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/list_background_color"
android:clipToPadding="false"
android:paddingBottom="72dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<ImageView
android:id="@+id/buttons_shadow"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_gravity="bottom"
android:background="@drawable/bg_contextmenu_shadow_top_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?attr/list_background_color"
android:orientation="horizontal"
android:paddingLeft="@dimen/content_padding"
android:paddingTop="@dimen/content_padding_small"
android:paddingRight="@dimen/content_padding"
android:paddingBottom="@dimen/content_padding_small">
<include
android:id="@+id/cancel_button"
layout="@layout/bottom_sheet_dialog_button" />
<View
android:id="@+id/buttons_divider"
android:layout_width="@dimen/content_padding"
android:layout_height="match_parent" />
<include
android:id="@+id/apply_button"
layout="@layout/bottom_sheet_dialog_button" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>

View file

@ -11,6 +11,7 @@
Thx - Hardy Thx - Hardy
--> -->
<string name="edit_profiles">Edit profiles</string>
<string name="select_nav_profile_dialog_message">Navigation type affects the rules for route calculations.</string> <string name="select_nav_profile_dialog_message">Navigation type affects the rules for route calculations.</string>
<string name="distance_and_address">%1$s • %2$s</string> <string name="distance_and_address">%1$s • %2$s</string>
<string name="street_city">%1$s, %2$s</string> <string name="street_city">%1$s, %2$s</string>

View file

@ -58,6 +58,7 @@
android:layout="@layout/preference_button" android:layout="@layout/preference_button"
android:persistent="false" android:persistent="false"
android:title="@string/reorder_profiles" android:title="@string/reorder_profiles"
app:fragment="net.osmand.plus.settings.EditProfilesFragment"
tools:icon="@drawable/ic_action_edit_dark" /> tools:icon="@drawable/ic_action_edit_dark" />
<Preference <Preference

View file

@ -17,6 +17,7 @@ import net.osmand.util.Algorithms;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -61,6 +62,7 @@ public class ApplicationMode {
private final String stringKey; private final String stringKey;
private String userProfileName; private String userProfileName;
private int descriptionId; private int descriptionId;
private int order;
private ApplicationMode parentAppMode; private ApplicationMode parentAppMode;
private String iconResName = "ic_world_globe_dark"; private String iconResName = "ic_world_globe_dark";
@ -127,7 +129,7 @@ public class ApplicationMode {
@Expose ProfileIconColors iconColor = ProfileIconColors.DEFAULT; @Expose ProfileIconColors iconColor = ProfileIconColors.DEFAULT;
@Expose String routingProfile = null; @Expose String routingProfile = null;
@Expose RouteService routeService = RouteService.OSMAND; @Expose RouteService routeService = RouteService.OSMAND;
@Expose int order;
} }
private static void initRegVisibility() { private static void initRegVisibility() {
@ -337,6 +339,11 @@ public class ApplicationMode {
applicationMode.iconColor = colorData; applicationMode.iconColor = colorData;
return this; return this;
} }
public ApplicationModeBuilder setOrder(int order) {
applicationMode.order = order;
return this;
}
} }
private static ApplicationModeBuilder create(ApplicationMode parent, int key, String stringKey) { private static ApplicationModeBuilder create(ApplicationMode parent, int key, String stringKey) {
@ -619,6 +626,13 @@ public class ApplicationMode {
} }
} }
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public static void onApplicationStart(OsmandApplication app) { public static void onApplicationStart(OsmandApplication app) {
// load for default profiles to initialize later custom modes // load for default profiles to initialize later custom modes
@ -627,6 +641,7 @@ public class ApplicationMode {
initCustomModes(app); initCustomModes(app);
initDefaultSpeed(app); initDefaultSpeed(app);
initRegVisibility(); initRegVisibility();
reorderAppModes();
} }
private static void initDefaultSpeed(OsmandApplication app) { private static void initDefaultSpeed(OsmandApplication app) {
@ -638,6 +653,19 @@ public class ApplicationMode {
} }
} }
public static void reorderAppModes() {
Comparator<ApplicationMode> comparator = new Comparator<ApplicationMode>() {
@Override
public int compare(ApplicationMode o1, ApplicationMode o2) {
return (o1.order < o2.order) ? -1 : ((o1.order == o2.order) ? 0 : 1);
}
};
Collections.sort(values, comparator);
Collections.sort(customValues, comparator);
Collections.sort(defaultValues, comparator);
Collections.sort(cachedFilteredValues, comparator);
}
public static ApplicationModeBuilder fromJson(OsmandApplication app, String json) { public static ApplicationModeBuilder fromJson(OsmandApplication app, String json) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
ApplicationModeBean mb = gson.fromJson(json, ApplicationModeBean.class); ApplicationModeBean mb = gson.fromJson(json, ApplicationModeBean.class);
@ -677,6 +705,7 @@ public class ApplicationMode {
applicationMode.iconColor = modeBean.iconColor; applicationMode.iconColor = modeBean.iconColor;
applicationMode.routingProfile = modeBean.routingProfile; applicationMode.routingProfile = modeBean.routingProfile;
applicationMode.routeService = modeBean.routeService; applicationMode.routeService = modeBean.routeService;
applicationMode.order = modeBean.order;
} }
} }
} }
@ -689,15 +718,29 @@ public class ApplicationMode {
if (!Algorithms.isEmpty(customProfiles)) { if (!Algorithms.isEmpty(customProfiles)) {
for (ApplicationModeBean m : customProfiles) { for (ApplicationModeBean m : customProfiles) {
ApplicationModeBuilder b = createCustomMode(valueOfStringKey(m.parent, CAR), ApplicationMode parentMode = valueOfStringKey(m.parent, CAR);
m.userProfileName, m.stringKey); createCustomMode(parentMode, m.userProfileName, m.stringKey)
b.setRouteService(m.routeService).setRoutingProfile(m.routingProfile); .setRouteService(m.routeService)
b.icon(app, m.iconName); .setRoutingProfile(m.routingProfile)
b.setColor(m.iconColor); .icon(app, m.iconName)
b.customReg(); .setColor(m.iconColor)
.setOrder(m.order)
.customReg();
} }
} }
}
public static void saveAppModesToSettings(OsmandSettings settings) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
List<ApplicationModeBean> defaultModeBeans = createApplicationModeBeans(defaultValues);
List<ApplicationModeBean> customModeBeans = createApplicationModeBeans(customValues);
String defaultProfiles = gson.toJson(defaultModeBeans);
String customProfiles = gson.toJson(customModeBeans);
settings.DEFAULT_APP_PROFILES.set(defaultProfiles);
settings.CUSTOM_APP_PROFILES.set(customProfiles);
} }
private static void saveAppModesToSettings(OsmandSettings settings, boolean saveCustomModes) { private static void saveAppModesToSettings(OsmandSettings settings, boolean saveCustomModes) {
@ -724,6 +767,7 @@ public class ApplicationMode {
mb.stringKey = mode.stringKey; mb.stringKey = mode.stringKey;
mb.routeService = mode.routeService; mb.routeService = mode.routeService;
mb.routingProfile = mode.routingProfile; mb.routingProfile = mode.routingProfile;
mb.order = mode.order;
modeBeans.add(mb); modeBeans.add(mb);
} }
@ -740,6 +784,7 @@ public class ApplicationMode {
mode.routingProfile = builder.applicationMode.routingProfile; mode.routingProfile = builder.applicationMode.routingProfile;
mode.routeService = builder.applicationMode.routeService; mode.routeService = builder.applicationMode.routeService;
mode.iconColor = builder.applicationMode.iconColor; mode.iconColor = builder.applicationMode.iconColor;
mode.order = builder.applicationMode.order;
} else { } else {
mode = builder.customReg(); mode = builder.customReg();
initRegVisibility(); initRegVisibility();
@ -807,12 +852,7 @@ public class ApplicationMode {
} }
public int getColor(boolean nightMode) { public int getColor(boolean nightMode) {
if (nightMode) { return nightMode ? nightColor : dayColor;
return nightColor;
} else {
return dayColor;
}
} }
} }
} }

View file

@ -0,0 +1,137 @@
package net.osmand.plus.profiles;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import net.osmand.AndroidUtils;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.settings.BaseSettingsFragment;
import java.util.Collections;
import java.util.List;
public class ProfilesAdapter extends AbstractProfileMenuAdapter<ProfilesAdapter.SelectProfileViewHolder>
implements ProfilesItemTouchHelperCallback.ItemTouchHelperAdapter {
private OsmandApplication app;
private List<ApplicationMode> applicationModes;
private ProfilesAdapterListener listener;
private boolean nightMode;
public ProfilesAdapter(MapActivity mapActivity, List<ApplicationMode> applicationModes) {
setHasStableIds(true);
app = mapActivity.getMyApplication();
this.applicationModes = applicationModes;
nightMode = !mapActivity.getMyApplication().getSettings().isLightContent();
}
public void setAdapterListener(ProfilesAdapterListener listener) {
this.listener = listener;
}
@NonNull
@Override
public SelectProfileViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View itemView = UiUtilities.getInflater(viewGroup.getContext(), nightMode).inflate(R.layout.profile_list_item, null);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onItemClick(view);
}
});
return new SelectProfileViewHolder(itemView);
}
@Override
public void onBindViewHolder(final SelectProfileViewHolder holder, final int pos) {
ApplicationMode mode = applicationModes.get(pos);
holder.icon.setVisibility(View.VISIBLE);
holder.descr.setVisibility(View.VISIBLE);
holder.switcher.setVisibility(View.GONE);
holder.menuIcon.setVisibility(View.VISIBLE);
holder.title.setText(mode.toHumanString(app));
holder.descr.setText(BaseSettingsFragment.getAppModeDescription(app, mode));
//set up cell color
int profileColorResId = mode.getIconColorInfo().getColor(nightMode);
int colorNoAlpha = ContextCompat.getColor(app, profileColorResId);
Drawable drawable = UiUtilities.getColoredSelectableDrawable(app, colorNoAlpha, 0.3f);
AndroidUtils.setBackground(holder.profileOptions, drawable);
updateViewHolder(holder, mode);
holder.menuIcon.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
listener.onDragStarted(holder);
}
return false;
}
});
}
@Override
public int getItemCount() {
return applicationModes.size();
}
@Override
public boolean onItemMove(int from, int to) {
Collections.swap(applicationModes, from, to);
notifyItemMoved(from, to);
return true;
}
@Override
public long getItemId(int position) {
return applicationModes.get(position).hashCode();
}
@Override
public void onItemDismiss(RecyclerView.ViewHolder holder) {
listener.onDragOrSwipeEnded(holder);
}
private void updateViewHolder(SelectProfileViewHolder holder, ApplicationMode mode) {
int iconRes = mode.getIconRes();
if (iconRes == 0 || iconRes == -1) {
iconRes = R.drawable.ic_action_world_globe;
}
int selectedIconColorRes = mode.getIconColorInfo().getColor(nightMode);
holder.icon.setImageDrawable(app.getUIUtilities().getIcon(iconRes, selectedIconColorRes));
}
public ApplicationMode getItem(int position) {
return applicationModes.get(position);
}
class SelectProfileViewHolder extends ProfileAbstractViewHolder {
SelectProfileViewHolder(View itemView) {
super(itemView);
}
}
public interface ProfilesAdapterListener {
void onItemClick(View view);
void onDragStarted(RecyclerView.ViewHolder holder);
void onDragOrSwipeEnded(RecyclerView.ViewHolder holder);
}
}

View file

@ -0,0 +1,57 @@
package net.osmand.plus.profiles;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
public class ProfilesItemTouchHelperCallback extends ItemTouchHelper.Callback {
private ProfilesItemTouchHelperCallback.ItemTouchHelperAdapter adapter;
public ProfilesItemTouchHelperCallback(ProfilesItemTouchHelperCallback.ItemTouchHelperAdapter adapter) {
this.adapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
return makeMovementFlags(dragFlags, 0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
int from = source.getAdapterPosition();
int to = target.getAdapterPosition();
if (from == RecyclerView.NO_POSITION || to == RecyclerView.NO_POSITION) {
return false;
}
return adapter.onItemMove(from, to);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
adapter.onItemDismiss(viewHolder);
}
interface ItemTouchHelperAdapter {
boolean onItemMove(int from, int to);
void onItemDismiss(RecyclerView.ViewHolder holder);
}
}

View file

@ -0,0 +1,120 @@
package net.osmand.plus.settings;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.profiles.ProfilesAdapter;
import net.osmand.plus.profiles.ProfilesItemTouchHelperCallback;
import java.util.ArrayList;
import java.util.List;
public class EditProfilesFragment extends BaseOsmAndFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
MapActivity mapActivity = (MapActivity) getActivity();
View mainView = inflater.inflate(R.layout.edit_profiles_list_fragment, container, false);
AndroidUtils.addStatusBarPadding21v(getContext(), mainView);
ImageButton closeButton = mainView.findViewById(R.id.close_button);
closeButton.setImageResource(R.drawable.ic_action_remove_dark);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity != null) {
fragmentActivity.onBackPressed();
}
}
});
TextView toolbarTitle = mainView.findViewById(R.id.toolbar_title);
toolbarTitle.setText(R.string.edit_profiles);
RecyclerView recyclerView = mainView.findViewById(R.id.profiles_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
final List<ApplicationMode> applicationModes = new ArrayList<>(ApplicationMode.allPossibleValues());
final ProfilesAdapter adapter = new ProfilesAdapter(mapActivity, applicationModes);
final ItemTouchHelper touchHelper = new ItemTouchHelper(new ProfilesItemTouchHelperCallback(adapter));
touchHelper.attachToRecyclerView(recyclerView);
adapter.setAdapterListener(new ProfilesAdapter.ProfilesAdapterListener() {
private int fromPosition;
private int toPosition;
@Override
public void onItemClick(View view) {
}
@Override
public void onDragStarted(RecyclerView.ViewHolder holder) {
fromPosition = holder.getAdapterPosition();
touchHelper.startDrag(holder);
}
@Override
public void onDragOrSwipeEnded(RecyclerView.ViewHolder holder) {
toPosition = holder.getAdapterPosition();
if (toPosition >= 0 && fromPosition >= 0 && toPosition != fromPosition) {
adapter.notifyDataSetChanged();
}
}
});
recyclerView.setAdapter(adapter);
View cancelButton = mainView.findViewById(R.id.cancel_button);
UiUtilities.setupDialogButton(false, cancelButton, UiUtilities.DialogButtonType.SECONDARY, R.string.shared_string_cancel);
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity != null) {
fragmentActivity.onBackPressed();
}
}
});
View applyButton = mainView.findViewById(R.id.apply_button);
UiUtilities.setupDialogButton(false, applyButton, UiUtilities.DialogButtonType.PRIMARY, R.string.shared_string_apply);
applyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = (MapActivity) getActivity();
if (mapActivity != null) {
OsmandSettings settings = mapActivity.getMyApplication().getSettings();
for (int i = 0; i < applicationModes.size(); i++) {
ApplicationMode mode = applicationModes.get(i);
mode.setOrder(i);
}
ApplicationMode.reorderAppModes();
ApplicationMode.saveAppModesToSettings(settings);
mapActivity.onBackPressed();
}
}
});
return mainView;
}
}