Commit e86e71ec authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Fix folder name not being preserved

parent 85a2743b
package foundation.e.blisslauncher.core.customviews
import android.content.Context
import android.text.TextUtils
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.inputmethod.InputMethodManager
import foundation.e.blisslauncher.features.test.UiThreadHelper
class FolderTitleInput @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : BlissInput(context, attrs) {
private var mShowImeAfterFirstLayout = false
private var mForceDisableSuggestions = false
/**
* Implemented by listeners of the back key.
*/
interface OnBackKeyListener {
fun onBackKey(): Boolean
}
private var mBackKeyListener: OnBackKeyListener? = null
fun setOnBackKeyListener(listener: OnBackKeyListener) {
mBackKeyListener = listener
}
override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
// If this is a back key, propagate the key back to the listener
return if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
mBackKeyListener?.onBackKey() ?: false
} else super.onKeyPreIme(keyCode, event)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (mShowImeAfterFirstLayout) {
// soft input only shows one frame after the layout of the EditText happens,
post {
showSoftInput()
mShowImeAfterFirstLayout = false
}
}
}
fun showKeyboard() {
mShowImeAfterFirstLayout = !showSoftInput()
}
fun hideKeyboard() {
UiThreadHelper.hideKeyboardAsync(context, windowToken)
}
private fun showSoftInput(): Boolean {
return requestFocus() &&
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}
fun dispatchBackKey() {
hideKeyboard()
if (mBackKeyListener != null) {
mBackKeyListener!!.onBackKey()
}
}
/**
* Set to true when you want isSuggestionsEnabled to return false.
* Use this to disable the red underlines that appear under typos when suggestions is enabled.
*/
fun forceDisableSuggestions(forceDisableSuggestions: Boolean) {
mForceDisableSuggestions = forceDisableSuggestions
}
override fun isSuggestionsEnabled(): Boolean {
return !mForceDisableSuggestions && super.isSuggestionsEnabled()
}
fun reset() {
if (!TextUtils.isEmpty(text)) {
setText("")
}
if (isFocused) {
val nextFocus = focusSearch(FOCUS_DOWN)
nextFocus?.requestFocus()
}
hideKeyboard()
}
}
\ No newline at end of file
......@@ -37,6 +37,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator;
import android.widget.GridLayout;
import android.widget.Toast;
import foundation.e.blisslauncher.BuildConfig;
import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.Utilities;
......@@ -60,6 +61,7 @@ import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver;
import foundation.e.blisslauncher.features.shortcuts.ShortcutKey;
import foundation.e.blisslauncher.features.test.Alarm;
import foundation.e.blisslauncher.features.test.CellLayout;
import foundation.e.blisslauncher.features.test.FolderIconTextView;
import foundation.e.blisslauncher.features.test.IconTextView;
import foundation.e.blisslauncher.features.test.LauncherItemMatcher;
import foundation.e.blisslauncher.features.test.LauncherState;
......@@ -79,6 +81,7 @@ import foundation.e.blisslauncher.features.test.dragndrop.DropTarget;
import foundation.e.blisslauncher.features.test.dragndrop.SpringLoadedDragController;
import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider;
import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
......@@ -88,6 +91,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.jetbrains.annotations.NotNull;
public class LauncherPagedView extends PagedView<PageIndicatorDots> implements View.OnTouchListener,
......@@ -288,7 +292,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
disableLayoutTransitions();
// Remove the pages and clear the screen models
//removeFolderListeners();
removeFolderListeners();
removeAllViews();
mScreenOrder.clear();
mWorkspaceScreens.clear();
......@@ -329,9 +333,20 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
int newItemsScreenId = -1;
for (int i = 0; i < launcherItems.size(); i++) {
LauncherItem launcherItem = launcherItems.get(i);
IconTextView appView = (IconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.app_icon, null, false);
appView.applyFromShortcutItem(launcherItem);
View appView;
if (launcherItem.itemType == Constants.ITEM_TYPE_FOLDER) {
FolderIconTextView folderIcon =
(FolderIconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.folder_icon, null, false);
folderIcon.applyFromFolderItem((FolderItem) launcherItem);
((FolderItem) launcherItem).addListener(folderIcon);
appView = folderIcon;
} else {
IconTextView appIcon = (IconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.app_icon, null, false);
appIcon.applyFromShortcutItem(launcherItem);
appView = appIcon;
}
appView.setOnClickListener(ItemClickHandler.INSTANCE);
appView.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
if (launcherItem.container == Constants.CONTAINER_DESKTOP) {
......@@ -346,7 +361,6 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
iconLayoutParams.height = mLauncher.getDeviceProfile().getCellHeightPx();
iconLayoutParams.width = mLauncher.getDeviceProfile().getCellWidthPx();
appView.setLayoutParams(iconLayoutParams);
appView.setTextVisibility(true);
} else if (launcherItem.container == Constants.CONTAINER_HOTSEAT) {
GridLayout.Spec rowSpec = GridLayout.spec(GridLayout.UNDEFINED);
GridLayout.Spec colSpec = GridLayout.spec(GridLayout.UNDEFINED);
......@@ -482,6 +496,10 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
}
}
public void updateDatabase() {
updateDatabase(getWorkspaceAndHotseatCellLayouts());
}
private int[] findSpaceForItem(IntegerArray addedWorkspaceScreensFinal) {
// Find appropriate space for the item.
int screenId = 0;
......@@ -511,6 +529,18 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
return new int[]{screenId, cell};
}
/**
* Removes all folder listeners
*/
public void removeFolderListeners() {
mapOverItems(false, (info, view, index) -> {
if (view instanceof FolderIconTextView) {
((FolderIconTextView) view).removeListeners();
}
return false;
});
}
/**
* Returns true if the shortcuts already exists on the workspace. This must be called after
* the workspace has been loaded. We identify a shortcut by its intent.
......@@ -1863,11 +1893,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
fi.screenId = screenId;
fi.cell = targetCell[1] * mLauncher.getDeviceProfile().getInv()
.getNumColumns() + targetCell[0];
IconTextView folderView = (IconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.app_icon, null, false);
FolderIconTextView folderView = (FolderIconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.folder_icon, null, false);
folderView.applyFromShortcutItem(fi);
folderView.setOnClickListener(ItemClickHandler.INSTANCE);
folderView.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
fi.addListener(folderView);
addInScreen(folderView, fi);
// if the drag started here, we need to remove it from the workspace
if (!external) {
......@@ -2627,12 +2658,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
// Update folder icons
mapOverItems(MAP_NO_RECURSE, (info, v, itemIdx) -> {
if (info instanceof FolderItem && folderIds.contains(info.id)
&& v instanceof IconTextView) {
&& v instanceof FolderIconTextView) {
FolderDotInfo folderDotInfo = new FolderDotInfo();
for (LauncherItem si : ((FolderItem) info).items) {
folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
}
((IconTextView) v).setDotInfo((FolderItem) info, folderDotInfo);
((FolderIconTextView) v).setDotInfo(folderDotInfo);
}
// process all the shortcuts
return false;
......
......@@ -2,6 +2,8 @@ package foundation.e.blisslauncher.core.database.model;
import foundation.e.blisslauncher.core.utils.Constants;
import java.util.ArrayList;
import java.util.List;
public class FolderItem extends LauncherItem {
......@@ -15,4 +17,24 @@ public class FolderItem extends LauncherItem {
itemType = Constants.ITEM_TYPE_FOLDER;
}
ArrayList<FolderListener> listeners = new ArrayList<>();
public void setTitle(CharSequence title) {
this.title = title;
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onTitleChanged(title);
}
}
public void addListener(FolderListener listener) {
listeners.add(listener);
}
public void removeListener(FolderListener listener) {
listeners.remove(listener);
}
public interface FolderListener {
void onTitleChanged(CharSequence title);
}
}
package foundation.e.blisslauncher.features.test
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import foundation.e.blisslauncher.core.database.model.FolderItem
import foundation.e.blisslauncher.features.notification.FolderDotInfo
/**
* A text view which displays an icon on top side of it.
*/
@SuppressLint("AppCompatCustomView")
class FolderIconTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : IconTextView(context, attrs, defStyle), FolderItem.FolderListener {
private var folderItem: FolderItem? = null
override fun onTitleChanged(title: CharSequence?) {
text = title
}
fun applyFromFolderItem(item: FolderItem) {
applyFromShortcutItem(item)
folderItem = item
}
fun setDotInfo(dotInfo: FolderDotInfo) {
val wasDotted = mDotInfo is FolderDotInfo && (mDotInfo as FolderDotInfo).hasDot()
updateDotScale(wasDotted, dotInfo.hasDot(), true)
mDotInfo = dotInfo
}
override fun hasDot(): Boolean {
return mDotInfo != null && (mDotInfo as FolderDotInfo).hasDot()
}
fun removeListeners() {
folderItem?.removeListener(this)
}
}
......@@ -27,7 +27,6 @@ import foundation.e.blisslauncher.core.database.model.ShortcutItem
import foundation.e.blisslauncher.core.utils.Constants
import foundation.e.blisslauncher.features.notification.DotInfo
import foundation.e.blisslauncher.features.notification.DotRenderer
import foundation.e.blisslauncher.features.notification.FolderDotInfo
import foundation.e.blisslauncher.features.test.uninstall.UninstallButtonRenderer
import kotlin.math.roundToInt
......@@ -35,7 +34,7 @@ import kotlin.math.roundToInt
* A text view which displays an icon on top side of it.
*/
@SuppressLint("AppCompatCustomView")
class IconTextView @JvmOverloads constructor(
open class IconTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet?,
defStyle: Int
......@@ -43,7 +42,6 @@ class IconTextView @JvmOverloads constructor(
companion object {
private const val DISPLAY_WORKSPACE = 1
private const val DISPLAY_FOLDER = 2
private val STATE_PRESSED = intArrayOf(android.R.attr.state_pressed)
private const val TAG = "IconTextView"
......@@ -115,7 +113,7 @@ class IconTextView @JvmOverloads constructor(
private var longPressHelper: CheckLongPressHelper
private var mDotInfo: DotInfo? = null
protected var mDotInfo: DotInfo? = null
private var mDotScaleAnim: Animator? = null
private var mForceHideDot = false
......@@ -154,7 +152,7 @@ class IconTextView @JvmOverloads constructor(
override fun setTextColor(colors: ColorStateList) {
mTextColor = colors.defaultColor
if (java.lang.Float.compare(mTextAlpha, 1f) == 0) {
if (mTextAlpha.compareTo(1f) == 0) {
super.setTextColor(colors)
} else {
super.setTextColor(getModifiedColor())
......@@ -199,13 +197,7 @@ class IconTextView @JvmOverloads constructor(
}
}
fun setDotInfo(item: FolderItem, dotInfo: FolderDotInfo) {
val wasDotted = mDotInfo is FolderDotInfo && (mDotInfo as FolderDotInfo).hasDot()
updateDotScale(wasDotted, dotInfo.hasDot(), true)
mDotInfo = dotInfo
}
private fun updateDotScale(wasDotted: Boolean, isDotted: Boolean, animate: Boolean) {
protected fun updateDotScale(wasDotted: Boolean, isDotted: Boolean, animate: Boolean) {
val newDotScale: Float = if (isDotted) 1f else 0f
mDotRenderer = mActivity.deviceProfile.mDotRenderer
if (wasDotted || isDotted) {
......@@ -355,10 +347,7 @@ class IconTextView @JvmOverloads constructor(
}
}
private fun hasDot(): Boolean {
if (mDotInfo != null && mDotInfo is FolderDotInfo) {
return (mDotInfo as FolderDotInfo).hasDot()
}
open fun hasDot(): Boolean {
return mDotInfo != null
}
......
......@@ -34,6 +34,8 @@ import android.os.StrictMode
import android.os.StrictMode.VmPolicy
import android.provider.Settings
import android.text.Editable
import android.text.InputType
import android.text.Selection
import android.text.TextWatcher
import android.util.Log
import android.view.ContextThemeWrapper
......@@ -41,6 +43,7 @@ import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnFocusChangeListener
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.LinearInterpolator
......@@ -52,6 +55,7 @@ import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.SeekBar
import android.widget.TextView
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.localbroadcastmanager.content.LocalBroadcastManager
......@@ -67,6 +71,7 @@ import foundation.e.blisslauncher.core.Utilities
import foundation.e.blisslauncher.core.customviews.AbstractFloatingView
import foundation.e.blisslauncher.core.customviews.BlissFrameLayout
import foundation.e.blisslauncher.core.customviews.BlissInput
import foundation.e.blisslauncher.core.customviews.FolderTitleInput
import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout
import foundation.e.blisslauncher.core.customviews.LauncherPagedView
import foundation.e.blisslauncher.core.customviews.RoundedWidgetView
......@@ -119,7 +124,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.observers.DisposableObserver
import io.reactivex.schedulers.Schedulers
import java.lang.Exception
import me.relex.circleindicator.CircleIndicator
import java.net.URISyntaxException
import java.util.ArrayList
import java.util.Arrays
......@@ -127,11 +132,12 @@ import java.util.Comparator
import java.util.Locale
import java.util.concurrent.TimeUnit
import java.util.function.Predicate
import me.relex.circleindicator.CircleIndicator
class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionClickListener,
LauncherModel.Callbacks {
LauncherModel.Callbacks, OnFocusChangeListener, FolderTitleInput.OnBackKeyListener,
OnEditorActionListener {
private var mIsEditingName: Boolean = false
private var mModel: LauncherModel? = null
private lateinit var widgetRootView: WidgetsRootView
private lateinit var overlayCallbackImpl: OverlayCallbackImpl
......@@ -202,7 +208,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
private var activeFolderStartBounds = Rect()
private var mFolderAppsViewPager: ViewPager? = null
private var mFolderTitleInput: BlissInput? = null
private lateinit var mFolderTitleInput: FolderTitleInput
private val mainHandler = Handler(Looper.getMainLooper())
......@@ -419,6 +425,16 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
folderContainer = findViewById(R.id.folder_window_container)
mFolderAppsViewPager = findViewById(R.id.folder_apps)
mFolderTitleInput = findViewById(R.id.folder_title)
mFolderTitleInput.setOnBackKeyListener(this)
mFolderTitleInput.setOnFocusChangeListener(this)
mFolderTitleInput.setOnEditorActionListener(this)
mFolderTitleInput.setSelectAllOnFocus(true)
mFolderTitleInput.inputType = mFolderTitleInput.inputType and
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT.inv() and
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS.inv() or
InputType.TYPE_TEXT_FLAG_CAP_WORDS
mFolderTitleInput.forceDisableSuggestions(true)
launcherView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
......@@ -1021,6 +1037,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
override fun onDestroy() {
super.onDestroy()
workspace.removeFolderListeners()
if (mCancelTouchController != null) {
mCancelTouchController!!.run()
mCancelTouchController = null
......@@ -1104,6 +1121,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
val populatedItems = populateItemPositions(launcherItems)
val orderedScreenIds = IntegerArray()
orderedScreenIds.addAll(collectWorkspaceScreens(populatedItems))
workspace.removeAllWorkspaceScreens()
workspace.bindScreens(orderedScreenIds)
workspace.bindItems(populatedItems, false)
}
......@@ -1701,7 +1719,10 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
fun closeFolder() {
mFolderTitleInput?.clearFocus()
if (isEditingName()) {
mFolderTitleInput.dispatchBackKey()
}
currentAnimator?.cancel()
// Animate the four positioning/sizing properties in parallel,
......@@ -1791,4 +1812,51 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
workspace.removeItemsByMatcher(matcher)
dragController.onAppsRemoved(matcher)
}
override fun onFocusChange(v: View?, hasFocus: Boolean) {
if (v === mFolderTitleInput) {
if (hasFocus) {
startEditingFolderName()
} else {
mFolderTitleInput.dispatchBackKey()
}
}
}
override fun onBackKey(): Boolean {
// Convert to a string here to ensure that no other state associated with the text field
// gets saved.
val newTitle: String = mFolderTitleInput.text.toString()
activeFolder?.setTitle(newTitle)
// Update database
workspace.updateDatabase()
// This ensures that focus is gained every time the field is clicked, which selects all
// the text and brings up the soft keyboard if necessary.
mFolderTitleInput.clearFocus()
Selection.setSelection(mFolderTitleInput.getText(), 0, 0)
mIsEditingName = false
return true
}
fun isEditingName(): Boolean {
return mIsEditingName
}
private fun startEditingFolderName() {
folderContainer.post(Runnable {
mFolderTitleInput.hint = ""
mIsEditingName = true
})
}
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_DONE) {
mFolderTitleInput.dispatchBackKey()
return true
}
return false
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<foundation.e.blisslauncher.features.test.FolderIconTextView style="@style/BaseIcon" />
......@@ -7,19 +7,20 @@
android:focusable="true"
android:visibility="gone">
<foundation.e.blisslauncher.core.customviews.BlissInput
<foundation.e.blisslauncher.core.customviews.FolderTitleInput
android:id="@+id/folder_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/folder_apps_background"
android:layout_centerHorizontal="true"
android:background="@null"
android:imeOptions="actionDone"
android:background="@android:color/transparent"
android:imeOptions="flagNoExtractUi"
android:inputType="textNoSuggestions|textCapSentences"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/untitled"
android:textAlignment="center"
android:textColorHighlight="?android:attr/colorControlHighlight"
android:textColor="@android:color/white"
android:textSize="18sp" />
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment