mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: implement edge-to-edge layout for editor activity
This commit is contained in:
Generated
+8
@@ -4,6 +4,14 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2024-05-12T19:07:48.842669075Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=fd22c9e0" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.itsaky.androidide.BuildConfig
|
||||
import com.itsaky.androidide.R
|
||||
import com.itsaky.androidide.adapters.SimpleIconTitleDescriptionAdapter
|
||||
import com.itsaky.androidide.app.BaseApplication
|
||||
import com.itsaky.androidide.app.LimitlessIDEActivity
|
||||
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
|
||||
import com.itsaky.androidide.app.configuration.IDEBuildConfigProvider
|
||||
import com.itsaky.androidide.buildinfo.BuildInfo
|
||||
import com.itsaky.androidide.databinding.ActivityAboutBinding
|
||||
@@ -44,7 +44,7 @@ import com.itsaky.androidide.utils.BuildInfoUtils
|
||||
import com.itsaky.androidide.utils.flashSuccess
|
||||
import com.itsaky.androidide.utils.resolveAttr
|
||||
|
||||
class AboutActivity : LimitlessIDEActivity() {
|
||||
class AboutActivity : EdgeToEdgeIDEActivity() {
|
||||
|
||||
private var _binding: ActivityAboutBinding? = null
|
||||
private val binding: ActivityAboutBinding
|
||||
@@ -76,7 +76,7 @@ class AboutActivity : LimitlessIDEActivity() {
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar!!.setTitle(R.string.about)
|
||||
toolbar.setNavigationOnClickListener { finish() }
|
||||
toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
aboutHeader.apply {
|
||||
ideVersion.text = createVersionText()
|
||||
|
||||
@@ -24,7 +24,7 @@ import androidx.activity.viewModels
|
||||
import androidx.core.view.isVisible
|
||||
import com.itsaky.androidide.R
|
||||
import com.itsaky.androidide.adapters.ContributorsGridAdapter
|
||||
import com.itsaky.androidide.app.LimitlessIDEActivity
|
||||
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
|
||||
import com.itsaky.androidide.databinding.ActivityContributorsBinding
|
||||
import com.itsaky.androidide.utils.getConnectionInfo
|
||||
import com.itsaky.androidide.viewmodel.ContributorsViewModel
|
||||
@@ -32,7 +32,7 @@ import com.itsaky.androidide.viewmodel.ContributorsViewModel
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ContributorsActivity : LimitlessIDEActivity() {
|
||||
class ContributorsActivity : EdgeToEdgeIDEActivity() {
|
||||
|
||||
private var _binding: ActivityContributorsBinding? = null
|
||||
private val binding: ActivityContributorsBinding
|
||||
@@ -54,7 +54,7 @@ class ContributorsActivity : LimitlessIDEActivity() {
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar!!.setTitle(R.string.title_contributors)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
toolbar.setNavigationOnClickListener { finish() }
|
||||
toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
githubContributors.apply {
|
||||
sectionTitle.setText(R.string.title_github_contributors)
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.itsaky.androidide.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.itsaky.androidide.app.IDEActivity;
|
||||
import com.itsaky.androidide.databinding.ActivityCrashHandlerBinding;
|
||||
import com.itsaky.androidide.fragments.CrashReportFragment;
|
||||
@@ -50,16 +51,12 @@ public class CrashHandlerActivity extends IDEActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected View bindLayout() {
|
||||
binding = ActivityCrashHandlerBinding.inflate(getLayoutInflater());
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
finishAffinity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -29,7 +29,7 @@ import androidx.transition.TransitionManager
|
||||
import androidx.transition.doOnEnd
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.itsaky.androidide.activities.editor.EditorActivityKt
|
||||
import com.itsaky.androidide.app.LimitlessIDEActivity
|
||||
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
|
||||
import com.itsaky.androidide.databinding.ActivityMainBinding
|
||||
import com.itsaky.androidide.preferences.internal.GeneralPreferences
|
||||
import com.itsaky.androidide.projects.ProjectManagerImpl
|
||||
@@ -43,7 +43,7 @@ import com.itsaky.androidide.viewmodel.MainViewModel.Companion.SCREEN_TEMPLATE_D
|
||||
import com.itsaky.androidide.viewmodel.MainViewModel.Companion.SCREEN_TEMPLATE_LIST
|
||||
import java.io.File
|
||||
|
||||
class MainActivity : LimitlessIDEActivity() {
|
||||
class MainActivity : EdgeToEdgeIDEActivity() {
|
||||
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
private var _binding: ActivityMainBinding? = null
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE 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.
|
||||
*
|
||||
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.activities;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.app.LimitlessIDEActivity;
|
||||
import com.itsaky.androidide.databinding.ActivityPreferencesBinding;
|
||||
import com.itsaky.androidide.fragments.IDEPreferencesFragment;
|
||||
import com.itsaky.androidide.preferences.IDEPreferences;
|
||||
import com.itsaky.androidide.preferences.RootPrefExtsKt;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PreferencesActivity extends LimitlessIDEActivity {
|
||||
|
||||
private ActivityPreferencesBinding binding;
|
||||
private IDEPreferencesFragment rootFragment;
|
||||
|
||||
public PreferencesActivity() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setSupportActionBar(binding.toolbar);
|
||||
getSupportActionBar().setTitle(R.string.ide_preferences);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener(v -> onBackPressed());
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var prefs = IDEPreferences.INSTANCE;
|
||||
prefs.getChildren().clear();
|
||||
|
||||
RootPrefExtsKt.addRootPreferences(prefs);
|
||||
|
||||
final var args = new Bundle();
|
||||
args.putParcelableArrayList(
|
||||
IDEPreferencesFragment.EXTRA_CHILDREN,
|
||||
new ArrayList<>(prefs.getChildren())
|
||||
);
|
||||
|
||||
final var root = getRootFragment();
|
||||
root.setArguments(args);
|
||||
loadFragment(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInsetsUpdated(@NonNull Rect insets) {
|
||||
super.onInsetsUpdated(insets);
|
||||
|
||||
View toolbar = binding.toolbar;
|
||||
toolbar.setPadding(
|
||||
toolbar.getPaddingLeft() + insets.left,
|
||||
toolbar.getPaddingTop(),
|
||||
toolbar.getPaddingRight() + insets.right,
|
||||
toolbar.getPaddingBottom()
|
||||
);
|
||||
|
||||
View fragmentContainer = binding.fragmentContainerParent;
|
||||
fragmentContainer.setPadding(
|
||||
fragmentContainer.getPaddingLeft() + insets.left,
|
||||
fragmentContainer.getPaddingTop(),
|
||||
fragmentContainer.getPaddingRight() + insets.right,
|
||||
fragmentContainer.getPaddingBottom()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected View bindLayout() {
|
||||
binding = ActivityPreferencesBinding.inflate(getLayoutInflater());
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private IDEPreferencesFragment getRootFragment() {
|
||||
return rootFragment == null ? rootFragment = new IDEPreferencesFragment() : rootFragment;
|
||||
}
|
||||
|
||||
private void loadFragment(Fragment fragment) {
|
||||
super.loadFragment(fragment, binding.fragmentContainer.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE 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.
|
||||
*
|
||||
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.itsaky.androidide.activities
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.itsaky.androidide.R
|
||||
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
|
||||
import com.itsaky.androidide.databinding.ActivityPreferencesBinding
|
||||
import com.itsaky.androidide.fragments.IDEPreferencesFragment
|
||||
import com.itsaky.androidide.preferences.addRootPreferences
|
||||
import com.itsaky.androidide.preferences.IDEPreferences as prefs
|
||||
|
||||
class PreferencesActivity : EdgeToEdgeIDEActivity() {
|
||||
|
||||
private var _binding: ActivityPreferencesBinding? = null
|
||||
private val binding: ActivityPreferencesBinding
|
||||
get() = checkNotNull(_binding) { "Activity has been destroyed" }
|
||||
|
||||
private val rootFragment by lazy {
|
||||
IDEPreferencesFragment()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar!!.setTitle(R.string.ide_preferences)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
return
|
||||
}
|
||||
|
||||
(prefs.children as MutableList?)?.clear()
|
||||
|
||||
prefs.addRootPreferences()
|
||||
|
||||
val args = Bundle()
|
||||
args.putParcelableArrayList(
|
||||
IDEPreferencesFragment.EXTRA_CHILDREN,
|
||||
ArrayList(prefs.children)
|
||||
)
|
||||
|
||||
rootFragment.arguments = args
|
||||
loadFragment(rootFragment)
|
||||
}
|
||||
|
||||
override fun onInsetsUpdated(insets: Rect) {
|
||||
super.onInsetsUpdated(insets)
|
||||
|
||||
val toolbar: View = binding.toolbar
|
||||
toolbar.setPadding(
|
||||
toolbar.paddingLeft + insets.left,
|
||||
toolbar.paddingTop,
|
||||
toolbar.paddingRight + insets.right,
|
||||
toolbar.paddingBottom
|
||||
)
|
||||
|
||||
val fragmentContainer: View = binding.fragmentContainerParent
|
||||
fragmentContainer.setPadding(
|
||||
fragmentContainer.paddingLeft + insets.left,
|
||||
fragmentContainer.paddingTop,
|
||||
fragmentContainer.paddingRight + insets.right,
|
||||
fragmentContainer.paddingBottom
|
||||
)
|
||||
}
|
||||
|
||||
override fun bindLayout(): View {
|
||||
_binding = ActivityPreferencesBinding.inflate(
|
||||
layoutInflater)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun loadFragment(fragment: Fragment) {
|
||||
super.loadFragment(fragment, binding.fragmentContainer.id)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package com.itsaky.androidide.activities.editor
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller.SessionCallback
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
@@ -28,6 +29,7 @@ import android.text.TextUtils
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.ActivityResult
|
||||
@@ -38,6 +40,8 @@ import androidx.annotation.GravityInt
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePaddingRelative
|
||||
import com.blankj.utilcode.util.FileUtils
|
||||
import com.blankj.utilcode.util.KeyboardUtils
|
||||
import com.blankj.utilcode.util.ThreadUtils
|
||||
@@ -50,11 +54,12 @@ import com.itsaky.androidide.R.string
|
||||
import com.itsaky.androidide.actions.ActionItem.Location.EDITOR_FILE_TABS
|
||||
import com.itsaky.androidide.adapters.DiagnosticsAdapter
|
||||
import com.itsaky.androidide.adapters.SearchListAdapter
|
||||
import com.itsaky.androidide.app.IDEActivity
|
||||
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
|
||||
import com.itsaky.androidide.databinding.ActivityEditorBinding
|
||||
import com.itsaky.androidide.databinding.LayoutDiagnosticInfoBinding
|
||||
import com.itsaky.androidide.events.InstallationResultEvent
|
||||
import com.itsaky.androidide.fragments.SearchResultFragment
|
||||
import com.itsaky.androidide.fragments.sidebar.EditorSidebarFragment
|
||||
import com.itsaky.androidide.fragments.sidebar.FileTreeFragment
|
||||
import com.itsaky.androidide.handlers.EditorActivityLifecyclerObserver
|
||||
import com.itsaky.androidide.handlers.LspHandler.registerLanguageServers
|
||||
@@ -96,7 +101,7 @@ import java.io.File
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract class BaseEditorActivity : IDEActivity(), TabLayout.OnTabSelectedListener,
|
||||
abstract class BaseEditorActivity : EdgeToEdgeIDEActivity(), TabLayout.OnTabSelectedListener,
|
||||
DiagnosticClickListener {
|
||||
|
||||
protected val mLifecycleObserver = EditorActivityLifecyclerObserver()
|
||||
@@ -194,6 +199,19 @@ abstract class BaseEditorActivity : IDEActivity(), TabLayout.OnTabSelectedListen
|
||||
return this.binding.root
|
||||
}
|
||||
|
||||
override fun onInsetsUpdated(insets: Rect) {
|
||||
super.onInsetsUpdated(insets)
|
||||
this._binding?.apply {
|
||||
drawerSidebar.getFragment<EditorSidebarFragment>()
|
||||
.onApplyWindowInsets(insets)
|
||||
|
||||
editorToolbar.updatePaddingRelative(
|
||||
start = editorToolbar.paddingStart + insets.left,
|
||||
end = editorToolbar.paddingEnd + insets.right
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = MAIN)
|
||||
open fun onInstallationResult(event: InstallationResultEvent) {
|
||||
val intent = event.intent
|
||||
@@ -544,7 +562,7 @@ abstract class BaseEditorActivity : IDEActivity(), TabLayout.OnTabSelectedListen
|
||||
|
||||
binding.apply {
|
||||
viewContainer.viewTreeObserver.addOnGlobalLayoutListener(observer)
|
||||
bottomSheet.setOffsetAnchor(editorToolbar)
|
||||
bottomSheet.setOffsetAnchor(editorAppBarLayout)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,6 @@ package com.itsaky.androidide.activities.editor
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class EditorActivityKt : EditorHandlerActivity()
|
||||
class EditorActivityKt : EditorHandlerActivity()
|
||||
|
||||
// TODO: Should we adjust to the display cutout insets?
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE 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.
|
||||
*
|
||||
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.app
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.OnApplyWindowInsetsListener
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.doOnAttach
|
||||
import androidx.core.view.setPadding
|
||||
import com.itsaky.androidide.utils.EdgeToEdgeUtils
|
||||
import com.itsaky.androidide.utils.getInsets
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
/**
|
||||
* Same as IDEActivity but DecorFitsSystemWindows is set to false
|
||||
* Useful for creating immersive edge-to-edge experiences.
|
||||
*
|
||||
* @author Smooth E
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class EdgeToEdgeIDEActivity : IDEActivity() {
|
||||
|
||||
/**
|
||||
* Whether edge-to-edge should be applied to the activity.
|
||||
*/
|
||||
protected open var edgeToEdgeEnabled = true
|
||||
|
||||
/**
|
||||
* Whether the decor view padding should be updated to match the system bars in landscape orientation.
|
||||
*/
|
||||
protected open var eteUpdateDecorViewPaddingInLandscape = true
|
||||
|
||||
/**
|
||||
* Style for the status bar.
|
||||
*/
|
||||
protected open val statusBarStyle = EdgeToEdgeUtils.DEFAULT_STATUS_BAR_STYLE!!
|
||||
|
||||
/**
|
||||
* Style for the navigation bar.
|
||||
*/
|
||||
protected open val navigationBarStyle = EdgeToEdgeUtils.DEFAULT_NAVIGATION_BAR_STYLE!!
|
||||
|
||||
/**
|
||||
* Original padding of the window's decor view.
|
||||
*/
|
||||
protected open var decorViewPadding: Rect? = null
|
||||
|
||||
override var enableSystemBarTheming: Boolean
|
||||
get() = false
|
||||
set(@Suppress("UNUSED_PARAMETER") value) {
|
||||
throw UnsupportedOperationException("Use edgeToEdgeEnabled and systemBarStyles instead")
|
||||
}
|
||||
|
||||
private val log = LoggerFactory.getLogger(EdgeToEdgeIDEActivity::class.java)
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
private val onApplyWindowInsetsListener = OnApplyWindowInsetsListener { v, insets ->
|
||||
if (!eteUpdateDecorViewPaddingInLandscape ||
|
||||
v.resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
|
||||
) {
|
||||
decorViewPadding?.also { p ->
|
||||
// when switching from landscape to portrait, restore the original padding
|
||||
v.setPadding(p.left, p.top, p.right, p.bottom)
|
||||
}
|
||||
return@OnApplyWindowInsetsListener insets
|
||||
}
|
||||
|
||||
if (decorViewPadding == null) {
|
||||
Rect().apply {
|
||||
left = v.paddingLeft
|
||||
top = v.paddingTop
|
||||
right = v.paddingRight
|
||||
bottom = v.paddingBottom
|
||||
}.also { paddings ->
|
||||
decorViewPadding = paddings
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
v.setPadding(
|
||||
insets.getInsets(WindowInsets.Type.systemBars()).left,
|
||||
0,
|
||||
insets.getInsets(WindowInsets.Type.systemBars()).right,
|
||||
insets.getInsets(WindowInsets.Type.systemBars()).bottom)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
v.setPadding(
|
||||
insets.stableInsetLeft,
|
||||
0,
|
||||
insets.stableInsetRight,
|
||||
insets.stableInsetBottom)
|
||||
}
|
||||
|
||||
insets
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
applyEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||
applyEdgeToEdge()
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private fun applyEdgeToEdge() {
|
||||
this.window!!.apply {
|
||||
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
@Suppress("DEPRECATION")
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
}
|
||||
|
||||
EdgeToEdgeUtils.applyEdgeToEdge(this, this.statusBarStyle, this.navigationBarStyle)
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
this.window.decorView,
|
||||
this.onApplyWindowInsetsListener
|
||||
)
|
||||
|
||||
this.window.decorView.doOnAttach { decorView -> onInsetsUpdated(getInsets(decorView)) }
|
||||
}
|
||||
|
||||
/** Called whenever insets are updated */
|
||||
protected open fun onInsetsUpdated(insets: Rect) {}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE 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.
|
||||
*
|
||||
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.app
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.doOnAttach
|
||||
import com.itsaky.androidide.utils.NavigationBar
|
||||
import com.itsaky.androidide.utils.getInsets
|
||||
import com.itsaky.androidide.utils.resolveAttr
|
||||
|
||||
/**
|
||||
* Same as IDEActivity but DecorFitsSystemWindows is set to false
|
||||
* Useful for creating immersive edge-to-edge experiences
|
||||
*
|
||||
* @author Smooth E
|
||||
*/
|
||||
abstract class LimitlessIDEActivity(
|
||||
private val highlightNavigationBar: Boolean = false
|
||||
) : IDEActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
makeLimitless()
|
||||
installOnDecorViewAttachedListener()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
makeLimitless()
|
||||
installOnDecorViewAttachedListener()
|
||||
}
|
||||
|
||||
private fun makeLimitless() {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
paintNavigationBar()
|
||||
|
||||
// This removes a black strip on the side where the camera cutout is in landscape mode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
window.attributes.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
}
|
||||
}
|
||||
|
||||
private fun installOnDecorViewAttachedListener() {
|
||||
window.decorView.doOnAttach { decorView -> onInsetsUpdated(getInsets(decorView)) }
|
||||
}
|
||||
|
||||
/** Called whenever insets are updated */
|
||||
open fun onInsetsUpdated(insets: Rect) { }
|
||||
|
||||
private fun paintNavigationBar() {
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
|
||||
if (!highlightNavigationBar) {
|
||||
return
|
||||
}
|
||||
|
||||
val refrainHighlighting =
|
||||
NavigationBar.getInteractionMode(this) == NavigationBar.MODE_GESTURES ||
|
||||
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
|
||||
if (refrainHighlighting) {
|
||||
return
|
||||
}
|
||||
|
||||
val navigationBarColor = resolveAttr(com.google.android.material.R.attr.colorSurface)
|
||||
window.navigationBarColor = navigationBarColor
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val dividerColor = resolveAttr(com.google.android.material.R.attr.colorOutlineVariant)
|
||||
window.navigationBarDividerColor = dividerColor
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -89,10 +89,6 @@ class RunTasksDialogFragment : BottomSheetDialogFragment() {
|
||||
val dialog = object : BottomSheetDialog(requireContext(), theme) {
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
window?.apply {
|
||||
WindowCompat.setDecorFitsSystemWindows(this, false)
|
||||
updateSystemBarColors(navigationBarColor = Color.TRANSPARENT)
|
||||
}
|
||||
findViewById<View>(com.google.android.material.R.id.container)?.apply {
|
||||
doOnApplyWindowInsets { view, insets, _, margins ->
|
||||
insets.getInsets(statusBars() or navigationBars()).apply {
|
||||
|
||||
@@ -17,8 +17,16 @@
|
||||
|
||||
package com.itsaky.androidide.fragments.sidebar
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.marginTop
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updateMarginsRelative
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.core.view.updatePaddingRelative
|
||||
import com.itsaky.androidide.databinding.FragmentEditorSidebarBinding
|
||||
import com.itsaky.androidide.fragments.FragmentWithBinding
|
||||
import com.itsaky.androidide.utils.EditorSidebarActions
|
||||
@@ -32,14 +40,33 @@ class EditorSidebarFragment : FragmentWithBinding<FragmentEditorSidebarBinding>(
|
||||
FragmentEditorSidebarBinding::inflate
|
||||
) {
|
||||
|
||||
internal fun onApplyWindowInsets(insets: Rect) {
|
||||
_binding?.apply {
|
||||
title.updateLayoutParams<MarginLayoutParams> {
|
||||
updateMarginsRelative(
|
||||
top = title.marginTop + insets.top,
|
||||
)
|
||||
}
|
||||
fragmentContainer.updateLayoutParams<MarginLayoutParams> {
|
||||
updateMarginsRelative(
|
||||
bottom = fragmentContainer.marginBottom + insets.bottom,
|
||||
)
|
||||
}
|
||||
navigation.updatePadding(
|
||||
top = navigation.paddingTop + insets.top,
|
||||
bottom = navigation.paddingBottom + insets.bottom,
|
||||
left = navigation.paddingLeft + insets.left,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
EditorSidebarActions.setup(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the action only if the binding is not null.
|
||||
* Get the (nullable) binding object for this fragment.
|
||||
*/
|
||||
internal fun getBinding() = _binding
|
||||
}
|
||||
@@ -19,16 +19,20 @@ package com.itsaky.androidide.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.GravityInt
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.core.view.updatePaddingRelative
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.transition.TransitionManager
|
||||
@@ -54,6 +58,7 @@ import com.itsaky.androidide.tasks.TaskExecutor.executeAsyncProvideError
|
||||
import com.itsaky.androidide.utils.IntentUtils.shareFile
|
||||
import com.itsaky.androidide.utils.Symbols.forFile
|
||||
import com.itsaky.androidide.utils.flashError
|
||||
import com.itsaky.androidide.utils.getInsets
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@@ -63,6 +68,7 @@ import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption.CREATE_NEW
|
||||
import java.nio.file.StandardOpenOption.WRITE
|
||||
import java.util.concurrent.Callable
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Bottom sheet shown in editor activity.
|
||||
@@ -84,12 +90,14 @@ constructor(
|
||||
|
||||
@JvmField
|
||||
var binding: LayoutEditorBottomSheetBinding
|
||||
|
||||
val pagerAdapter: EditorBottomSheetTabAdapter
|
||||
|
||||
private var windowInsets: Rect? = null
|
||||
|
||||
companion object {
|
||||
|
||||
private val log = LoggerFactory.getLogger(EditorBottomSheet::class.java)
|
||||
private const val COLLAPSE_HEADER_AT_OFFSET = 0.5f
|
||||
|
||||
const val CHILD_HEADER = 0
|
||||
const val CHILD_SYMBOL_INPUT = 1
|
||||
@@ -160,6 +168,11 @@ constructor(
|
||||
sheet.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
|
||||
this.windowInsets = getInsets(view)
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -184,23 +197,52 @@ constructor(
|
||||
override fun onGlobalLayout() {
|
||||
val sheet = BottomSheetBehavior.from(this@EditorBottomSheet)
|
||||
val offset = view.height + SizeUtils.dp2px(1f)
|
||||
val collapsedHeight = collapsedHeight
|
||||
|
||||
sheet.isFitToContents = false
|
||||
sheet.halfExpandedRatio = 0.3f
|
||||
sheet.skipCollapsed = true
|
||||
sheet.isGestureInsetBottomIgnored = false
|
||||
sheet.peekHeight = binding.headerContainer.height
|
||||
sheet.peekHeight = collapsedHeight.roundToInt()
|
||||
sheet.expandedOffset = offset
|
||||
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
|
||||
binding.root.updatePadding(bottom = offset + SizeUtils.dp2px(16f))
|
||||
val insetBottom = windowInsets?.bottom ?: 0
|
||||
binding.root.updatePadding(bottom = offset + insetBottom)
|
||||
binding.headerContainer.apply {
|
||||
updatePaddingRelative(bottom = paddingBottom + insetBottom)
|
||||
updateLayoutParams<ViewGroup.LayoutParams> {
|
||||
height = (collapsedHeight + insetBottom).roundToInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view.viewTreeObserver.addOnGlobalLayoutListener(listener)
|
||||
}
|
||||
|
||||
fun onSlide(offset: Float) {
|
||||
if (offset >= 0.5f) {
|
||||
updateCollapsedHeight(((0.5f - offset) + 0.5f) * 2f)
|
||||
} else updateCollapsedHeight(1f)
|
||||
fun onSlide(sheetOffset: Float) {
|
||||
val heightScale = if (sheetOffset >= COLLAPSE_HEADER_AT_OFFSET) {
|
||||
((COLLAPSE_HEADER_AT_OFFSET - sheetOffset) + COLLAPSE_HEADER_AT_OFFSET) * 2f
|
||||
} else {
|
||||
1f
|
||||
}
|
||||
|
||||
val paddingScale = if (sheetOffset <= COLLAPSE_HEADER_AT_OFFSET) {
|
||||
((1f - sheetOffset) * 2f) - 1f
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
|
||||
val insetBottom = windowInsets?.bottom ?: 0
|
||||
val padding = insetBottom * paddingScale
|
||||
binding.headerContainer.apply {
|
||||
updateLayoutParams<ViewGroup.LayoutParams> {
|
||||
height = ((collapsedHeight + padding) * heightScale).roundToInt()
|
||||
}
|
||||
updatePaddingRelative(
|
||||
bottom = padding.roundToInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun showChild(index: Int) {
|
||||
@@ -276,12 +318,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCollapsedHeight(offset: Float) {
|
||||
binding.headerContainer.updateLayoutParams<android.view.ViewGroup.LayoutParams> {
|
||||
height = (collapsedHeight * offset).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareFile(file: File) {
|
||||
shareFile(context, file, "text/plain")
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:ignore="DuplicateIncludedIds"
|
||||
tools:openDrawer="start">
|
||||
android:background="?attr/colorSurface"
|
||||
tools:ignore="DuplicateIncludedIds">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/realContainer"
|
||||
@@ -19,6 +19,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:fitsSystemWindows="true"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
|
||||
|
||||
<com.itsaky.androidide.ui.ExtendedMenuToolbar
|
||||
@@ -47,7 +48,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<!--Views in this flipper are dynamically added and must be instances of CodeEditorView-->
|
||||
@@ -55,8 +55,7 @@
|
||||
android:id="@+id/editor_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/editor_sheet_peek_height"
|
||||
android:background="?attr/colorSurface" />
|
||||
android:layout_marginBottom="@dimen/editor_sheet_peek_height" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -32,6 +32,8 @@ abstract class BaseIDEActivity : AppCompatActivity() {
|
||||
|
||||
open val subscribeToEvents: Boolean = false
|
||||
|
||||
open var enableSystemBarTheming: Boolean = true
|
||||
|
||||
open val navigationBarColor: Int
|
||||
get() = resolveAttr(R.attr.colorSurface)
|
||||
|
||||
@@ -44,9 +46,11 @@ abstract class BaseIDEActivity : AppCompatActivity() {
|
||||
val activityScope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
window?.apply {
|
||||
navigationBarColor = this@BaseIDEActivity.navigationBarColor
|
||||
statusBarColor = this@BaseIDEActivity.statusBarColor
|
||||
if (enableSystemBarTheming) {
|
||||
window?.apply {
|
||||
navigationBarColor = this@BaseIDEActivity.navigationBarColor
|
||||
statusBarColor = this@BaseIDEActivity.statusBarColor
|
||||
}
|
||||
}
|
||||
IThemeManager.getInstance().applyTheme(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE 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.
|
||||
*
|
||||
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.utils;
|
||||
|
||||
import static android.graphics.Color.TRANSPARENT;
|
||||
import static com.google.android.material.color.MaterialColors.isColorLight;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.view.Window;
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.activity.SystemBarStyle;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
|
||||
/**
|
||||
* A util class that helps apply edge-to-edge mode to activity/dialog windows.
|
||||
* <p>
|
||||
* <b>AndroidIDE Changed</b>: Allow to choose if the status bar and navigation bar's color should
|
||||
* be changed or not.
|
||||
*
|
||||
* @see <a
|
||||
* href="https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/internal/EdgeToEdgeUtils.java">EdgeToEdgeUtils.java</a>
|
||||
*/
|
||||
public class EdgeToEdgeUtils {
|
||||
|
||||
private static final int EDGE_TO_EDGE_BAR_ALPHA = 128;
|
||||
|
||||
public static final int DEFAULT_LIGHT_SCRIM = EdgeToEdge.getDefaultLightScrim();
|
||||
public static final int DEFAULT_DARK_SCRIM = EdgeToEdge.getDefaultDarkScrim();
|
||||
|
||||
public static final SystemBarStyle DEFAULT_STATUS_BAR_STYLE = SystemBarStyle.auto(TRANSPARENT,
|
||||
TRANSPARENT);
|
||||
public static final SystemBarStyle DEFAULT_NAVIGATION_BAR_STYLE = SystemBarStyle.auto(
|
||||
DEFAULT_LIGHT_SCRIM, DEFAULT_DARK_SCRIM);
|
||||
|
||||
private EdgeToEdgeUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable edge-to-edge mode for the provided activity, using the built-in
|
||||
* {@link EdgeToEdge#enable(androidx.activity.ComponentActivity, SystemBarStyle,
|
||||
* SystemBarStyle)}.
|
||||
*
|
||||
* @param activity The activity to enable edge-to-edge mode for.
|
||||
* @param statusBarStyle The status bar style to use.
|
||||
* @param navigationBarStyle The navigation bar style to use.
|
||||
*/
|
||||
public static void applyEdgeToEdge(
|
||||
ComponentActivity activity,
|
||||
SystemBarStyle statusBarStyle,
|
||||
SystemBarStyle navigationBarStyle
|
||||
) {
|
||||
EdgeToEdge.enable(activity, statusBarStyle, navigationBarStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies or removes edge-to-edge mode to the provided {@link Window}. When edge-to-edge mode is
|
||||
* applied, the activities, or the non-floating dialogs, that host the provided window will be
|
||||
* drawn over the system bar area by default and the system bar colors will be adjusted according
|
||||
* to the background color you provide.
|
||||
*/
|
||||
public static void applyEdgeToEdgeManually(
|
||||
@NonNull Window window,
|
||||
boolean edgeToEdgeEnabled,
|
||||
@Nullable @ColorInt Integer statusBarColor,
|
||||
@Nullable @ColorInt Integer navBarColor) {
|
||||
applyEdgeToEdgeManually(window, edgeToEdgeEnabled, null, null, statusBarColor,
|
||||
navBarColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies or removes edge-to-edge mode to the provided {@link Window}. When edge-to-edge mode is
|
||||
* applied, the activities, or the non-floating dialogs, that host the provided window will be
|
||||
* drawn over the system bar area by default and the system bar colors will be adjusted according
|
||||
* to the background color you provide.
|
||||
*
|
||||
* @param statusBarOverlapBackgroundColor The reference background color to decide the
|
||||
* text/icon colors on status bars. {@code null} to use
|
||||
* the default color from
|
||||
* {@code ?android:attr/colorBackground}.
|
||||
* @param navigationBarOverlapBackgroundColor The reference background color to decide the icon
|
||||
* colors on navigation bars.{@code null} to use the
|
||||
* default color from
|
||||
* {@code ?android:attr/colorBackground}.
|
||||
*/
|
||||
public static void applyEdgeToEdgeManually(
|
||||
@NonNull Window window,
|
||||
boolean edgeToEdgeEnabled,
|
||||
@Nullable @ColorInt Integer statusBarOverlapBackgroundColor,
|
||||
@Nullable @ColorInt Integer navigationBarOverlapBackgroundColor,
|
||||
@Nullable @ColorInt Integer statusBarColor,
|
||||
@Nullable @ColorInt Integer navBarColor
|
||||
) {
|
||||
|
||||
// If the overlapping background color is unknown or TRANSPARENT, use the default one.
|
||||
boolean useDefaultBackgroundColorForStatusBar =
|
||||
statusBarOverlapBackgroundColor == null || statusBarOverlapBackgroundColor == 0;
|
||||
boolean useDefaultBackgroundColorForNavigationBar =
|
||||
navigationBarOverlapBackgroundColor == null || navigationBarOverlapBackgroundColor == 0;
|
||||
if (useDefaultBackgroundColorForStatusBar || useDefaultBackgroundColorForNavigationBar) {
|
||||
int defaultBackgroundColor =
|
||||
MaterialColors.getColor(window.getContext(), android.R.attr.colorBackground, Color.BLACK);
|
||||
if (useDefaultBackgroundColorForStatusBar) {
|
||||
statusBarOverlapBackgroundColor = defaultBackgroundColor;
|
||||
}
|
||||
if (useDefaultBackgroundColorForNavigationBar) {
|
||||
navigationBarOverlapBackgroundColor = defaultBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, !edgeToEdgeEnabled);
|
||||
|
||||
int color = statusBarColor != null ? statusBarColor
|
||||
: getStatusBarColor(window.getContext(), edgeToEdgeEnabled);
|
||||
window.setStatusBarColor(color);
|
||||
setLightStatusBar(
|
||||
window,
|
||||
isUsingLightSystemBar(color, isColorLight(statusBarOverlapBackgroundColor)));
|
||||
|
||||
color = navBarColor != null ? navBarColor
|
||||
: getNavigationBarColor(window.getContext(), edgeToEdgeEnabled);
|
||||
window.setNavigationBarColor(color);
|
||||
setLightNavigationBar(
|
||||
window,
|
||||
isUsingLightSystemBar(
|
||||
color, isColorLight(navigationBarOverlapBackgroundColor)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the foreground color of the status bars to light or dark so that the items on the bar
|
||||
* can be read clearly.
|
||||
*
|
||||
* @param window Window that hosts the status bars
|
||||
* @param isLight {@code true} to make the foreground color light
|
||||
*/
|
||||
public static void setLightStatusBar(@NonNull Window window, boolean isLight) {
|
||||
WindowInsetsControllerCompat insetsController =
|
||||
WindowCompat.getInsetsController(window, window.getDecorView());
|
||||
insetsController.setAppearanceLightStatusBars(isLight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the foreground color of the navigation bars to light or dark so that the items on the
|
||||
* bar can be read clearly.
|
||||
*
|
||||
* @param window Window that hosts the status bars
|
||||
* @param isLight {@code true} to make the foreground color light.
|
||||
*/
|
||||
public static void setLightNavigationBar(@NonNull Window window, boolean isLight) {
|
||||
WindowInsetsControllerCompat insetsController =
|
||||
WindowCompat.getInsetsController(window, window.getDecorView());
|
||||
insetsController.setAppearanceLightNavigationBars(isLight);
|
||||
}
|
||||
|
||||
private static int getStatusBarColor(Context context, boolean isEdgeToEdgeEnabled) {
|
||||
if (isEdgeToEdgeEnabled) {
|
||||
return TRANSPARENT;
|
||||
}
|
||||
return MaterialColors.getColor(context, android.R.attr.statusBarColor, Color.BLACK);
|
||||
}
|
||||
|
||||
private static int getNavigationBarColor(Context context, boolean isEdgeToEdgeEnabled) {
|
||||
// Light navigation bars are only supported on O_MR1+. So we need to use a translucent black
|
||||
// navigation bar instead to ensure the text/icon contrast of it.
|
||||
if (isEdgeToEdgeEnabled && VERSION.SDK_INT < VERSION_CODES.O_MR1) {
|
||||
int opaqueNavBarColor =
|
||||
MaterialColors.getColor(context, android.R.attr.navigationBarColor, Color.BLACK);
|
||||
return ColorUtils.setAlphaComponent(opaqueNavBarColor, EDGE_TO_EDGE_BAR_ALPHA);
|
||||
}
|
||||
if (isEdgeToEdgeEnabled) {
|
||||
return TRANSPARENT;
|
||||
}
|
||||
return MaterialColors.getColor(context, android.R.attr.navigationBarColor, Color.BLACK);
|
||||
}
|
||||
|
||||
private static boolean isUsingLightSystemBar(int systemBarColor, boolean isLightBackground) {
|
||||
return isColorLight(systemBarColor) || (systemBarColor == TRANSPARENT && isLightBackground);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ fun getInsets(view: View): Rect {
|
||||
val typeMask = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout()
|
||||
rootWindowInsets.getInsetsIgnoringVisibility(typeMask)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
view.rootWindowInsets.stableInsets
|
||||
}
|
||||
|
||||
@@ -52,6 +53,7 @@ fun getInsets(view: View): Rect {
|
||||
receivedInsets.bottom
|
||||
)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
insets = Rect(
|
||||
rootWindowInsets.stableInsetLeft,
|
||||
rootWindowInsets.stableInsetTop,
|
||||
|
||||
@@ -8,7 +8,7 @@ kotlin-coroutines = "1.8.0"
|
||||
tree-sitter = "4.3.1"
|
||||
editor = "0.23.4-ce8de8e-SNAPSHOT"
|
||||
glide = "4.16.0"
|
||||
androidx-vectordrawable = "1.1.0"
|
||||
androidx-vectordrawable = "1.2.0"
|
||||
androidx-navigation = "2.7.7"
|
||||
ksp = "1.9.22-1.0.17"
|
||||
antlr4 = "4.13.1"
|
||||
@@ -84,12 +84,12 @@ androidx-preference = { module = "androidx.preference:preference", version = "1.
|
||||
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.3.2" }
|
||||
androidx-vectors = { module = "androidx.vectordrawable:vectordrawable", version.ref = "androidx-vectordrawable" }
|
||||
androidx-animated_vectors = { module = "androidx.vectordrawable:vectordrawable-animated", version.ref = "androidx-vectordrawable" }
|
||||
androidx-core = { module = "androidx.core:core", version = "1.12.0" }
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version = "1.12.0" }
|
||||
androidx-fragment_ktx = { module = "androidx.fragment:fragment-ktx", version = "1.6.2" }
|
||||
androidx-core = { module = "androidx.core:core", version = "1.13.1" }
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version = "1.13.1" }
|
||||
androidx-fragment_ktx = { module = "androidx.fragment:fragment-ktx", version = "1.7.0" }
|
||||
androidx-libDesugaring = { module = "com.android.tools:desugar_jdk_libs", version = "2.0.4" }
|
||||
androidx-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.0.1" }
|
||||
androidx-transition = { module = "androidx.transition:transition-ktx", version = "1.4.1" }
|
||||
androidx-transition = { module = "androidx.transition:transition-ktx", version = "1.5.0" }
|
||||
androidx-nav-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
|
||||
androidx-nav-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" }
|
||||
androidx-tracing = { module = "androidx.tracing:tracing", version = "1.2.0" }
|
||||
|
||||
@@ -25,7 +25,8 @@ import android.os.Parcelable
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
object IDEPreferences : BaseIDEPreferences(){
|
||||
data object IDEPreferences : BaseIDEPreferences() {
|
||||
|
||||
override val children: List<IPreference> = mutableListOf()
|
||||
override fun describeContents(): Int = 0
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {}
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
<style name="Theme.AndroidIDE.Material3" parent="Theme.Material3.Dark.NoActionBar"/>
|
||||
|
||||
<style name="Theme.AndroidIDE" parent="Theme.AndroidIDE.Styled">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="27">false</item>
|
||||
|
||||
<!-- Left drawer. -->
|
||||
<item name="buttonBarButtonStyle">@style/TermuxActivity.Drawer.ButtonBarStyle.Dark</item>
|
||||
<item name="termuxActivityDrawerBackground">@color/black</item>
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
</style>
|
||||
|
||||
<style name="Theme.AndroidIDE.Styled" parent="Theme.AndroidIDE.Base">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="switchPreferenceStyle">@style/AppTheme.SwitchPreference</item>
|
||||
<item name="shapeAppearanceLargeComponent">@style/AppTheme.ShapeOverlay.Large</item>
|
||||
<item name="textAppearanceBodySmall">@style/TextAppearance.AndroidIDE.BodySmall</item>
|
||||
@@ -37,9 +35,6 @@
|
||||
</style>
|
||||
|
||||
<style name="Theme.AndroidIDE" parent="Theme.AndroidIDE.Styled">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="27">true</item>
|
||||
|
||||
<!-- Left drawer. -->
|
||||
<item name="buttonBarButtonStyle">@style/TermuxActivity.Drawer.ButtonBarStyle.Light</item>
|
||||
<item name="termuxActivityDrawerBackground">@android:color/white</item>
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ class ProjectManagerImpl : IProjectManager, EventReceiver {
|
||||
withStopWatch("Setup project") {
|
||||
val indexerScope = CoroutineScope(Dispatchers.Default)
|
||||
val modulesFlow = flow {
|
||||
rootProject.subProjects.filterIsInstance(ModuleProject::class.java).forEach {
|
||||
rootProject.subProjects.filterIsInstance<ModuleProject>().forEach {
|
||||
emit(it)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user