Compare commits
	
		
			5 Commits
		
	
	
		
			3.1.0+122
			...
			b2c5d64fc5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b2c5d64fc5 | |||
|  | 5371637b16 | ||
| c5cbf0af37 | |||
| 1a31e22450 | |||
|  | 49db54529d | 
| @@ -51,6 +51,12 @@ android { | ||||
|     buildTypes { | ||||
|         release { | ||||
|             signingConfig = signingConfigs.getByName("release") | ||||
|  | ||||
|             isMinifyEnabled = true | ||||
|             proguardFiles( | ||||
|                 getDefaultProguardFile("proguard-android-optimize.txt"), | ||||
|                 "proguard-rules.pro" | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -58,7 +64,7 @@ android { | ||||
| dependencies { | ||||
|     implementation("com.google.android.material:material:1.12.0") | ||||
|     implementation("com.github.bumptech.glide:glide:4.16.0") | ||||
|     implementation("com.squareup.okhttp3:okhttp:4.12.0") | ||||
|     implementation("com.squareup.okhttp3:okhttp:5.1.0") | ||||
| } | ||||
|  | ||||
| flutter { | ||||
|   | ||||
							
								
								
									
										5
									
								
								android/app/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								android/app/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # JNI Zero initialization (required for WebRTC native method registration) | ||||
| -keep class livekit.org.jni_zero.JniInit { | ||||
|     # Keep the init method un-obfuscated for native code callback | ||||
|     private static java.lang.Object[] init(); | ||||
| } | ||||
| @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip | ||||
|   | ||||
| @@ -18,11 +18,11 @@ pluginManagement { | ||||
|  | ||||
| plugins { | ||||
|     id("dev.flutter.flutter-plugin-loader") version "1.0.0" | ||||
|     id("com.android.application") version "8.10.1" apply false | ||||
|     id("com.android.application") version "8.12.0" apply false | ||||
|     // START: FlutterFire Configuration | ||||
|     id("com.google.gms.google-services") version("4.3.15") apply false | ||||
|     // END: FlutterFire Configuration | ||||
|     id("org.jetbrains.kotlin.android") version "1.8.22" apply false | ||||
|     id("org.jetbrains.kotlin.android") version("2.2.0") apply false | ||||
| } | ||||
|  | ||||
| include(":app") | ||||
|   | ||||
| @@ -28,6 +28,7 @@ import 'package:relative_time/relative_time.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; | ||||
| import 'package:flutter_native_splash/flutter_native_splash.dart'; | ||||
| import 'package:island/widgets/keyboard_navigation.dart'; | ||||
| import 'package:url_launcher/url_launcher_string.dart'; | ||||
| import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect; | ||||
|  | ||||
| @@ -244,7 +245,8 @@ class IslandApp extends HookConsumerWidget { | ||||
|  | ||||
|     final router = ref.watch(routerProvider); | ||||
|  | ||||
|     return MaterialApp.router( | ||||
|     return KeyboardNavigation( | ||||
|       child: MaterialApp.router( | ||||
|         theme: theme?.light, | ||||
|         darkTheme: theme?.dark, | ||||
|         themeMode: ThemeMode.system, | ||||
| @@ -268,6 +270,7 @@ class IslandApp extends HookConsumerWidget { | ||||
|             ], | ||||
|           ); | ||||
|         }, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -31,7 +31,7 @@ class StickersScreen extends HookConsumerWidget { | ||||
|               context | ||||
|                   .pushNamed( | ||||
|                     'creatorStickerPackNew', | ||||
|                     queryParameters: {'name': pubName}, | ||||
|                     pathParameters: {'name': pubName}, | ||||
|                   ) | ||||
|                   .then((value) { | ||||
|                     if (value != null) { | ||||
| @@ -187,10 +187,8 @@ class EditStickerPacksScreen extends HookConsumerWidget { | ||||
|             'description': descriptionController.text, | ||||
|             'prefix': prefixController.text, | ||||
|           }, | ||||
|           options: Options( | ||||
|             method: packId == null ? 'POST' : 'PATCH', | ||||
|             headers: {'X-Pub': pubName}, | ||||
|           ), | ||||
|           queryParameters: {'pub': pubName}, | ||||
|           options: Options(method: packId == null ? 'POST' : 'PATCH'), | ||||
|         ); | ||||
|         if (!context.mounted) return; | ||||
|         context.pop(SnStickerPack.fromJson(resp.data)); | ||||
|   | ||||
| @@ -67,6 +67,9 @@ Future<void> subscribePushNotification( | ||||
|   Dio apiClient, { | ||||
|   bool detailedErrors = false, | ||||
| }) async { | ||||
|   if (Platform.isLinux){ | ||||
|     return; | ||||
|   } | ||||
|   await FirebaseMessaging.instance.requestPermission( | ||||
|     alert: true, | ||||
|     badge: true, | ||||
|   | ||||
							
								
								
									
										86
									
								
								lib/widgets/keyboard_navigation.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								lib/widgets/keyboard_navigation.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
|  | ||||
| enum VimMode { normal, insert } | ||||
|  | ||||
| class KeyboardNavigation extends StatefulWidget { | ||||
|   const KeyboardNavigation({super.key, required this.child}); | ||||
|  | ||||
|   final Widget child; | ||||
|  | ||||
|   @override | ||||
|   State<KeyboardNavigation> createState() => _KeyboardNavigationState(); | ||||
| } | ||||
|  | ||||
| class _KeyboardNavigationState extends State<KeyboardNavigation> { | ||||
|   VimMode _mode = VimMode.normal; | ||||
|   final FocusScopeNode _focusScopeNode = FocusScopeNode(); | ||||
|  | ||||
|   @override | ||||
|   void dispose() { | ||||
|     _focusScopeNode.dispose(); | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
|   KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) { | ||||
|     if (event is! KeyDownEvent && event is! KeyRepeatEvent) { | ||||
|       return KeyEventResult.ignored; | ||||
|     } | ||||
|  | ||||
|     if (_mode == VimMode.normal) { | ||||
|       if (event.logicalKey == LogicalKeyboardKey.keyJ) { | ||||
|         node.focusInDirection(TraversalDirection.down); | ||||
|         return KeyEventResult.handled; | ||||
|       } else if (event.logicalKey == LogicalKeyboardKey.keyK) { | ||||
|         node.focusInDirection(TraversalDirection.up); | ||||
|         return KeyEventResult.handled; | ||||
|       } else if (event.logicalKey == LogicalKeyboardKey.keyH) { | ||||
|         final focusNode = FocusManager.instance.primaryFocus; | ||||
|         if (focusNode != null) { | ||||
|           final scrollable = Scrollable.of(focusNode.context!); | ||||
|           if (scrollable.position.axis == Axis.horizontal) { | ||||
|             scrollable.position.moveTo(scrollable.position.pixels - 50); | ||||
|             return KeyEventResult.handled; | ||||
|           } | ||||
|         } | ||||
|         node.focusInDirection(TraversalDirection.left); | ||||
|         return KeyEventResult.handled; | ||||
|       } else if (event.logicalKey == LogicalKeyboardKey.keyL) { | ||||
|         final focusNode = FocusManager.instance.primaryFocus; | ||||
|         if (focusNode != null) { | ||||
|           final scrollable = Scrollable.of(focusNode.context!); | ||||
|           if (scrollable.position.axis == Axis.horizontal) { | ||||
|             scrollable.position.moveTo(scrollable.position.pixels + 50); | ||||
|             return KeyEventResult.handled; | ||||
|           } | ||||
|         } | ||||
|         node.focusInDirection(TraversalDirection.right); | ||||
|         return KeyEventResult.handled; | ||||
|       } else if (event.logicalKey == LogicalKeyboardKey.keyI) { | ||||
|         setState(() { | ||||
|           _mode = VimMode.insert; | ||||
|         }); | ||||
|         return KeyEventResult.handled; | ||||
|       } | ||||
|     } else if (_mode == VimMode.insert) { | ||||
|       if (event.logicalKey == LogicalKeyboardKey.escape) { | ||||
|         setState(() { | ||||
|           _mode = VimMode.normal; | ||||
|         }); | ||||
|         // Unfocus the current widget to prevent typing | ||||
|         node.unfocus(); | ||||
|         return KeyEventResult.handled; | ||||
|       } | ||||
|     } | ||||
|     return KeyEventResult.ignored; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Focus( | ||||
|       focusNode: _focusScopeNode, | ||||
|       onKeyEvent: _handleKeyEvent, | ||||
|       child: widget.child, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user