[SwitchListTile] adds controlAffinity property (#58037)

diff --git a/AUTHORS b/AUTHORS
index a2cc16a..0e911ef 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -56,3 +56,4 @@
 Katarina Sheremet <katarina@sheremet.ch>
 Nicolas Schneider <nioncode+git@gmail.com>
 Mikhail Zotyev <mbixjkee1392@gmail.com>
+Ayush Bherwani <ayush.bherwani1998@gmail.com>
diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart
index 8be220e..a423a16 100644
--- a/packages/flutter/lib/src/material/list_tile.dart
+++ b/packages/flutter/lib/src/material/list_tile.dart
@@ -148,6 +148,7 @@
 ///
 ///  * [CheckboxListTile], which combines a [ListTile] with a [Checkbox].
 ///  * [RadioListTile], which combines a [ListTile] with a [Radio] button.
+///  * [SwitchListTile], which combines a [ListTile] with a [Switch].
 enum ListTileControlAffinity {
   /// Position the control on the leading edge, and the secondary widget, if
   /// any, on the trailing edge.
diff --git a/packages/flutter/lib/src/material/switch_list_tile.dart b/packages/flutter/lib/src/material/switch_list_tile.dart
index 62fae85..cf14d89 100644
--- a/packages/flutter/lib/src/material/switch_list_tile.dart
+++ b/packages/flutter/lib/src/material/switch_list_tile.dart
@@ -39,9 +39,8 @@
 /// appear selected when the switch is on, pass the same value to both.
 ///
 /// The switch is shown on the right by default in left-to-right languages (i.e.
-/// in the [ListTile.trailing] slot). The [secondary] widget is placed in the
-/// [ListTile.leading] slot. This cannot be changed; there is not sufficient
-/// space in a [ListTile]'s [ListTile.leading] slot for a [Switch].
+/// in the [ListTile.trailing] slot) which can be changed using [controlAffinity].
+/// The [secondary] widget is placed in the [ListTile.leading] slot.
 ///
 /// To show the [SwitchListTile] as disabled, pass null as the [onChanged]
 /// callback.
@@ -273,6 +272,7 @@
     this.secondary,
     this.selected = false,
     this.autofocus = false,
+    this.controlAffinity = ListTileControlAffinity.platform,
   }) : _switchListTileType = _SwitchListTileType.material,
        assert(value != null),
        assert(isThreeLine != null),
@@ -307,6 +307,7 @@
     this.secondary,
     this.selected = false,
     this.autofocus = false,
+    this.controlAffinity = ListTileControlAffinity.platform,
   }) : _switchListTileType = _SwitchListTileType.adaptive,
        assert(value != null),
        assert(isThreeLine != null),
@@ -429,6 +430,11 @@
   /// If adaptive, creates the switch with [Switch.adaptive].
   final _SwitchListTileType _switchListTileType;
 
+  /// Defines the position of control and [secondary], relative to text.
+  ///
+  /// By default, the value of `controlAffinity` is [ListTileControlAffinity.platform].
+  final ListTileControlAffinity controlAffinity;
+
   @override
   Widget build(BuildContext context) {
     Widget control;
@@ -462,14 +468,28 @@
           autofocus: autofocus,
         );
     }
+
+    Widget leading, trailing;
+    switch (controlAffinity) {
+      case ListTileControlAffinity.leading:
+        leading = control;
+        trailing = secondary;
+        break;
+      case ListTileControlAffinity.trailing:
+      case ListTileControlAffinity.platform:
+        leading = secondary;
+        trailing = control;
+        break;
+    }
+
     return MergeSemantics(
       child: ListTileTheme.merge(
         selectedColor: activeColor ?? Theme.of(context).accentColor,
         child: ListTile(
-          leading: secondary,
+          leading: leading,
           title: title,
           subtitle: subtitle,
-          trailing: control,
+          trailing: trailing,
           isThreeLine: isThreeLine,
           dense: dense,
           contentPadding: contentPadding,
diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart
index a4ad456..a6bd56a 100644
--- a/packages/flutter/test/material/switch_list_tile_test.dart
+++ b/packages/flutter/test/material/switch_list_tile_test.dart
@@ -298,4 +298,44 @@
     await tester.pump();
     expect(Focus.of(childKey.currentContext, nullOk: true).hasPrimaryFocus, isFalse);
   });
+
+  testWidgets('SwitchListTile controlAffinity test', (WidgetTester tester) async {
+    await tester.pumpWidget(const MaterialApp(
+      home: Material(
+        child: SwitchListTile(
+          value: true,
+          onChanged: null,
+          secondary: Icon(Icons.info),
+          title: Text('Title'),
+          controlAffinity: ListTileControlAffinity.leading,
+        ),
+      ),
+    ));
+
+    final ListTile listTile = tester.widget(find.byType(ListTile));
+    // When controlAffinity is ListTileControlAffinity.leading, the position of
+    // Switch is at leading edge and SwitchListTile.secondary at trailing edge.
+    expect(listTile.leading.runtimeType, Switch);
+    expect(listTile.trailing.runtimeType, Icon);
+  });
+
+  testWidgets('SwitchListTile controlAffinity default value test', (WidgetTester tester) async {
+    await tester.pumpWidget(const MaterialApp(
+      home: Material(
+        child: SwitchListTile(
+          value: true,
+          onChanged: null,
+          secondary: Icon(Icons.info),
+          title: Text('Title'),
+        ),
+      ),
+    ));
+
+    final ListTile listTile = tester.widget(find.byType(ListTile));
+    // By default, value of controlAffinity is ListTileControlAffinity.platform,
+    // where the position of SwitchListTile.secondary is at leading edge and Switch
+    // at trailing edge. This also covers test for ListTileControlAffinity.trailing.
+    expect(listTile.leading.runtimeType, Icon);
+    expect(listTile.trailing.runtimeType, Switch);
+  });
 }