Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OpenTalkie/AppShell.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ public AppShell(IPlatformCapabilitiesService platformCapabilitiesService)
Routing.RegisterRoute("PlaybackSettingsPage", typeof(PlaybackSettingsPage));
Routing.RegisterRoute("ReceiverSettingsPage", typeof(ReceiverSettingsPage));
Routing.RegisterRoute("AudioManagerSettingsPage", typeof(AudioManagerSettingsPage));
Routing.RegisterRoute("GeneralSettingsPage", typeof(GeneralSettingsPage));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static IServiceCollection AddPresentationCoreLayer(this IServiceCollectio
services.AddTransient<SettingsViewModel>();
services.AddTransient<AddStreamViewModel>();
services.AddTransient<AudioManagerSettingsViewModel>();
services.AddTransient<GeneralSettingsViewModel>();

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static IServiceCollection AddPresentationLayer(this IServiceCollection se
services.AddTransient<AudioManagerSettingsPage>();
services.AddTransient<SettingsPage>();
services.AddTransient<AddStreamPage>();
services.AddTransient<GeneralSettingsPage>();

return services;
}
Expand Down
8 changes: 8 additions & 0 deletions OpenTalkie/OpenTalkie.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="10.0.50" />
</ItemGroup>
<ItemGroup>
<Compile Update="Views\GeneralSettingsPage.xaml.cs">
<DependentUpon>GeneralSettingsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Views\HomePage.xaml.cs">
<DependentUpon>HomePage.xaml</DependentUpon>
</Compile>
Expand All @@ -97,4 +100,9 @@
<ProjectReference Include="..\OpenTalkie.Infrastructure\OpenTalkie.Infrastructure.csproj" />
<ProjectReference Include="..\OpenTalkie.Infrastructure.Android\OpenTalkie.Infrastructure.Android.csproj" />
</ItemGroup>
<ItemGroup>
<MauiXaml Update="Views\GeneralSettingsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
</Project>
19 changes: 19 additions & 0 deletions OpenTalkie/Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Views;

namespace OpenTalkie.Platforms.Android;

Expand All @@ -12,13 +13,31 @@ public class MainActivity : MauiAppCompatActivity
{
public static MainActivity? Instance { get; private set; }

// Instantiate swipe detector
private SwipeNavigationDetector _swipeDetector = null!;


protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
Instance = this;

_swipeDetector = new SwipeNavigationDetector();
}

// Intercept touch data at the root window level
public override bool DispatchTouchEvent(MotionEvent? ev)
{
// Hand the touch data off to our helper file.
// If it returns true, it means a swipe happened and we swallow it.
if (_swipeDetector != null && _swipeDetector.HandleTouchEvent(ev))
{
return true;
}

// Otherwise, let normal clicks and scrolls pass through to MAUI untouched
return base.DispatchTouchEvent(ev);
}

protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
{
Expand Down
85 changes: 85 additions & 0 deletions OpenTalkie/Platforms/Android/SwipeNavigation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Android.Views;
using Microsoft.Maui.Storage;
using OpenTalkie.Presentation.ViewModels;

namespace OpenTalkie.Platforms.Android;

public class SwipeNavigationDetector
{
private const int SwipeThreshold = 80;
private float _startX;
private float _startY;

// Processes incoming window touches to check for swipe gestures.
public bool HandleTouchEvent(MotionEvent? ev)
{
// Check enabled state by referencing GeneralSettingsViewModel directly
bool isEnabled = Preferences.Default.Get(
GeneralSettingsViewModel.SwipeNavPreferenceKey,
GeneralSettingsViewModel.DefaultSwipeNavEnabled
);

if (!isEnabled)
{
return false;
}

if (ev is null) return false;

switch (ev.Action)
{
case MotionEventActions.Down:
_startX = ev.RawX;
_startY = ev.RawY;
break;

case MotionEventActions.Up:
var deltaX = ev.RawX - _startX;
var deltaY = ev.RawY - _startY;

// Ensure horizontal movement is greater than the threshold and flatter than a vertical scroll
if (Math.Abs(deltaX) > SwipeThreshold && Math.Abs(deltaX) > Math.Abs(deltaY) * 1.2f)
{
// Run on main thread to safely update UI navigation
MainThread.BeginInvokeOnMainThread(() => TriggerTabNavigation(deltaX < 0 ? 1 : -1));
return true;
}
break;
}

return false;
}


// Calculates current shell tab index dynamically and shifts navigation.
// Works perfectly on root pages and sub-pages alike.
private void TriggerTabNavigation(int direction)
{
var shell = Shell.Current;
if (shell is null) return;

// Optional UX Guardrail: Uncomment the line below if you don't want
// swiping to switch tabs when a sub-page has a "Go Back" backstack arrow.
// if (shell.Navigation.NavigationStack.Count > 1) return;

var tabBar = shell.CurrentItem;
if (tabBar is null) return;

var currentTab = tabBar.CurrentItem;
if (currentTab is null) return;

// Fetch only visible tabs to handle hidden or dynamic items properly
var visibleTabs = tabBar.Items.Where(t => t.IsVisible).ToList();
int currentIndex = visibleTabs.IndexOf(currentTab);

if (currentIndex < 0) return;

int nextIndex = currentIndex + direction;

// Execute the tab shift if within layout boundaries
if (nextIndex >= 0 && nextIndex < visibleTabs.Count)
{
tabBar.CurrentItem = visibleTabs[nextIndex];
}
}
}
25 changes: 25 additions & 0 deletions OpenTalkie/ViewModels/GeneralSettingsViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Maui.Storage;

namespace OpenTalkie.Presentation.ViewModels;

public partial class GeneralSettingsViewModel : ObservableObject
{
// Single Source of Truth for both files
public const string SwipeNavPreferenceKey = "SwipeNavigationEnabled";
public const bool DefaultSwipeNavEnabled = true;

[ObservableProperty]
private bool _isSwipingEnabled;

public GeneralSettingsViewModel()
{
// Read using internal public constants
_isSwipingEnabled = Preferences.Default.Get(SwipeNavPreferenceKey, DefaultSwipeNavEnabled);
}

partial void OnIsSwipingEnabledChanged(bool value)
{
Preferences.Default.Set(SwipeNavPreferenceKey, value);
}
}
1 change: 1 addition & 0 deletions OpenTalkie/ViewModels/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public SettingsViewModel(INavigationService navigationService, IPlatformCapabili
SettingsItems.Add(new SettingsItem { Name = "Cast Settings", Route = "PlaybackSettingsPage" });

SettingsItems.Add(new SettingsItem { Name = "Audio Manager Settings", Route = "AudioManagerSettingsPage" });
SettingsItems.Add(new SettingsItem { Name = "General Settings", Route = "GeneralSettingsPage" });
}

[RelayCommand]
Expand Down
43 changes: 43 additions & 0 deletions OpenTalkie/Views/GeneralSettingsPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="OpenTalkie.Presentation.Views.GeneralSettingsPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodel="clr-namespace:OpenTalkie.Presentation.ViewModels"
Title="General settings"
x:DataType="viewmodel:GeneralSettingsViewModel"
Padding="16">
<ScrollView VerticalScrollBarVisibility="Never" HorizontalScrollBarVisibility="Never">
<Grid RowDefinitions="Auto" RowSpacing="16">

<Border
Grid.Row="6"
Padding="16"
BackgroundColor="{AppThemeBinding Light={StaticResource SurfaceContainerLowLight}, Dark={StaticResource SurfaceContainerLowDark}}"
Stroke="{AppThemeBinding Light={StaticResource OutlineLight}, Dark={StaticResource OutlineDark}}"
StrokeShape="RoundRectangle 8"
Shadow="{StaticResource MaterialShadowLevel1}">
<Grid Padding="5" ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto" RowSpacing="4">
<Label
Grid.Row="0"
FontAttributes="Bold"
FontSize="16"
Text="Swipe Navigation"
TextColor="{AppThemeBinding Light={StaticResource OnSurfaceLight}, Dark={StaticResource OnSurfaceDark}}" />
<Label
Grid.Row="1"
FontSize="14"
Text="Swipe horizontally on screen to switch tabs."
TextColor="{AppThemeBinding Light={StaticResource OnSurfaceVariantLight}, Dark={StaticResource OnSurfaceVariantDark}}" />
<Switch
Grid.RowSpan="2"
Grid.Column="1"
IsToggled="{Binding IsSwipingEnabled, Mode=TwoWay}"
VerticalOptions="Center">
</Switch>
</Grid>
</Border>

</Grid>
</ScrollView>
</ContentPage>
12 changes: 12 additions & 0 deletions OpenTalkie/Views/GeneralSettingsPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using OpenTalkie.Presentation.ViewModels;

namespace OpenTalkie.Presentation.Views;

public partial class GeneralSettingsPage : ContentPage
{
public GeneralSettingsPage(GeneralSettingsViewModel viewModel)
{
BindingContext = viewModel;
InitializeComponent();
}
}