Skip to content

Commit 00bccbc

Browse files
author
ADFA
committed
Daily merge from stage to main
2 parents deadfc6 + f7befd3 commit 00bccbc

File tree

27 files changed

+971
-199
lines changed

27 files changed

+971
-199
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,37 @@
8484
</activity>
8585
<activity
8686
android:name=".activities.OnboardingActivity"
87+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
8788
android:exported="false" />
8889
<activity
8990
android:name=".activities.MainActivity"
91+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
9092
android:exported="false"
9193
android:theme="@style/Theme.AndroidIDE" />
9294
<activity
9395
android:name=".activities.editor.EditorActivityKt"
94-
android:configChanges="orientation|screenSize"
96+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
9597
android:launchMode="singleTask"
9698
android:windowSoftInputMode="adjustResize" />
97-
<activity android:name=".activities.PreferencesActivity" />
98-
<activity android:name=".activities.PluginManagerActivity" />
99+
<activity
100+
android:name=".activities.PreferencesActivity"
101+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" />
102+
<activity
103+
android:name=".activities.PluginManagerActivity"
104+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" />
99105
<activity android:name=".activities.AboutActivity" />
100-
<activity android:name=".activities.editor.FAQActivity" />
101-
<activity android:name=".activities.editor.HelpActivity" />
102-
<activity android:name=".activities.ContributorsActivity" />
106+
<activity
107+
android:name=".activities.editor.FAQActivity"
108+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" />
109+
<activity
110+
android:name=".activities.editor.HelpActivity"
111+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" />
112+
<activity
113+
android:name=".activities.ContributorsActivity"
114+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" />
103115
<activity
104116
android:name=".activities.TerminalActivity"
117+
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
105118
android:windowSoftInputMode="adjustResize" />
106119

107120
<!-- Required: set your sentry.io project identifier (DSN) -->

app/src/main/java/com/itsaky/androidide/activities/MainActivity.kt

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.itsaky.androidide.activities
1919

2020
import android.content.Intent
21+
import android.content.res.Configuration
2122
import android.os.Bundle
2223
import android.view.View
2324
import androidx.activity.OnBackPressedCallback
@@ -47,6 +48,8 @@ import com.itsaky.androidide.utils.FeatureFlags
4748
import com.itsaky.androidide.utils.UrlManager
4849
import com.itsaky.androidide.utils.findValidProjects
4950
import com.itsaky.androidide.utils.flashInfo
51+
import com.itsaky.androidide.fragments.MainFragment
52+
import com.itsaky.androidide.fragments.RecentProjectsFragment
5053
import com.itsaky.androidide.viewmodel.MainViewModel
5154
import com.itsaky.androidide.viewmodel.MainViewModel.Companion.SCREEN_DELETE_PROJECTS
5255
import com.itsaky.androidide.viewmodel.MainViewModel.Companion.SCREEN_MAIN
@@ -168,22 +171,53 @@ class MainActivity : EdgeToEdgeIDEActivity() {
168171
builder.show()
169172
}
170173

174+
override fun onConfigurationChanged(newConfig: Configuration) {
175+
super.onConfigurationChanged(newConfig)
176+
recreateVisibleFragmentView()
177+
}
178+
171179
override fun onResume() {
172180
super.onResume()
173181
feedbackButtonManager?.loadFabPosition()
174182
}
175183

184+
/**
185+
* With configChanges="orientation|screenSize", the activity is not recreated on rotation,
186+
* so fragment views stay inflated with the initial layout. Replace the visible fragment
187+
* with a new instance so it re-inflates and picks up layout-land when in landscape.
188+
*/
189+
private fun recreateVisibleFragmentView() {
190+
when (viewModel.currentScreen.value) {
191+
SCREEN_MAIN ->
192+
supportFragmentManager.beginTransaction()
193+
.setReorderingAllowed(true)
194+
.replace(R.id.main, MainFragment())
195+
.commitNow()
196+
SCREEN_SAVED_PROJECTS ->
197+
supportFragmentManager.beginTransaction()
198+
.setReorderingAllowed(true)
199+
.replace(R.id.saved_projects_view, RecentProjectsFragment())
200+
.commitNow()
201+
else -> { }
202+
}
203+
}
204+
176205
override fun onApplySystemBarInsets(insets: Insets) {
177206
// onApplySystemBarInsets can be called before bindLayout() sets _binding
207+
// Use 0 for bottom so fragment content stretches to the screen bottom (no white bar).
178208
_binding?.fragmentContainersParent?.setPadding(
179209
insets.left,
180210
0,
181211
insets.right,
182-
insets.bottom,
212+
0,
183213
)
184214
}
185215

186216
private fun onScreenChanged(screen: Int?) {
217+
// When navigating to main (e.g. Exit from saved projects), replace the fragment so it
218+
// inflates with the current configuration (landscape -> 3 columns, portrait -> 1 column).
219+
if (screen == SCREEN_MAIN) recreateVisibleFragmentView()
220+
187221
val previous = viewModel.previousScreen
188222
if (previous != -1) {
189223
closeKeyboard()

app/src/main/java/com/itsaky/androidide/activities/OnboardingActivity.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.itsaky.androidide.activities
1919

2020
import android.annotation.SuppressLint
2121
import android.content.Intent
22+
import android.content.pm.ActivityInfo
2223
import android.os.Bundle
2324
import android.util.TypedValue
2425
import android.view.View
@@ -50,7 +51,6 @@ import com.itsaky.androidide.preferences.internal.prefManager
5051
import com.itsaky.androidide.tasks.doAsyncWithProgress
5152
import com.itsaky.androidide.ui.themes.IThemeManager
5253
import com.itsaky.androidide.utils.Environment
53-
import com.itsaky.androidide.utils.OrientationUtilities
5454
import com.itsaky.androidide.utils.PermissionsHelper
5555
import com.itsaky.androidide.utils.isAtLeastV
5656
import com.itsaky.androidide.utils.isSystemInDarkMode
@@ -82,9 +82,7 @@ class OnboardingActivity : AppIntro2() {
8282
override fun onCreate(savedInstanceState: Bundle?) {
8383
IThemeManager.getInstance().applyTheme(this)
8484
setOrientationFunction {
85-
OrientationUtilities.setOrientation {
86-
OrientationUtilities.setAdaptiveOrientation(this) { requestedOrientation = it }
87-
}
85+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
8886
}
8987

9088
super.onCreate(savedInstanceState)

app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.itsaky.androidide.activities.editor
1919

2020
import android.content.ComponentName
21+
import android.content.res.Configuration
2122
import android.content.Intent
2223
import android.content.ServiceConnection
2324
import android.graphics.Color
@@ -40,6 +41,8 @@ import android.view.MotionEvent
4041
import android.view.View
4142
import android.view.ViewGroup
4243
import android.view.ViewTreeObserver.OnGlobalLayoutListener
44+
import android.widget.LinearLayout
45+
import android.widget.TextView
4346
import androidx.activity.OnBackPressedCallback
4447
import androidx.activity.result.ActivityResult
4548
import androidx.activity.result.ActivityResultLauncher
@@ -596,6 +599,7 @@ abstract class BaseEditorActivity :
596599
}
597600

598601
setupToolbar()
602+
syncProjectToolbarRowForOrientation(resources.configuration.orientation)
599603
setupDrawers()
600604
content.tabs.addOnTabSelectedListener(this)
601605

@@ -631,6 +635,11 @@ abstract class BaseEditorActivity :
631635
setupGestureDetector()
632636
}
633637

638+
override fun onConfigurationChanged(newConfig: Configuration) {
639+
super.onConfigurationChanged(newConfig)
640+
syncProjectToolbarRowForOrientation(newConfig.orientation)
641+
}
642+
634643
private fun setupToolbar() {
635644
// Set the project name in the title TextView
636645
content.root.findViewById<android.widget.TextView>(R.id.title_text)?.apply {
@@ -682,6 +691,88 @@ abstract class BaseEditorActivity :
682691
}
683692
}
684693

694+
private fun syncProjectToolbarRowForOrientation(currentOrientation: Int) {
695+
val appBar = content.editorAppBarLayout
696+
val titleToolbar = content.titleToolbar
697+
val actionsToolbar = content.projectActionsToolbar
698+
699+
val titleParent = titleToolbar.parent as? ViewGroup ?: return
700+
val actionsParent = actionsToolbar.parent as? ViewGroup ?: return
701+
if (titleParent != actionsParent) return
702+
703+
val isLandscape = currentOrientation == Configuration.ORIENTATION_LANDSCAPE
704+
705+
if (isLandscape && titleParent === appBar) {
706+
val insertAt =
707+
minOf(
708+
appBar.indexOfChild(titleToolbar),
709+
appBar.indexOfChild(actionsToolbar),
710+
).coerceAtLeast(0)
711+
val row =
712+
LinearLayout(this).apply {
713+
orientation = LinearLayout.HORIZONTAL
714+
gravity = Gravity.CENTER_VERTICAL
715+
layoutParams =
716+
com.google.android.material.appbar.AppBarLayout.LayoutParams(
717+
ViewGroup.LayoutParams.MATCH_PARENT,
718+
ViewGroup.LayoutParams.WRAP_CONTENT,
719+
)
720+
}
721+
722+
appBar.removeView(titleToolbar)
723+
appBar.removeView(actionsToolbar)
724+
725+
titleToolbar.layoutParams =
726+
LinearLayout.LayoutParams(
727+
0,
728+
ViewGroup.LayoutParams.WRAP_CONTENT,
729+
1f,
730+
)
731+
actionsToolbar.layoutParams =
732+
LinearLayout.LayoutParams(
733+
ViewGroup.LayoutParams.WRAP_CONTENT,
734+
ViewGroup.LayoutParams.WRAP_CONTENT,
735+
).apply { marginEnd = SizeUtils.dp2px(8f) }
736+
737+
content.root.findViewById<TextView>(R.id.title_text)?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
738+
marginEnd = SizeUtils.dp2px(8f)
739+
}
740+
741+
row.addView(titleToolbar)
742+
row.addView(actionsToolbar)
743+
appBar.addView(row, insertAt)
744+
return
745+
}
746+
747+
if (!isLandscape && titleParent is LinearLayout && titleParent.parent === appBar) {
748+
val row = titleParent
749+
val insertAt = appBar.indexOfChild(row).coerceAtLeast(0)
750+
row.removeView(titleToolbar)
751+
row.removeView(actionsToolbar)
752+
appBar.removeView(row)
753+
754+
titleToolbar.layoutParams =
755+
com.google.android.material.appbar.AppBarLayout.LayoutParams(
756+
ViewGroup.LayoutParams.MATCH_PARENT,
757+
ViewGroup.LayoutParams.WRAP_CONTENT,
758+
)
759+
actionsToolbar.layoutParams =
760+
com.google.android.material.appbar.AppBarLayout.LayoutParams(
761+
ViewGroup.LayoutParams.MATCH_PARENT,
762+
ViewGroup.LayoutParams.WRAP_CONTENT,
763+
).apply {
764+
topMargin = SizeUtils.dp2px(4f)
765+
}
766+
767+
content.root.findViewById<TextView>(R.id.title_text)?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
768+
marginEnd = SizeUtils.dp2px(16f)
769+
}
770+
771+
appBar.addView(titleToolbar, insertAt)
772+
appBar.addView(actionsToolbar, insertAt + 1)
773+
}
774+
}
775+
685776
private fun onSwipeRevealDragProgress(progress: Float) {
686777
_binding?.apply {
687778
contentCard.progress = progress

app/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,10 @@ abstract class ProjectHandlerActivity : BaseEditorActivity() {
632632
service.setEventListener(mBuildEventListener)
633633

634634
if (service.isToolingServerStarted()) {
635+
if (service.isBuildInProgress) {
636+
log.info("Skipping project initialization while build is in progress")
637+
return
638+
}
635639
initializeProject()
636640
return
637641
}

app/src/main/java/com/itsaky/androidide/api/commands/GetBuildOutputCommand.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.itsaky.androidide.api.commands
33
import com.itsaky.androidide.agent.model.ToolResult
44
import com.itsaky.androidide.api.BuildOutputProvider
55

6-
76
class GetBuildOutputCommand : Command<Unit> {
87
override fun execute(): ToolResult {
98
return try {

app/src/main/java/com/itsaky/androidide/fragments/MainFragment.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,22 @@ class MainFragment : BaseFragment() {
9494
}
9595
}
9696

97-
binding!!.actions.adapter = MainActionsListAdapter(actions)
97+
// Portrait: single list. Landscape: first 3 (Create, Open, Delete) in middle, last 3 (Terminal, Preferences, Docs) on right.
98+
val leftActions = if (binding!!.actionsRight != null) actions.take(3) else actions
99+
binding!!.actions.adapter = MainActionsListAdapter(leftActions)
100+
binding!!.actionsRight?.adapter = MainActionsListAdapter(actions.drop(3))
98101

99102
binding!!.headerContainer?.setOnClickListener { ifAttached { openQuickstartPageAction() } }
100103
binding!!.headerContainer?.setOnLongClickListener {
101104
ifAttached { TooltipManager.showIdeCategoryTooltip(requireContext(), it, MAIN_GET_STARTED) }
102105
true
103106
}
107+
// Landscape layout uses "greeting" instead of "headerContainer"
108+
binding!!.greeting?.setOnClickListener { ifAttached { openQuickstartPageAction() } }
109+
binding!!.greeting?.setOnLongClickListener {
110+
ifAttached { TooltipManager.showIdeCategoryTooltip(requireContext(), it, MAIN_GET_STARTED) }
111+
true
112+
}
104113

105114
binding!!.greetingText.setOnLongClickListener {
106115
ifAttached { TooltipManager.showIdeCategoryTooltip(requireContext(), it, MAIN_GET_STARTED) }

app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ class PermissionsFragment :
118118
b.onboardingItems.adapter = createAdapter()
119119

120120
b.finishInstallationButton.setOnClickListener {
121+
if (viewModel.state.value is InstallationState.InstallationPending) {
122+
onPermissionsUpdated()
123+
return@setOnClickListener
124+
}
121125
startIdeSetup()
122126
}
123127
}
@@ -134,6 +138,11 @@ class PermissionsFragment :
134138
viewModel.onPermissionsUpdated(allGranted)
135139
}
136140

141+
override fun onResume() {
142+
super.onResume()
143+
onPermissionsUpdated()
144+
}
145+
137146
private fun observeViewModelState() {
138147
viewLifecycleScope.launch {
139148
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {

0 commit comments

Comments
 (0)