From 9535ca8940ca94caae13662523086a2b4ed65074 Mon Sep 17 00:00:00 2001 From: Developer Chunk <90105266+developerchunk@users.noreply.github.com> Date: Mon, 20 Oct 2025 23:44:50 +0530 Subject: [PATCH] feat: Add tablet landscape orientation support (#490) - Tablets now support landscape mode, phones remain portrait-only - Add OrientationAwareActivity base class for orientation management - Add DeviceUtils.isTablet() for runtime device detection - Update MainActivity and GeohashPickerActivity to extend OrientationAwareActivity - Uses multiple detection criteria (screen size, density, configuration) Fixes #480 --- app/src/main/AndroidManifest.xml | 2 - .../java/com/bitchat/android/MainActivity.kt | 7 ++-- .../android/ui/GeohashPickerActivity.kt | 3 +- .../android/ui/OrientationAwareActivity.kt | 28 +++++++++++++ .../com/bitchat/android/utils/DeviceUtils.kt | 39 +++++++++++++++++++ 5 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/bitchat/android/ui/OrientationAwareActivity.kt create mode 100644 app/src/main/java/com/bitchat/android/utils/DeviceUtils.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 134dcdfa..8e953323 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -64,14 +64,12 @@ android:name=".ui.GeohashPickerActivity" android:exported="false" android:theme="@style/Theme.BitchatAndroid" - android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize" /> diff --git a/app/src/main/java/com/bitchat/android/MainActivity.kt b/app/src/main/java/com/bitchat/android/MainActivity.kt index 4900d2fb..28d67280 100644 --- a/app/src/main/java/com/bitchat/android/MainActivity.kt +++ b/app/src/main/java/com/bitchat/android/MainActivity.kt @@ -3,7 +3,6 @@ package com.bitchat.android import android.content.Intent import android.os.Bundle import android.util.Log -import androidx.activity.ComponentActivity import androidx.activity.OnBackPressedCallback import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -15,7 +14,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.dp import androidx.lifecycle.lifecycleScope import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.repeatOnLifecycle @@ -39,13 +37,14 @@ import com.bitchat.android.onboarding.PermissionExplanationScreen import com.bitchat.android.onboarding.PermissionManager import com.bitchat.android.ui.ChatScreen import com.bitchat.android.ui.ChatViewModel +import com.bitchat.android.ui.OrientationAwareActivity import com.bitchat.android.ui.theme.BitchatTheme import com.bitchat.android.nostr.PoWPreferenceManager import kotlinx.coroutines.delay import kotlinx.coroutines.launch -class MainActivity : ComponentActivity() { - +class MainActivity : OrientationAwareActivity() { + private lateinit var permissionManager: PermissionManager private lateinit var onboardingCoordinator: OnboardingCoordinator private lateinit var bluetoothStatusManager: BluetoothStatusManager diff --git a/app/src/main/java/com/bitchat/android/ui/GeohashPickerActivity.kt b/app/src/main/java/com/bitchat/android/ui/GeohashPickerActivity.kt index d0971aad..b69926d0 100644 --- a/app/src/main/java/com/bitchat/android/ui/GeohashPickerActivity.kt +++ b/app/src/main/java/com/bitchat/android/ui/GeohashPickerActivity.kt @@ -11,7 +11,6 @@ import android.webkit.WebChromeClient import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient -import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape @@ -45,7 +44,7 @@ import com.bitchat.android.geohash.LocationChannelManager import com.bitchat.android.ui.theme.BASE_FONT_SIZE @OptIn(ExperimentalMaterial3Api::class) -class GeohashPickerActivity : ComponentActivity() { +class GeohashPickerActivity : OrientationAwareActivity() { companion object { const val EXTRA_INITIAL_GEOHASH = "initial_geohash" diff --git a/app/src/main/java/com/bitchat/android/ui/OrientationAwareActivity.kt b/app/src/main/java/com/bitchat/android/ui/OrientationAwareActivity.kt new file mode 100644 index 00000000..82d8feaa --- /dev/null +++ b/app/src/main/java/com/bitchat/android/ui/OrientationAwareActivity.kt @@ -0,0 +1,28 @@ +package com.bitchat.android.ui + +import android.content.pm.ActivityInfo +import android.os.Bundle +import androidx.activity.ComponentActivity +import com.bitchat.android.utils.DeviceUtils + +/** + * Base activity that automatically sets orientation based on device type. + * Tablets can rotate to landscape, phones are locked to portrait. + */ +abstract class OrientationAwareActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setOrientationBasedOnDeviceType() + } + + private fun setOrientationBasedOnDeviceType() { + requestedOrientation = if (DeviceUtils.isTablet(this)) { + // Allow all orientations on tablets + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + } else { + // Lock to portrait on phones + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + } + } +} diff --git a/app/src/main/java/com/bitchat/android/utils/DeviceUtils.kt b/app/src/main/java/com/bitchat/android/utils/DeviceUtils.kt new file mode 100644 index 00000000..c4054a70 --- /dev/null +++ b/app/src/main/java/com/bitchat/android/utils/DeviceUtils.kt @@ -0,0 +1,39 @@ +package com.bitchat.android.utils + +import android.content.Context +import android.content.res.Configuration +import android.util.DisplayMetrics +import android.view.WindowManager +import androidx.core.content.getSystemService +import kotlin.math.sqrt + +object DeviceUtils { + + /** + * Determines if the current device is a tablet based on screen size and density. + * Uses multiple criteria to accurately detect tablets vs phones. + */ + fun isTablet(context: Context): Boolean { + val windowManager = context.getSystemService() + val displayMetrics = DisplayMetrics() + windowManager?.defaultDisplay?.getMetrics(displayMetrics) + + // Calculate screen size in inches + val widthInches = displayMetrics.widthPixels / displayMetrics.xdpi + val heightInches = displayMetrics.heightPixels / displayMetrics.ydpi + val diagonalInches = sqrt((widthInches * widthInches) + (heightInches * heightInches)) + + // Check if device has tablet configuration + val configuration = context.resources.configuration + val isLargeScreen = (configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE + val isXLargeScreen = (configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE + + // A device is considered a tablet if: + // 1. Screen diagonal is 7 inches or larger, OR + // 2. Configuration indicates large or xlarge screen, OR + // 3. Smallest width is 600dp or more (sw600dp) + val smallestWidthDp = context.resources.configuration.smallestScreenWidthDp + + return diagonalInches >= 7.0 || isLargeScreen || isXLargeScreen || smallestWidthDp >= 600 + } +}