Skip to content

feat: implement app lock feature with biometric authentication and PIN setup#23

Open
shreyaspapi wants to merge 3 commits into
cogwheel0:mainfrom
shreyaspapi:main
Open

feat: implement app lock feature with biometric authentication and PIN setup#23
shreyaspapi wants to merge 3 commits into
cogwheel0:mainfrom
shreyaspapi:main

Conversation

@shreyaspapi

@shreyaspapi shreyaspapi commented Aug 2, 2025

Copy link
Copy Markdown

fixes #15

Summary by CodeRabbit

  • New Features

    • Introduced App Lock Security with PIN code and biometric authentication (fingerprint/Face ID) to protect access to the app.
    • Users can set, change, and confirm a 4-digit PIN, enable/disable biometrics, and configure lock timeout intervals.
    • App automatically locks on timeout or when switching apps; unlocking requires PIN or biometrics.
    • Added dedicated screens for app lock and PIN setup, accessible via Settings.
  • Improvements

    • Updated Settings to include App Lock controls and biometric options.
    • Enhanced splash and login flows to respect app lock status.
    • Expanded documentation to describe new security features.
  • Platform Support

    • Added necessary Android permissions and iOS usage descriptions for biometric authentication.
  • Dependencies

    • Added biometric authentication support via new dependency.

@coderabbitai

coderabbitai Bot commented Aug 2, 2025

Copy link
Copy Markdown

Walkthrough

App lock security functionality was introduced across the project, enabling PIN and biometric authentication for accessing the app. This involved adding new screens for lock and PIN setup, updating app lifecycle and navigation logic, creating an AppLockService, modifying platform configuration for biometrics, updating dependencies, and documenting the feature in the README.

Changes

Cohort / File(s) Change Summary
App Lock Core Service
lib/services/app_lock_service.dart
Introduced AppLockService to manage app lock state, PIN and biometric setup, verification, lock/unlock logic, and secure storage.
App Lock Screens
lib/screens/app_lock_screen.dart, lib/screens/pin_setup_screen.dart
Added new screens for unlocking the app via PIN/biometrics and for setting up a PIN code. These manage user input, validation, error handling, and UI for app lock flows.
App Lifecycle & Routing
lib/main.dart, lib/screens/splash_screen.dart, lib/screens/login_screen.dart
Updated main app and splash screen to check and enforce app lock state on resume and startup; adjusted routing to support new app lock screens. Login screen navigation updated to use new main route.
Settings Integration
lib/screens/settings_screen.dart
Refactored settings screen to stateful, integrating app lock controls: enable/disable, PIN management, biometric toggle, lock timeout, and test lock.
Platform Configuration
android/app/src/main/AndroidManifest.xml, ios/Runner/Info.plist
Added required permissions and descriptions for biometric authentication on Android and iOS.
Build & Dependency Updates
android/app/build.gradle.kts, pubspec.yaml
Updated build scripts for conditional signing config; added local_auth dependency for biometric support.
Documentation
README.md
Updated documentation to describe the new App Lock Security feature, its capabilities, and integration in security/privacy.
PIN UI Components
lib/widgets/pin_ui_components.dart
Added reusable widgets for PIN input UI, including digit indicators and numeric/action buttons with theming and state support.
Service Factory Update
lib/services/service_factory.dart
Extended ServiceFactory interface and implementations to provide AppLockService instances.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App (UI)
    participant AppLockService
    participant SecureStorage
    participant BiometricAPI

    User->>App (UI): Launches app
    App (UI)->>AppLockService: initialize()
    AppLockService->>SecureStorage: Load lock settings & PIN
    AppLockService-->>App (UI): Return lock state

    alt App lock enabled and locked
        App (UI)->>User: Show AppLockScreen
        User->>App (UI): Enter PIN or tap biometric
        alt Biometric auth
            App (UI)->>AppLockService: authenticateWithBiometrics()
            AppLockService->>BiometricAPI: Prompt biometric
            BiometricAPI-->>AppLockService: Success/Failure
        else PIN entry
            App (UI)->>AppLockService: verifyPinCode(pin)
            AppLockService->>SecureStorage: Compare PIN
            SecureStorage-->>AppLockService: Result
        end
        AppLockService-->>App (UI): Unlock or error
        App (UI)->>User: Navigate to main screen or show error
    else App lock not enabled or already unlocked
        App (UI)->>User: Navigate to main screen
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐇✨
A hop and a skip, now the app’s under lock,
With PINs and with biometrics, no need for a rock!
Settings are richer, the splash now aware,
Secure as a burrow, with features to spare.
The README’s been polished, dependencies in tow—
This rabbit’s app fortress is ready to go!
🥕🔒

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1541d04 and 231ae71.

📒 Files selected for processing (3)
  • lib/screens/app_lock_screen.dart (1 hunks)
  • lib/screens/pin_setup_screen.dart (1 hunks)
  • lib/services/service_factory.dart (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • lib/services/service_factory.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/screens/pin_setup_screen.dart
  • lib/screens/app_lock_screen.dart
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (9)
android/app/src/main/AndroidManifest.xml (1)

3-4: Add maxSdkVersion to fingerprint permission to silence deprecation lint

android.permission.USE_FINGERPRINT is deprecated from API 28 onward. Keeping it for ≤ 28 devices is fine, but add android:maxSdkVersion="28" so newer builds don’t flag it.

-    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+    <uses-permission
+        android:name="android.permission.USE_FINGERPRINT"
+        android:maxSdkVersion="28"/>
lib/screens/login_screen.dart (1)

50-54: Avoid hard-coded route strings – centralise to reduce drift

'/main' is now repeated four times. Declare a const (e.g. AppRoutes.main) and reuse it so future route renames touch only one place.

-      unawaited(Navigator.of(context).pushReplacementNamed('/main'));
+      unawaited(Navigator.of(context).pushReplacementNamed(AppRoutes.main));

Same change applies to the other three occurrences.

Also applies to: 138-142, 156-162, 184-188

android/app/build.gradle.kts (1)

44-68: Minor duplication – lift the keystore check into a val

The identical 5-line condition appears twice. Compute it once to keep the block concise:

+val hasSigningProps =
+    keystorePropertiesFile.exists() &&
+    listOf("storeFile","storePassword","keyAlias","keyPassword")
+        .all { keystoreProperties[it] != null }
+
 signingConfigs {
     create("release") {
-        // Only configure signing if key.properties file exists and has required properties
-        if (keystorePropertiesFile.exists() &&
-            keystoreProperties["storeFile"] != null &&
-            keystoreProperties["storePassword"] != null &&
-            keystoreProperties["keyAlias"] != null &&
-            keystoreProperties["keyPassword"] != null) {
+        if (hasSigningProps) {
             …
         }
     }
 }
 …
 getByName("release") {
-        // Only set signing config if it's properly configured
-        if (keystorePropertiesFile.exists() &&
-            keystoreProperties["storeFile"] != null &&
-            keystoreProperties["storePassword"] != null &&
-            keystoreProperties["keyAlias"] != null &&
-            keystoreProperties["keyPassword"] != null) {
+        if (hasSigningProps) {
             signingConfig = signingConfigs.getByName("release")
         }

Pure nit, but keeps the build script tidy.

lib/screens/splash_screen.dart (1)

40-55: Consider reusing AppLockService instance for better performance

The current implementation creates a new AppLockService instance and initializes it on every splash screen load. Consider caching the initialized service or using a singleton pattern to avoid redundant initialization calls.

-    // Check app lock status
-    final appLockService = AppLockService();
-    await appLockService.initialize();
+    // Check app lock status
+    final appLockService = AppLockService();
+    if (!appLockService.isInitialized) {
+      await appLockService.initialize();
+    }
lib/screens/app_lock_screen.dart (2)

54-65: Consider adding haptic feedback for better UX

The PIN digit input logic is solid with proper length validation and error state clearing. Consider adding haptic feedback when digits are entered to improve the user experience.

+import 'package:flutter/services.dart';

  void _onPinDigitPressed(String digit) {
    if (_enteredPin.length < 4) {
+     HapticFeedback.lightImpact();
      setState(() {
        _enteredPin.add(digit);
        _showError = false;
      });

109-120: Consider making PIN dot size responsive

The PIN digit visualization is clean and functional. Consider making the dot size responsive to different screen sizes for better accessibility.

  Widget _buildPinDigit({bool isFilled = false}) {
+   final screenWidth = MediaQuery.of(context).size.width;
+   final dotSize = screenWidth > 400 ? 24.0 : 20.0;
+   
    return Container(
-     width: 20,
-     height: 20,
+     width: dotSize,
+     height: dotSize,
lib/main.dart (1)

66-77: Consider adding error handling for app lock service failures

The _checkAppLock method assumes the AppLockService is always available and functional. Consider adding error handling for cases where the service might fail or be unavailable.

  Future<void> _checkAppLock() async {
-   if (_isAppLockEnabled) {
+   if (_isAppLockEnabled && _appLockService != null) {
-     _appLockService.onAppResumed();
-     
-     if (_appLockService.isLocked) {
-       // Navigate to app lock screen
-       if (mounted) {
-         Navigator.of(context).pushReplacementNamed('/app-lock');
+     try {
+       _appLockService.onAppResumed();
+       
+       if (_appLockService.isLocked) {
+         // Navigate to app lock screen
+         if (mounted) {
+           Navigator.of(context).pushReplacementNamed('/app-lock');
+         }
       }
+     } catch (e) {
+       // Log error or handle gracefully
+       debugPrint('App lock check failed: $e');
     }
   }
lib/screens/settings_screen.dart (1)

294-300: Extract timeout options to reduce duplication.

The timeout options are duplicated between _getLockTimeoutText and _showLockTimeoutDialog. Consider extracting them to a class constant.

Add this constant to the class:

static const List<Map<String, dynamic>> _timeoutOptions = [
  {'value': 0, 'label': 'Immediate'},
  {'value': 30, 'label': '30 seconds'},  
  {'value': 60, 'label': '1 minute'},
  {'value': 300, 'label': '5 minutes'},
  {'value': 600, 'label': '10 minutes'},
];

Then update _getLockTimeoutText to use this constant:

String _getLockTimeoutText() {
  final option = _timeoutOptions.firstWhere(
    (opt) => opt['value'] == _lockTimeout,
    orElse: () => {'label': '$_lockTimeout seconds'},
  );
  return option['label'] as String;
}
lib/services/app_lock_service.dart (1)

77-89: Consider enhancing PIN security validation.

The current implementation only validates PIN length. Consider adding validation for weak PINs and implementing rate limiting for verification attempts.

Consider these security enhancements:

  1. Validate against common weak PINs (1234, 0000, etc.)
  2. Add rate limiting for failed PIN attempts
  3. Consider hashing the PIN before storage for additional security

Example validation:

static const List<String> _weakPins = ['0000', '1111', '1234', '4321'];

Future<bool> setPinCode(String pinCode) async {
  if (pinCode.length < 4) {
    return false;
  }
  
  if (_weakPins.contains(pinCode)) {
    return false; // Reject weak PINs
  }
  
  try {
    await _secureStorage.write(key: _pinCodeKey, value: pinCode);
    return true;
  } catch (e) {
    return false;
  }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df8d2a6 and ce9be5f.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • README.md (3 hunks)
  • android/app/build.gradle.kts (2 hunks)
  • android/app/src/main/AndroidManifest.xml (1 hunks)
  • ios/Runner/Info.plist (1 hunks)
  • lib/main.dart (2 hunks)
  • lib/screens/app_lock_screen.dart (1 hunks)
  • lib/screens/login_screen.dart (4 hunks)
  • lib/screens/pin_setup_screen.dart (1 hunks)
  • lib/screens/settings_screen.dart (4 hunks)
  • lib/screens/splash_screen.dart (2 hunks)
  • lib/services/app_lock_service.dart (1 hunks)
  • pubspec.yaml (1 hunks)
🔇 Additional comments (22)
pubspec.yaml (1)

43-43: Dependency addition LGTM

local_auth ^2.2.0 is the canonical package for biometrics and is compatible with your min / target SDK versions. Nice catch including it here.

ios/Runner/Info.plist (1)

53-54: Face ID usage string looks good

The mandatory NSFaceIDUsageDescription key is present with a clear explanation — this will satisfy App Store review.

lib/screens/splash_screen.dart (2)

6-6: LGTM - Clean import addition

The AppLockService import is correctly added to support the new app lock functionality.


44-58: LGTM - Proper app lock integration with navigation

The navigation logic correctly handles both reviewer mode and app lock states. The mounted checks prevent navigation issues, and the routing to /main and /app-lock is consistent with the new app structure.

README.md (3)

32-32: LGTM - Clear feature description

The app lock security feature description is concise and accurately reflects the implemented functionality.


47-55: Excellent documentation of app lock capabilities

The dedicated App Lock Security section provides comprehensive coverage of all features including PIN protection, biometric authentication, configurable timeouts, and secure storage. This will help users understand the full scope of the security enhancements.


111-111: LGTM - Consistent security documentation

The addition to the Security & Privacy section appropriately highlights the app lock feature alongside existing security measures.

lib/screens/app_lock_screen.dart (4)

33-52: LGTM - Secure biometric authentication flow

The biometric authentication implementation correctly checks for availability and user preferences before attempting authentication. The mounted check prevents navigation issues after async operations.


76-107: Secure PIN verification with proper error handling

The PIN verification logic correctly handles async operations, provides user feedback for incorrect PINs, and includes proper cleanup with mounted checks. The automatic error clearing after 2 seconds provides good UX.


122-155: LGTM - Well-structured number button implementation

The number button widget provides good visual feedback with proper theming and aspect ratio handling. The tap state management correctly disables interaction during authentication.


192-302: Excellent overall UI composition and accessibility

The main build method creates a well-structured, accessible interface with proper spacing, theming, and responsive layout. The numeric keypad layout follows standard conventions and includes proper accessibility considerations.

lib/screens/pin_setup_screen.dart (3)

27-53: LGTM - Clear two-phase PIN entry logic

The PIN entry logic correctly handles both creation and confirmation phases with proper state transitions. The length validation and error state clearing provide good user feedback.


73-123: Secure PIN verification and storage with proper error handling

The PIN matching logic and AppLockService integration correctly handles the confirmation flow. The success feedback with SnackBar and navigation provides clear user feedback. Error handling includes proper async state management.


207-315: Well-structured setup UI with clear user guidance

The main build method provides excellent user guidance with contextual instructions that change based on the setup phase. The layout is consistent with the app lock screen while being appropriately adapted for the setup flow.

lib/main.dart (5)

10-12: LGTM - Clean imports for app lock integration

The new imports for AppLockScreen, PinSetupScreen, and AppLockService are properly organized and support the app lock functionality.


22-27: LGTM - Proper widget state conversion

The conversion from ConsumerWidget to ConsumerStatefulWidget is correctly implemented to support app lifecycle monitoring.


29-55: Excellent app lifecycle integration with proper cleanup

The implementation correctly adds and removes the WidgetsBindingObserver, initializes the AppLockService asynchronously, and manages the app lock state. The initialization pattern ensures the service is ready before state updates.


57-77: Secure app lifecycle state management

The app lifecycle monitoring correctly responds to app resume events and navigates to the app lock screen when needed. The mounted check prevents navigation issues after async operations.


110-117: LGTM - Complete routing configuration

The route configuration includes all necessary screens for the app lock feature. The route naming is consistent with the navigation calls throughout the app.

lib/screens/settings_screen.dart (1)

7-14: LGTM! Widget conversion is appropriate for state management.

The conversion to ConsumerStatefulWidget is the correct approach for managing the asynchronous loading and local state of app lock settings.

lib/services/app_lock_service.dart (2)

143-167: Biometric authentication implementation looks secure.

Good security practices:

  • Checks availability before attempting authentication
  • Uses biometricOnly: true to prevent fallback to device credentials
  • Proper error handling
  • Auto-unlocks on successful authentication

186-198: Data cleanup method is comprehensive.

The clearAllData method properly removes all secure storage entries and resets in-memory state, ensuring complete cleanup of app lock data.

Comment thread lib/screens/pin_setup_screen.dart Outdated
Comment thread lib/screens/settings_screen.dart
Comment thread lib/screens/settings_screen.dart
Comment thread lib/services/app_lock_service.dart
Comment thread lib/services/app_lock_service.dart
…pp lock and pin setup screens

AI code suggestion fixes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
lib/widgets/pin_ui_components.dart (1)

77-88: Same consistency issue with PinActionButton.

Apply the same fix as PinNumberButton to maintain consistent behavior patterns.

lib/screens/settings_screen.dart (1)

231-234: Consider user experience for test functionality.

Using pushNamed instead of pushReplacementNamed would allow users to return to settings after testing, improving the UX for this test feature.

 onTap: () {
   _appLockService.lock();
-  Navigator.of(context).pushReplacementNamed('/app-lock');
+  Navigator.of(context).pushNamed('/app-lock');
 },
🧹 Nitpick comments (2)
lib/widgets/pin_ui_components.dart (1)

27-38: Consider making onPressed non-nullable for better UX.

The PinNumberButton allows onPressed to be null, but this creates inconsistent behavior with the isDisabled parameter. A disabled button should still have a callback but ignore it.

-  final VoidCallback? onPressed;
+  final VoidCallback onPressed;

Then update the InkWell:

-              onTap: isDisabled ? null : onPressed,
+              onTap: isDisabled ? () {} : onPressed,
lib/screens/pin_setup_screen.dart (1)

23-26: Remove empty initState method.

The initState method is empty and unnecessary.

-  @override
-  void initState() {
-    super.initState();
-  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce9be5f and 1541d04.

📒 Files selected for processing (5)
  • lib/screens/app_lock_screen.dart (1 hunks)
  • lib/screens/pin_setup_screen.dart (1 hunks)
  • lib/screens/settings_screen.dart (4 hunks)
  • lib/services/app_lock_service.dart (1 hunks)
  • lib/widgets/pin_ui_components.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/services/app_lock_service.dart
🔇 Additional comments (9)
lib/widgets/pin_ui_components.dart (1)

3-10: LGTM! Well-structured PIN digit indicator widget.

The PinDigitWidget uses proper theme colors and follows Flutter conventions with optional parameters and clear naming.

lib/screens/app_lock_screen.dart (2)

82-82: Security: PIN stored in memory as plain text.

The PIN is concatenated into a plain string before verification. Consider using a more secure approach where individual digits are not stored in memory longer than necessary.

This approach stores the complete PIN in memory. Verify if the AppLockService.verifyPinCode method handles secure comparison to prevent timing attacks and ensure the PIN is cleared from memory promptly.


239-243: Good UX: Biometric button placement and functionality.

The biometric authentication button is well-positioned and allows users to retry biometric auth if the initial attempt fails.

lib/screens/pin_setup_screen.dart (2)

105-107: Good security practice: Automatic app lock enablement.

Automatically enabling app lock after PIN setup ensures the security feature is immediately active.


74-94: Well-implemented PIN validation logic.

The PIN mismatch handling with error display and confirmation reset provides good user feedback.

lib/screens/settings_screen.dart (4)

31-50: Well-structured initialization with proper loading states.

The initialization pattern correctly separates service setup from async operations like biometrics checking, with appropriate loading state management.


165-178: Good UX: Conditional PIN setup navigation.

The logic to automatically navigate to PIN setup when enabling app lock without a PIN provides seamless user experience.


247-262: Clean timeout text formatting.

The helper method provides clear, user-friendly timeout descriptions with good fallback handling.


290-330: Well-implemented timeout selection dialog.

The dialog provides clear options with immediate state updates and proper navigation handling.

Comment thread lib/screens/app_lock_screen.dart
Comment thread lib/screens/app_lock_screen.dart
Comment thread lib/screens/pin_setup_screen.dart Outdated
}
getByName("debug") {
signingConfig = signingConfigs.getByName("debug")
// Debug builds don't need signing config for development

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cogwheel0 check this if you want to keep it as is, I was unable to run as I didn't have any signing config.

@maxraywork

Copy link
Copy Markdown

@cogwheel0 Please take a look at this and merge for the next version

@shreyaspapi

Copy link
Copy Markdown
Author

@cogwheel0 Please take a look at this and merge for the next version

I agree

@cogwheel0

Copy link
Copy Markdown
Owner

Yes, planning on it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App lock

3 participants