✨ feat(ui): add AppSettingsPopup for individual app settings

This commit is contained in:
sankalp committed 2025-06-30 11:02:59 +05:45
1 parent 9bcb0eb0e0
commit 5ac0316d58
10 files changed
+650 -185

No files matched your search

@@ -79,12 +79,14 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import io.github.sankalp.lunox.dialogs.AppSettingsPopup;
import io.github.sankalp.lunox.dialogs.ColorSizeDialog;
import io.github.sankalp.lunox.dialogs.FrozenAppsDialogs;
import io.github.sankalp.lunox.dialogs.GlobalColorSizeDialog;
import io.github.sankalp.lunox.dialogs.GlobalSettingsDialog;
import io.github.sankalp.lunox.dialogs.HiddenAppsDialogs;
import io.github.sankalp.lunox.dialogs.PaddingDialog;
import io.github.sankalp.lunox.dialogs.PermissionDialog;
import io.github.sankalp.lunox.dialogs.RenameInputDialogs;
import io.github.sankalp.lunox.model.Apps;
import io.github.sankalp.lunox.model.Shortcut;
@@ -564,13 +566,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
// If we have very few apps, try reloading in case permissions were granted
loadApps();
}
// Check if search box is visible and hide it if needed
if (mSearchBox.getVisibility() == View.VISIBLE) {
mSearchBox.setVisibility(View.GONE);
mHomeLayout.setPadding(DbUtils.getPaddingLeft(), DbUtils.getPaddingTop(), DbUtils.getPaddingRight(), DbUtils.getPaddingBottom());
}
// Reset search state
searching = false;
}
@@ -605,88 +607,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
private void showPopup(String activityName, AppTextView view) {
Context context;
// set theme
// if theme wallpaper ie transparent then we have to show other theme
if (DbUtils.getTheme() == R.style.Wallpaper)
context = new ContextThemeWrapper(this, R.style.AppTheme);
else
context = new ContextThemeWrapper(this, DbUtils.getTheme());
PopupMenu popupMenu = new PopupMenu(context, view);
popupMenu.getMenuInflater().inflate(R.menu.menu, popupMenu.getMenu());
int color = Color.parseColor("#E53935");
SpannableString s = new SpannableString(getString(R.string.hide));
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
popupMenu.getMenu().findItem(R.id.menu_hide).setTitle(s);
s = new SpannableString(getString(R.string.uninstall));
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s);
s = new SpannableString(getString(R.string.reset_to_default));
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
popupMenu.getMenu().findItem(R.id.menu_reset_to_default).setTitle(s);
// set proper item based on Db value
if (DbUtils.isAppFrozen(activityName)) {
popupMenu.getMenu().findItem(R.id.menu_freeze_size).setTitle(R.string.unfreeze_size);
}
//disable some item for shortcut
// and change the uninstall to remove
if (view.isShortcut()) {
SpannableString s1 = new SpannableString(getString(R.string.remove));
s1.setSpan(new ForegroundColorSpan(Color.parseColor("#E53935")), 0, s1.length(), 0);
popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s1);
popupMenu.getMenu().findItem(R.id.menu_hide).setVisible(false);
//renaming is also disabled;
// consider it later
popupMenu.getMenu().findItem(R.id.menu_rename).setVisible(false);
popupMenu.getMenu().findItem(R.id.menu_app_info).setVisible(false);
}
popupMenu.setOnMenuItemClickListener(menuItem -> {
int id = menuItem.getItemId();
if (id == R.id.menu_color) {
changeColorSize(activityName, view);
} else if (id == R.id.menu_rename) {
renameApp(activityName, view.getText().toString());
} else if (id == R.id.menu_freeze_size) {
freezeAppSize(activityName);
} else if (id == R.id.menu_hide) {
hideApp(activityName);
} else if (id == R.id.menu_uninstall) {
if (view.isShortcut()) {
removeShortcut(view);
} else {
uninstallApp(activityName);
}
} else if (id == R.id.menu_app_info) {
showAppInfo(activityName);
} else if (id == R.id.menu_reset_to_default) {
resetApp(activityName);
} else if (id == R.id.menu_reset_color) {
resetAppColor(activityName);
} else {
return true;
}
return true;
});
// not forget to show popup
popupMenu.show();
// show app settings popup instead of popup menu
AppSettingsPopup popup = new AppSettingsPopup(this, activityName, view, this);
popup.showAsDropDown(view);
}
//reset the app color to default color;
private void resetAppColor(String activityName) {
public void resetAppColor(String activityName) {
DbUtils.removeColor(activityName);
boolean sortNeeded = (DbUtils.getSortsTypes() == SORT_BY_COLOR);
addAppAfterReset(activityName, sortNeeded);
@@ -723,7 +650,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
// as method name suggest
private void freezeAppSize(String activityName) {
public void freezeAppSize(String activityName) {
boolean b = DbUtils.isAppFrozen(activityName);
for (Apps apps : mAppsList) {
if (activityName.equalsIgnoreCase(apps.getActivityName())) {
@@ -734,7 +661,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
// as method name suggest
private void hideApp(String activityName) {
public void hideApp(String activityName) {
for (Apps apps : mAppsList) {
if (activityName.equalsIgnoreCase(apps.getActivityName())) {
apps.setAppHidden(true);
@@ -744,7 +671,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
// show the app rename Dialog
private void renameApp(String activityName, String appName) {
public void renameApp(String activityName, String appName) {
dialogs = new RenameInputDialogs(this, activityName, appName, this);
Window window = dialogs.getWindow();
if (window != null) {
@@ -771,20 +698,20 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
// reset the app
private void resetApp(String activityName) {
public void resetApp(String activityName) {
DbUtils.removeAppName(activityName);
DbUtils.removeColor(activityName);
DbUtils.removeSize(activityName);
addAppAfterReset(activityName, true);
}
private void showAppInfo(String activityName) {
public void showAppInfo(String activityName) {
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + activityName.split("/")[0]));
startActivity(intent);
}
private void uninstallApp(String activityName) {
public void uninstallApp(String activityName) {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:" + activityName.split("/")[0]));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
@@ -792,7 +719,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
}
//show dialog(i.e a color seek bar) for change color
private void changeColorSize(String activityName, TextView view) {
public void changeColorSize(String activityName, TextView view) {
int color = DbUtils.getAppColor(activityName);
if (color == DbUtils.NULL_TEXT_COLOR) {
color = view.getCurrentTextColor();
@@ -1214,7 +1141,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
*
* @param view shortcut view to be removed...
*/
private void removeShortcut(AppTextView view) {
public void removeShortcut(AppTextView view) {
// view.setVisibility(View.GONE);
shortcutUtils.removeShortcut(new Shortcut(view.getText().toString(), view.getUri()));
@@ -1224,13 +1151,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
@Override
public void onSwipe(Gestures.Direction direction) {
if (direction == Gestures.Direction.SWIPE_RIGHT) {
if (direction == Gestures.Direction.SWIPE_UP) {
searching = true;
mSearchBox.setText("");
mSearchBox.setVisibility(View.VISIBLE);
mSearchBox.requestFocus();
imm.showSoftInput(mSearchBox, InputMethodManager.SHOW_IMPLICIT);
} else if (direction == Gestures.Direction.SWIPE_LEFT) {
} else if (direction == Gestures.Direction.SWIPE_DOWN) {
if (searching) {
mSearchBox.setVisibility(View.GONE);
imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
@@ -1245,6 +1172,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
DeviceAdminManager.lockDevice(this);
}
@Override
public void onLongPress() {
// Show launcher settings on long press in free space
dialogs = new GlobalSettingsDialog(this, this);
dialogs.show();
}
static class SearchTask extends AsyncTask<CharSequence, Void, ArrayList<Apps>> {
@Override
protected void onPostExecute(ArrayList<Apps> filteredApps) {
@@ -1341,100 +1275,16 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
return;
}
// Create a comprehensive permission request dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Welcome to Lunox! 🚀");
builder.setMessage("To provide the best experience, Lunox needs a few permissions:\n\n" +
"📱 **Usage Access**: To show all your installed apps\n" +
"🔒 **Device Admin**: To manage app freezing and advanced features\n\n" +
"These permissions help Lunox work properly and show all your apps.");
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setCancelable(false);
builder.setPositiveButton("Grant Permissions", (dialog, which) -> {
requestPermissions();
});
builder.setNegativeButton("Skip for Now", (dialog, which) -> {
DbUtils.setPermissionDialogShown(true);
});
AlertDialog dialog = builder.create();
dialog.show();
// Create the new permission dialog with proper theming
Context ctx;
if (DbUtils.getTheme() == R.style.Wallpaper)
ctx = new ContextThemeWrapper(this, R.style.AppTheme);
else
ctx = new ContextThemeWrapper(this, DbUtils.getTheme());
PermissionDialog permissionDialog = new PermissionDialog(ctx, this);
permissionDialog.show();
}
/**
* Request all necessary permissions
*/
private void requestPermissions() {
// Check and request Usage Access permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
if (mode != AppOpsManager.MODE_ALLOWED) {
showUsageAccessDialog();
}
}
// Check and request Device Admin permission
if (!DeviceAdminManager.isDeviceAdminActive(this)) {
showDeviceAdminDialog();
}
DbUtils.setPermissionDialogShown(true);
}
/**
* Show dialog to guide user to enable usage access
*/
private void showUsageAccessDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("📱 Usage Access Required");
builder.setMessage("To show all your installed apps, please enable 'Usage Access' for Lunox:\n\n" +
"1. Tap 'Open Settings'\n" +
"2. Find 'Lunox Dev' in the list\n" +
"3. Toggle 'Allow usage access' ON\n" +
"4. Return to Lunox\n\n" +
"This helps Lunox detect all your apps properly.");
builder.setIcon(android.R.drawable.ic_menu_manage);
builder.setCancelable(false);
builder.setPositiveButton("Open Settings", (dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
});
builder.setNegativeButton("Later", null);
AlertDialog dialog = builder.create();
dialog.show();
}
/**
* Show dialog to guide user to enable device admin
*/
private void showDeviceAdminDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("🔒 Device Admin Required");
builder.setMessage("Device Admin permission enables advanced features like:\n\n" +
"• App freezing functionality\n" +
"• Enhanced app management\n" +
"• Better system integration\n\n" +
"This permission is safe and only used for launcher features.");
builder.setIcon(android.R.drawable.ic_lock_lock);
builder.setCancelable(false);
builder.setPositiveButton("Enable Device Admin", (dialog, which) -> {
DeviceAdminManager.requestDeviceAdminPermission(this);
});
builder.setNegativeButton("Skip", null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
@@ -0,0 +1,152 @@
/*
* Last Launcher
* Copyright (C) 2019 Shubham Tyagi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.sankalp.lunox.dialogs;
import android.content.Context;
import android.graphics.Color;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.PopupWindow;
import android.widget.TextView;
import io.github.sankalp.lunox.LauncherActivity;
import io.github.sankalp.lunox.R;
import io.github.sankalp.lunox.utils.DbUtils;
import io.github.sankalp.lunox.views.textview.AppTextView;
/**
* App settings popup that shows options for individual apps
*/
public class AppSettingsPopup extends PopupWindow implements View.OnClickListener {
private final LauncherActivity launcherActivity;
private final Context context;
private final String activityName;
private final AppTextView appTextView;
private TextView freezeSize;
private TextView hideApp;
private TextView resetToDefault;
private TextView uninstallApp;
public AppSettingsPopup(Context context, String activityName, AppTextView appTextView, LauncherActivity launcherActivity) {
super(context);
this.context = context;
this.activityName = activityName;
this.appTextView = appTextView;
this.launcherActivity = launcherActivity;
initPopup();
}
private void initPopup() {
LayoutInflater inflater = LayoutInflater.from(context);
View contentView = inflater.inflate(R.layout.dialog_app_settings, null);
setContentView(contentView);
// Set popup properties
setWidth(android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
setHeight(android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
setFocusable(true);
setOutsideTouchable(true);
// Set background to match the dialog style with border
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
setBackgroundDrawable(context.getResources().getDrawable(R.drawable.popup_background, null));
} else {
setBackgroundDrawable(context.getResources().getDrawable(R.drawable.popup_background));
}
// Set up click listeners
contentView.findViewById(R.id.app_settings_color).setOnClickListener(this);
contentView.findViewById(R.id.app_settings_rename).setOnClickListener(this);
freezeSize = contentView.findViewById(R.id.app_settings_freeze_size);
freezeSize.setOnClickListener(this);
contentView.findViewById(R.id.app_settings_app_info).setOnClickListener(this);
contentView.findViewById(R.id.app_settings_reset_color).setOnClickListener(this);
hideApp = contentView.findViewById(R.id.app_settings_hide);
hideApp.setOnClickListener(this);
resetToDefault = contentView.findViewById(R.id.app_settings_reset_to_default);
resetToDefault.setOnClickListener(this);
resetToDefault.setTextColor(Color.parseColor("#E53935"));
uninstallApp = contentView.findViewById(R.id.app_settings_uninstall);
uninstallApp.setOnClickListener(this);
uninstallApp.setTextColor(Color.parseColor("#E53935"));
// Set proper text based on DB value
if (DbUtils.isAppFrozen(activityName)) {
freezeSize.setText(R.string.unfreeze_size);
} else {
freezeSize.setText(R.string.freeze_size);
}
// Handle shortcut-specific settings
if (appTextView.isShortcut()) {
uninstallApp.setText(R.string.remove);
hideApp.setVisibility(View.GONE);
contentView.findViewById(R.id.app_settings_rename).setVisibility(View.GONE);
contentView.findViewById(R.id.app_settings_app_info).setVisibility(View.GONE);
} else {
hideApp.setTextColor(Color.parseColor("#E53935"));
}
}
public void showAsDropDown(View anchor) {
showAsDropDown(anchor, 0, 0, Gravity.START);
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.app_settings_color) {
launcherActivity.changeColorSize(activityName, appTextView);
dismiss();
} else if (id == R.id.app_settings_rename) {
launcherActivity.renameApp(activityName, appTextView.getText().toString());
dismiss();
} else if (id == R.id.app_settings_freeze_size) {
launcherActivity.freezeAppSize(activityName);
dismiss();
} else if (id == R.id.app_settings_app_info) {
launcherActivity.showAppInfo(activityName);
dismiss();
} else if (id == R.id.app_settings_reset_color) {
launcherActivity.resetAppColor(activityName);
dismiss();
} else if (id == R.id.app_settings_hide) {
launcherActivity.hideApp(activityName);
dismiss();
} else if (id == R.id.app_settings_reset_to_default) {
launcherActivity.resetApp(activityName);
dismiss();
} else if (id == R.id.app_settings_uninstall) {
if (appTextView.isShortcut()) {
launcherActivity.removeShortcut(appTextView);
} else {
launcherActivity.uninstallApp(activityName);
}
dismiss();
}
}
}
@@ -0,0 +1,169 @@
/*
* Last Launcher
* Copyright (C) 2019 Shubham Tyagi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.sankalp.lunox.dialogs;
import android.app.AppOpsManager;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.view.Window;
import android.widget.TextView;
import android.widget.Toast;
import io.github.sankalp.lunox.LauncherActivity;
import io.github.sankalp.lunox.R;
import io.github.sankalp.lunox.utils.DbUtils;
import io.github.sankalp.lunox.utils.DeviceAdminManager;
public class PermissionDialog extends Dialog implements View.OnClickListener {
private final LauncherActivity context;
private TextView usageAccessButton;
private TextView deviceAdminButton;
private TextView continueButton;
public PermissionDialog(Context context, LauncherActivity launcherActivity) {
super(context);
this.context = launcherActivity;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialog_permission_setup);
setCancelable(false);
// Initialize views
usageAccessButton = findViewById(R.id.permission_usage_access);
deviceAdminButton = findViewById(R.id.permission_device_admin);
continueButton = findViewById(R.id.permission_continue);
// Set click listeners
usageAccessButton.setOnClickListener(this);
deviceAdminButton.setOnClickListener(this);
continueButton.setOnClickListener(this);
// Update button states
updatePermissionStates();
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.permission_usage_access) {
openUsageAccessSettings();
} else if (id == R.id.permission_device_admin) {
enableDeviceAdmin();
} else if (id == R.id.permission_continue) {
continueToLauncher();
}
}
private void openUsageAccessSettings() {
try {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
Toast.makeText(context, "Please enable Usage Access for Lunox", Toast.LENGTH_LONG).show();
} catch (Exception e) {
// Fallback to general settings if specific intent fails
Intent intent = new Intent(Settings.ACTION_SETTINGS);
context.startActivity(intent);
Toast.makeText(context, "Please find and enable Usage Access for Lunox in Settings", Toast.LENGTH_LONG).show();
}
}
private void enableDeviceAdmin() {
try {
DeviceAdminManager.requestDeviceAdminPermission(context);
Toast.makeText(context, "Please enable Device Admin for Lunox", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(context, "Unable to open Device Admin settings", Toast.LENGTH_SHORT).show();
}
}
private void continueToLauncher() {
// Mark permission dialog as shown
DbUtils.setPermissionDialogShown(true);
// Check if at least one permission is granted
boolean hasUsageAccess = checkUsageAccessPermission();
boolean hasDeviceAdmin = DeviceAdminManager.isDeviceAdminActive(context);
if (hasUsageAccess || hasDeviceAdmin) {
dismiss();
context.loadApps(); // Reload apps after permissions are granted
} else {
Toast.makeText(context, "Please grant at least one permission to continue", Toast.LENGTH_LONG).show();
}
}
private boolean checkUsageAccessPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
return mode == AppOpsManager.MODE_ALLOWED;
}
return true; // For older versions, assume permission is granted
}
private void updatePermissionStates() {
// Update Usage Access button
boolean hasUsageAccess = checkUsageAccessPermission();
if (hasUsageAccess) {
usageAccessButton.setText("Usage Access");
usageAccessButton.setAlpha(0.7f);
} else {
usageAccessButton.setText("Enable Usage Access");
usageAccessButton.setAlpha(1.0f);
}
// Update Device Admin button
boolean hasDeviceAdmin = DeviceAdminManager.isDeviceAdminActive(context);
if (hasDeviceAdmin) {
deviceAdminButton.setText("Device Admin");
deviceAdminButton.setAlpha(0.7f);
} else {
deviceAdminButton.setText("Enable Device Admin");
deviceAdminButton.setAlpha(1.0f);
}
}
@Override
protected void onStart() {
super.onStart();
// Update permission states when dialog becomes visible
updatePermissionStates();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Update permission states when user returns to the dialog
updatePermissionStates();
}
}
}
@@ -79,6 +79,11 @@ public class Gestures extends GestureDetector.SimpleOnGestureListener {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
this.listener.onLongPress();
}
public enum Direction {
SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT
@@ -88,6 +93,8 @@ public class Gestures extends GestureDetector.SimpleOnGestureListener {
void onSwipe(Direction direction);
void onDoubleTap();
void onLongPress();
}
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- Black background like the dialog -->
<solid android:color="@android:color/black" />
<!-- Border/stroke around the popup -->
<stroke
android:width="2dp"
android:color="#DEDEDE" />
<!-- Rounded corners for better appearance -->
<corners android:radius="4dp" />
</shape>
@@ -1,10 +1,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Last Launcher
~ Copyright (C) 2019 Shubham Tyagi
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/app_settings_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/color_for_this_entry"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_rename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/rename"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_freeze_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/freeze_size"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_app_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/app_info"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_reset_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/reset_color"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_hide"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/hide"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_reset_to_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/reset_to_default"
android:textSize="20sp" />
<View
android:layout_width="170dp"
android:layout_height="1dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:background="#DEDEDE"
android:foregroundGravity="center_vertical|center_horizontal" />
<TextView
android:id="@+id/app_settings_uninstall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/uninstall"
android:textSize="20sp" />
</LinearLayout>
</ScrollView>
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Last Launcher
~ Copyright (C) 2019 Shubham Tyagi
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout android:id="@+id/permission_linear_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Title -->
<TextView
android:id="@+id/permission_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="@string/permission_dialog_title"
android:textSize="24sp"
android:textStyle="bold" />
<!-- Description -->
<TextView
android:id="@+id/permission_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="@string/permission_dialog_message"
android:textSize="16sp"
android:lineSpacingMultiplier="1.2" />
<!-- Usage Access Permission -->
<TextView
android:id="@+id/permission_usage_access"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"
android:layout_margin="5dp"
android:text="Enable Usage Access"
android:textSize="20sp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true" />
<!-- Device Admin Permission -->
<TextView
android:id="@+id/permission_device_admin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"
android:layout_margin="5dp"
android:text="Enable Device Admin"
android:textSize="20sp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true" />
<!-- Continue Button -->
<TextView
android:id="@+id/permission_continue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="15dp"
android:layout_margin="10dp"
android:layout_marginTop="20dp"
android:text="Continue to Lunox"
android:textSize="18sp"
android:textStyle="bold"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true" />
</LinearLayout>
+6 -1
View File
@@ -90,12 +90,17 @@
<!--Sort Apps IN : RECENTLY USED FIRST ORDER -->
<string name="recently_first">Recently first</string>
<string name="restart_launcher">Restart Launcher</string>
<string name="device_admin_label">Lunox Device Admin</string>
<string name="device_admin_description">Required for double-tap to lock screen functionality</string>
<string name="device_admin_enable">Enable Device Admin</string>
<string name="device_admin_disabled">Device Admin is required for lock screen functionality</string>
<!-- Permission Dialog Strings -->
<string name="permission_dialog_title">Welcome to Lunox! 🚀</string>
<string name="permission_dialog_message">To provide the best launcher experience, Lunox needs these permissions:\n\n<b>Usage Access</b> - Display all your apps\n<b>Device Admin</b> - Enable advanced features\n\nTap each permission below to enable it.</string>
<!-- Frozen apps dialog title -->
<string name="freezed_apps">Freezed Apps</string>
<!-- Color source from ColorSniffer app -->
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 264 KiB