Skip to content

Commit 861ce33

Browse files
committed
✨ Resolve landscape orientation issues
1 parent 1745250 commit 861ce33

File tree

10 files changed

+221
-120
lines changed

10 files changed

+221
-120
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
1+
<manifest xmlns:tools="http://schemas.android.com/tools"
2+
xmlns:android="http://schemas.android.com/apk/res/android">
23

34
<uses-feature
45
android:name="android.hardware.camera"
@@ -23,7 +24,9 @@
2324

2425
<activity
2526
android:name=".MainActivity"
26-
android:exported="true">
27+
android:screenOrientation="unspecified"
28+
android:exported="true"
29+
tools:ignore="DiscouragedApi">
2730
<intent-filter>
2831
<action android:name="android.intent.action.MAIN"/>
2932
<category android:name="android.intent.category.LAUNCHER"/>

app/src/main/java/co/stonephone/stonecamera/MainActivity.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package co.stonephone.stonecamera
22

33
import android.Manifest
4+
import android.annotation.SuppressLint
5+
import android.content.pm.ActivityInfo
46
import android.content.pm.PackageManager
57
import android.os.Bundle
68
import androidx.activity.ComponentActivity
@@ -33,9 +35,18 @@ class MainActivity : ComponentActivity() {
3335
}
3436
}
3537

38+
private fun isChromeOS(): Boolean {
39+
return packageManager.hasSystemFeature("org.chromium.arc.device_management")
40+
}
41+
42+
@SuppressLint("SourceLockedOrientationActivity")
3643
override fun onCreate(savedInstanceState: Bundle?) {
3744
super.onCreate(savedInstanceState)
3845

46+
if (!isChromeOS()) {
47+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
48+
}
49+
3950
WindowCompat.setDecorFitsSystemWindows(window, false)
4051
window.statusBarColor = android.graphics.Color.TRANSPARENT
4152
window.navigationBarColor = android.graphics.Color.TRANSPARENT

app/src/main/java/co/stonephone/stonecamera/StoneCameraApp.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import co.stonephone.stonecamera.plugins.VideoModePlugin
4343
import co.stonephone.stonecamera.plugins.ZoomBarPlugin
4444
import co.stonephone.stonecamera.plugins.ZoomBasePlugin
4545
import co.stonephone.stonecamera.ui.RenderPluginSetting
46+
import co.stonephone.stonecamera.ui.ResponsiveOrientation
4647
import co.stonephone.stonecamera.ui.StoneCameraPreview
4748
import co.stonephone.stonecamera.utils.calculateImageCoverageRegion
4849
import co.stonephone.stonecamera.utils.getAllCamerasInfo
@@ -127,9 +128,11 @@ fun StoneCameraApp(
127128
) {
128129
stoneCameraViewModel.pluginSettings.filter { it.renderLocation == SettingLocation.TOP }
129130
.map { setting ->
130-
RenderPluginSetting(
131-
setting, stoneCameraViewModel, modifier = Modifier.padding(4.dp)
132-
)
131+
ResponsiveOrientation {
132+
RenderPluginSetting(
133+
setting, stoneCameraViewModel, modifier = Modifier.padding(4.dp)
134+
)
135+
}
133136
}
134137
}
135138

@@ -191,7 +194,7 @@ fun StoneCameraApp(
191194
})
192195
}
193196
}
194-
197+
195198
activeModePlugin?.renderModeControl?.invoke()
196199
}
197200
}

app/src/main/java/co/stonephone/stonecamera/plugins/PhotoMode.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier
2121
import androidx.compose.ui.graphics.Color
2222
import androidx.compose.ui.unit.dp
2323
import co.stonephone.stonecamera.StoneCameraViewModel
24+
import co.stonephone.stonecamera.ui.ResponsiveOrientation
2425

2526
class PhotoModePlugin : IPlugin {
2627
override val id: String = "photoMode"
@@ -75,20 +76,22 @@ class PhotoModePlugin : IPlugin {
7576
}) {}
7677
}
7778

78-
// Camera Switcher Button
79-
IconButton(
80-
onClick = { viewModel.toggleCameraFacing() },
81-
modifier = Modifier
82-
.size(48.dp)
83-
.padding(8.dp)
84-
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
85-
) {
86-
Icon(
87-
imageVector = Icons.Filled.FlipCameraAndroid, // Use FlipCameraAndroid if preferred
88-
contentDescription = "Flip Camera",
89-
tint = Color.White, // Customize the color if needed
90-
modifier = Modifier.fillMaxSize()
91-
)
79+
ResponsiveOrientation {
80+
// Camera Switcher Button
81+
IconButton(
82+
onClick = { viewModel.toggleCameraFacing() },
83+
modifier = Modifier
84+
.size(48.dp)
85+
.padding(8.dp)
86+
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
87+
) {
88+
Icon(
89+
imageVector = Icons.Filled.FlipCameraAndroid, // Use FlipCameraAndroid if preferred
90+
contentDescription = "Flip Camera",
91+
tint = Color.White, // Customize the color if needed
92+
modifier = Modifier.fillMaxSize()
93+
)
94+
}
9295
}
9396
}
9497
}

app/src/main/java/co/stonephone/stonecamera/plugins/QRScanner.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.compose.foundation.background
1919
import androidx.compose.foundation.clickable
2020
import androidx.compose.foundation.layout.Box
2121
import androidx.compose.foundation.layout.fillMaxWidth
22+
import androidx.compose.foundation.layout.offset
2223
import androidx.compose.foundation.layout.padding
2324
import androidx.compose.foundation.layout.widthIn
2425
import androidx.compose.foundation.shape.CircleShape
@@ -75,7 +76,8 @@ class QRScannerPlugin : IPlugin {
7576
return Box(
7677
Modifier
7778
.fillMaxWidth()
78-
.padding(vertical = 16.dp)
79+
// TODO move to a configurable model for plugin render location
80+
.offset(y = -48.dp)
7981
.onGloballyPositioned { layoutCoordinates ->
8082
width = layoutCoordinates.size.width.toFloat()
8183
}

app/src/main/java/co/stonephone/stonecamera/plugins/SettingsTray.kt

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.compose.ui.platform.LocalConfiguration
3434
import androidx.compose.ui.text.font.FontWeight
3535
import androidx.compose.ui.unit.dp
3636
import co.stonephone.stonecamera.StoneCameraViewModel
37+
import co.stonephone.stonecamera.ui.ResponsiveOrientation
3738
import kotlinx.coroutines.launch
3839

3940
class SettingsTrayPlugin : IPlugin {
@@ -141,23 +142,25 @@ class SettingsTrayPlugin : IPlugin {
141142
horizontalArrangement = Arrangement.End,
142143
verticalAlignment = Alignment.CenterVertically
143144
) {
144-
IconButton(
145-
onClick = {
146-
showSettingsTray = true
147-
},
148-
modifier = Modifier
149-
.size(36.dp)
150-
.background(
151-
Color.White.copy(alpha = 0.1f), CircleShape
145+
ResponsiveOrientation {
146+
IconButton(
147+
onClick = {
148+
showSettingsTray = true
149+
},
150+
modifier = Modifier
151+
.size(36.dp)
152+
.background(
153+
Color.White.copy(alpha = 0.1f), CircleShape
154+
)
155+
.padding(8.dp),
156+
) {
157+
Icon(
158+
imageVector = Icons.Default.Settings,
159+
contentDescription = "Settings Tray",
160+
tint = Color.White,
161+
modifier = Modifier.fillMaxSize()
152162
)
153-
.padding(8.dp),
154-
) {
155-
Icon(
156-
imageVector = Icons.Default.Settings,
157-
contentDescription = "Settings Tray",
158-
tint = Color.White,
159-
modifier = Modifier.fillMaxSize()
160-
)
163+
}
161164
}
162165
}
163166
}

app/src/main/java/co/stonephone/stonecamera/plugins/VideoMode.kt

Lines changed: 83 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.compose.ui.graphics.Color
2525
import androidx.compose.ui.graphics.RectangleShape
2626
import androidx.compose.ui.unit.dp
2727
import co.stonephone.stonecamera.StoneCameraViewModel
28+
import co.stonephone.stonecamera.ui.ResponsiveOrientation
2829

2930
class VideoModePlugin : IPlugin {
3031
override val id: String = "videoMode"
@@ -62,79 +63,85 @@ class VideoModePlugin : IPlugin {
6263
) {
6364
// Camera Switcher Button
6465
if (isRecording) {
65-
IconButton(
66-
onClick = {
66+
ResponsiveOrientation {
67+
IconButton(
68+
onClick = {
69+
if (isPaused) {
70+
viewModel.resumeRecording()
71+
} else {
72+
viewModel.pauseRecording()
73+
}
74+
},
75+
modifier = Modifier
76+
.size(48.dp)
77+
.padding(8.dp)
78+
.border(1.dp, Color.White, CircleShape)
79+
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
80+
) {
6781
if (isPaused) {
68-
viewModel.resumeRecording()
82+
Icon(
83+
imageVector = Icons.Filled.PlayArrow,
84+
contentDescription = "Resume Recording",
85+
tint = Color.White,
86+
modifier = Modifier.fillMaxSize()
87+
)
6988
} else {
70-
viewModel.pauseRecording()
89+
Icon(
90+
imageVector = Icons.Filled.Pause,
91+
contentDescription = "Pause Recording",
92+
tint = Color.White,
93+
modifier = Modifier.fillMaxSize()
94+
)
7195
}
72-
},
73-
modifier = Modifier
74-
.size(48.dp)
75-
.padding(8.dp)
76-
.border(1.dp, Color.White, CircleShape)
77-
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
78-
) {
79-
if (isPaused) {
80-
Icon(
81-
imageVector = Icons.Filled.PlayArrow,
82-
contentDescription = "Resume Recording",
83-
tint = Color.White,
84-
modifier = Modifier.fillMaxSize()
85-
)
86-
} else {
87-
Icon(
88-
imageVector = Icons.Filled.Pause,
89-
contentDescription = "Pause Recording",
90-
tint = Color.White,
91-
modifier = Modifier.fillMaxSize()
92-
)
9396
}
9497
}
9598
} else {
96-
Box(
97-
modifier = Modifier
98-
.size(48.dp)
99-
.background(Color.Transparent, shape = CircleShape)
100-
.clickable {
101-
viewModel.toggleCameraFacing()
102-
}, contentAlignment = Alignment.Center
103-
) {
99+
ResponsiveOrientation {
100+
Box(
101+
modifier = Modifier
102+
.size(48.dp)
103+
.background(Color.Transparent, shape = CircleShape)
104+
.clickable {
105+
viewModel.toggleCameraFacing()
106+
}, contentAlignment = Alignment.Center
107+
) {
104108

109+
}
105110
}
106111
}
107-
108-
Box(
109-
modifier = Modifier
110-
.size(60.dp)
111-
.border(1.dp, Color.White, CircleShape)
112-
.padding(4.dp), contentAlignment = Alignment.Center
113-
) {
114-
Box(contentAlignment = Alignment.Center, modifier = Modifier
115-
.background(
116-
Color.Red, shape = if (!isRecording) CircleShape else RectangleShape
117-
)
118-
.fillMaxSize(if (!isRecording) 1f else 0.5f)
119-
.clickable {
120-
if (!isRecording) {
121-
// Start recording
122-
viewModel.startRecording(
123-
viewModel.videoCapture
124-
) { uri ->
125-
Log.d(
126-
"StoneCameraApp", "Video saved to: $uri"
127-
)
112+
ResponsiveOrientation {
113+
Box(
114+
modifier = Modifier
115+
.size(60.dp)
116+
.border(1.dp, Color.White, CircleShape)
117+
.padding(4.dp), contentAlignment = Alignment.Center
118+
) {
119+
Box(contentAlignment = Alignment.Center, modifier = Modifier
120+
.background(
121+
Color.Red,
122+
shape = if (!isRecording) CircleShape else RectangleShape
123+
)
124+
.fillMaxSize(if (!isRecording) 1f else 0.5f)
125+
.clickable {
126+
if (!isRecording) {
127+
// Start recording
128+
viewModel.startRecording(
129+
viewModel.videoCapture
130+
) { uri ->
131+
Log.d(
132+
"StoneCameraApp", "Video saved to: $uri"
133+
)
134+
}
135+
} else {
136+
// Stop recording
137+
viewModel.stopRecording()
128138
}
129-
} else {
130-
// Stop recording
131-
viewModel.stopRecording()
132-
}
133139

134-
}
140+
}
135141

136142

137-
) {}
143+
) {}
144+
}
138145
}
139146

140147
if (isRecording) {
@@ -160,20 +167,22 @@ class VideoModePlugin : IPlugin {
160167
}) {}
161168
}
162169
} else {
163-
// Camera Switcher Button
164-
IconButton(
165-
onClick = { viewModel.toggleCameraFacing() },
166-
modifier = Modifier
167-
.size(48.dp)
168-
.padding(8.dp)
169-
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
170-
) {
171-
Icon(
172-
imageVector = Icons.Filled.FlipCameraAndroid, // Use FlipCameraAndroid if preferred
173-
contentDescription = "Flip Camera",
174-
tint = Color.White, // Customize the color if needed
175-
modifier = Modifier.fillMaxSize()
176-
)
170+
ResponsiveOrientation {
171+
// Camera Switcher Button
172+
IconButton(
173+
onClick = { viewModel.toggleCameraFacing() },
174+
modifier = Modifier
175+
.size(48.dp)
176+
.padding(8.dp)
177+
.background(Color.White.copy(alpha = 0.1f), shape = CircleShape)
178+
) {
179+
Icon(
180+
imageVector = Icons.Filled.FlipCameraAndroid, // Use FlipCameraAndroid if preferred
181+
contentDescription = "Flip Camera",
182+
tint = Color.White, // Customize the color if needed
183+
modifier = Modifier.fillMaxSize()
184+
)
185+
}
177186
}
178187
}
179188
}

0 commit comments

Comments
 (0)