Compare commits
	
		
			20 Commits
		
	
	
		
			7bca25a30c
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1403c3115c | |||
| 52529a7974 | |||
| 2d5d04987b | |||
| 43ddf76827 | |||
| 640a9fb3a2 | |||
| be0483fbef | |||
| 3b860a6d97 | |||
| ba39bef3b9 | |||
| 6f75dafa0d | |||
| 64a54dabb8 | |||
| bb8ea9a037 | |||
| e96db56927 | |||
| 1684a3b46f | |||
| 35befd8e40 | |||
| 8f585da677 | |||
| 67209dbb1c | |||
| 55ba06295e | |||
| c0da607b72 | |||
| a6531ca88a | |||
| 9010574b59 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -43,3 +43,4 @@ package-lock.json
 | 
			
		||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
 | 
			
		||||
*.apk
 | 
			
		||||
*.log
 | 
			
		||||
ios
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import registerRootComponent from 'expo/build/launch/registerRootComponent';
 | 
			
		||||
import { registerRootComponent } from 'expo';
 | 
			
		||||
import App from "App";
 | 
			
		||||
 | 
			
		||||
registerRootComponent(App);
 | 
			
		||||
							
								
								
									
										1
									
								
								android/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -10,6 +10,7 @@ build/
 | 
			
		||||
local.properties
 | 
			
		||||
*.iml
 | 
			
		||||
*.hprof
 | 
			
		||||
.cxx/
 | 
			
		||||
 | 
			
		||||
# Bundle artifacts
 | 
			
		||||
*.jsbundle
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
apply plugin: "com.android.application"
 | 
			
		||||
apply plugin: "org.jetbrains.kotlin.android"
 | 
			
		||||
apply plugin: "com.facebook.react"
 | 
			
		||||
 | 
			
		||||
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
 | 
			
		||||
@@ -11,20 +12,21 @@ react {
 | 
			
		||||
    entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
 | 
			
		||||
    reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
 | 
			
		||||
    hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
 | 
			
		||||
    codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
 | 
			
		||||
    codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
 | 
			
		||||
 | 
			
		||||
    enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
 | 
			
		||||
    // Use Expo CLI to bundle the app, this ensures the Metro config
 | 
			
		||||
    // works correctly with Expo projects.
 | 
			
		||||
    cliFile = new File(["node", "--print", "require.resolve('@expo/cli')"].execute(null, rootDir).text.trim())
 | 
			
		||||
    cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
 | 
			
		||||
    bundleCommand = "export:embed"
 | 
			
		||||
 | 
			
		||||
    /* Folders */
 | 
			
		||||
    //   The root of your project, i.e. where "package.json" lives. Default is '..'
 | 
			
		||||
    // root = file("../")
 | 
			
		||||
    //   The folder where the react-native NPM package is. Default is ../node_modules/react-native
 | 
			
		||||
    // reactNativeDir = file("../node_modules/react-native")
 | 
			
		||||
    //   The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
 | 
			
		||||
    // codegenDir = file("../node_modules/@react-native/codegen")
 | 
			
		||||
     //   The root of your project, i.e. where "package.json" lives. Default is '../..'
 | 
			
		||||
    // root = file("../../")
 | 
			
		||||
    //   The folder where the react-native NPM package is. Default is ../../node_modules/react-native
 | 
			
		||||
    // reactNativeDir = file("../../node_modules/react-native")
 | 
			
		||||
    //   The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
 | 
			
		||||
    // codegenDir = file("../../node_modules/@react-native/codegen")
 | 
			
		||||
 | 
			
		||||
    /* Variants */
 | 
			
		||||
    //   The list of variants to that are debuggable. For those we're going to
 | 
			
		||||
@@ -56,6 +58,9 @@ react {
 | 
			
		||||
    //
 | 
			
		||||
    //   The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
 | 
			
		||||
    // hermesFlags = ["-O", "-output-source-map"]
 | 
			
		||||
 | 
			
		||||
    /* Autolinking */
 | 
			
		||||
    autolinkLibrariesWithApp()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -74,12 +79,13 @@ def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInRelea
 | 
			
		||||
 * give correct results when using with locales other than en-US. Note that
 | 
			
		||||
 * this variant is about 6MiB larger per architecture than default.
 | 
			
		||||
 */
 | 
			
		||||
def jscFlavor = 'org.webkit:android-jsc:+'
 | 
			
		||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    ndkVersion rootProject.ext.ndkVersion
 | 
			
		||||
 | 
			
		||||
    compileSdkVersion rootProject.ext.compileSdkVersion
 | 
			
		||||
    buildToolsVersion rootProject.ext.buildToolsVersion
 | 
			
		||||
    compileSdk rootProject.ext.compileSdkVersion
 | 
			
		||||
 | 
			
		||||
    namespace 'com.anonymous.Assemblr'
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
@@ -87,9 +93,7 @@ android {
 | 
			
		||||
        minSdkVersion rootProject.ext.minSdkVersion
 | 
			
		||||
        targetSdkVersion rootProject.ext.targetSdkVersion
 | 
			
		||||
        versionCode 1
 | 
			
		||||
        versionName "1.1.7"
 | 
			
		||||
 | 
			
		||||
        buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString())
 | 
			
		||||
        versionName "1.5.3"
 | 
			
		||||
    }
 | 
			
		||||
    signingConfigs {
 | 
			
		||||
        debug {
 | 
			
		||||
@@ -110,8 +114,17 @@ android {
 | 
			
		||||
            shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
 | 
			
		||||
            minifyEnabled enableProguardInReleaseBuilds
 | 
			
		||||
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
 | 
			
		||||
            crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    packagingOptions {
 | 
			
		||||
        jniLibs {
 | 
			
		||||
            useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    androidResources {
 | 
			
		||||
        ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply static values from `gradle.properties` to the `android.packagingOptions`
 | 
			
		||||
@@ -141,40 +154,28 @@ dependencies {
 | 
			
		||||
    def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
 | 
			
		||||
    def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
 | 
			
		||||
    def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
 | 
			
		||||
    def frescoVersion = rootProject.ext.frescoVersion
 | 
			
		||||
 | 
			
		||||
    // If your app supports Android versions before Ice Cream Sandwich (API level 14)
 | 
			
		||||
    if (isGifEnabled || isWebpEnabled) {
 | 
			
		||||
        implementation("com.facebook.fresco:fresco:${frescoVersion}")
 | 
			
		||||
        implementation("com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}")
 | 
			
		||||
    }
 | 
			
		||||
    implementation project(':react-native-tcp-socket')
 | 
			
		||||
    implementation project(':react-native-keyevent')
 | 
			
		||||
    implementation project(':react-native-bluetooth-classic')
 | 
			
		||||
 | 
			
		||||
    if (isGifEnabled) {
 | 
			
		||||
        // For animated gif support
 | 
			
		||||
        implementation("com.facebook.fresco:animated-gif:${frescoVersion}")
 | 
			
		||||
        implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isWebpEnabled) {
 | 
			
		||||
        // For webp support
 | 
			
		||||
        implementation("com.facebook.fresco:webpsupport:${frescoVersion}")
 | 
			
		||||
        implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
 | 
			
		||||
        if (isWebpAnimatedEnabled) {
 | 
			
		||||
            // Animated webp support
 | 
			
		||||
            implementation("com.facebook.fresco:animated-webp:${frescoVersion}")
 | 
			
		||||
            implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
 | 
			
		||||
    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
 | 
			
		||||
        exclude group:'com.squareup.okhttp3', module:'okhttp'
 | 
			
		||||
    }
 | 
			
		||||
    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
 | 
			
		||||
 | 
			
		||||
    if (hermesEnabled.toBoolean()) {
 | 
			
		||||
        implementation("com.facebook.react:hermes-android")
 | 
			
		||||
    } else {
 | 
			
		||||
        implementation jscFlavor
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
 | 
			
		||||
applyNativeModulesAppBuildGradle(project)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,16 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.VIBRATE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH" />
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 | 
			
		||||
 | 
			
		||||
    <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
 | 
			
		||||
</manifest>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,75 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
 | 
			
		||||
 * directory of this source tree.
 | 
			
		||||
 */
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import com.facebook.flipper.android.AndroidFlipperClient;
 | 
			
		||||
import com.facebook.flipper.android.utils.FlipperUtils;
 | 
			
		||||
import com.facebook.flipper.core.FlipperClient;
 | 
			
		||||
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
 | 
			
		||||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
 | 
			
		||||
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
 | 
			
		||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
 | 
			
		||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
 | 
			
		||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
 | 
			
		||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
 | 
			
		||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
 | 
			
		||||
import com.facebook.react.ReactInstanceEventListener;
 | 
			
		||||
import com.facebook.react.ReactInstanceManager;
 | 
			
		||||
import com.facebook.react.bridge.ReactContext;
 | 
			
		||||
import com.facebook.react.modules.network.NetworkingModule;
 | 
			
		||||
import okhttp3.OkHttpClient;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class responsible of loading Flipper inside your React Native application. This is the debug
 | 
			
		||||
 * flavor of it. Here you can add your own plugins and customize the Flipper setup.
 | 
			
		||||
 */
 | 
			
		||||
public class ReactNativeFlipper {
 | 
			
		||||
  public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
 | 
			
		||||
    if (FlipperUtils.shouldEnableFlipper(context)) {
 | 
			
		||||
      final FlipperClient client = AndroidFlipperClient.getInstance(context);
 | 
			
		||||
 | 
			
		||||
      client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
 | 
			
		||||
      client.addPlugin(new DatabasesFlipperPlugin(context));
 | 
			
		||||
      client.addPlugin(new SharedPreferencesFlipperPlugin(context));
 | 
			
		||||
      client.addPlugin(CrashReporterPlugin.getInstance());
 | 
			
		||||
 | 
			
		||||
      NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
 | 
			
		||||
      NetworkingModule.setCustomClientBuilder(
 | 
			
		||||
          new NetworkingModule.CustomClientBuilder() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void apply(OkHttpClient.Builder builder) {
 | 
			
		||||
              builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
      client.addPlugin(networkFlipperPlugin);
 | 
			
		||||
      client.start();
 | 
			
		||||
 | 
			
		||||
      // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
 | 
			
		||||
      // Hence we run if after all native modules have been initialized
 | 
			
		||||
      ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
 | 
			
		||||
      if (reactContext == null) {
 | 
			
		||||
        reactInstanceManager.addReactInstanceEventListener(
 | 
			
		||||
            new ReactInstanceEventListener() {
 | 
			
		||||
              @Override
 | 
			
		||||
              public void onReactContextInitialized(ReactContext reactContext) {
 | 
			
		||||
                reactInstanceManager.removeReactInstanceEventListener(this);
 | 
			
		||||
                reactContext.runOnNativeModulesQueueThread(
 | 
			
		||||
                    new Runnable() {
 | 
			
		||||
                      @Override
 | 
			
		||||
                      public void run() {
 | 
			
		||||
                        client.addPlugin(new FrescoFlipperPlugin());
 | 
			
		||||
                      }
 | 
			
		||||
                    });
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
      } else {
 | 
			
		||||
        client.addPlugin(new FrescoFlipperPlugin());
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,15 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
  <uses-permission android:name="android.permission.INTERNET"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.RECORD_AUDIO"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.VIBRATE"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
  <uses-permission android:name="android.permission.BLUETOOTH" />
 | 
			
		||||
  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
 | 
			
		||||
  <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 | 
			
		||||
 | 
			
		||||
  <queries>
 | 
			
		||||
    <intent>
 | 
			
		||||
      <action android:name="android.intent.action.VIEW"/>
 | 
			
		||||
@@ -12,12 +17,11 @@
 | 
			
		||||
      <data android:scheme="https"/>
 | 
			
		||||
    </intent>
 | 
			
		||||
  </queries>
 | 
			
		||||
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
 | 
			
		||||
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:usesCleartextTraffic="true">
 | 
			
		||||
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
 | 
			
		||||
    <meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="49.0.0"/>
 | 
			
		||||
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
 | 
			
		||||
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
 | 
			
		||||
    <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
 | 
			
		||||
    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
 | 
			
		||||
      <intent-filter>
 | 
			
		||||
        <action android:name="android.intent.action.MAIN"/>
 | 
			
		||||
        <category android:name="android.intent.category.LAUNCHER"/>
 | 
			
		||||
@@ -26,9 +30,8 @@
 | 
			
		||||
        <action android:name="android.intent.action.VIEW"/>
 | 
			
		||||
        <category android:name="android.intent.category.DEFAULT"/>
 | 
			
		||||
        <category android:name="android.intent.category.BROWSABLE"/>
 | 
			
		||||
        <data android:scheme="com.anonymous.Assemblr"/>
 | 
			
		||||
        <data android:scheme="exp+assemblr"/>
 | 
			
		||||
      </intent-filter>
 | 
			
		||||
    </activity>
 | 
			
		||||
    <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
 | 
			
		||||
  </application>
 | 
			
		||||
</manifest>
 | 
			
		||||
@@ -1,65 +0,0 @@
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.ReactActivity;
 | 
			
		||||
import com.facebook.react.ReactActivityDelegate;
 | 
			
		||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
 | 
			
		||||
import com.facebook.react.defaults.DefaultReactActivityDelegate;
 | 
			
		||||
 | 
			
		||||
import expo.modules.ReactActivityDelegateWrapper;
 | 
			
		||||
 | 
			
		||||
public class MainActivity extends ReactActivity {
 | 
			
		||||
  @Override
 | 
			
		||||
  protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
    // Set the theme to AppTheme BEFORE onCreate to support 
 | 
			
		||||
    // coloring the background, status bar, and navigation bar.
 | 
			
		||||
    // This is required for expo-splash-screen.
 | 
			
		||||
    setTheme(R.style.AppTheme);
 | 
			
		||||
    super.onCreate(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the name of the main component registered from JavaScript.
 | 
			
		||||
   * This is used to schedule rendering of the component.
 | 
			
		||||
   */
 | 
			
		||||
  @Override
 | 
			
		||||
  protected String getMainComponentName() {
 | 
			
		||||
    return "main";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
 | 
			
		||||
   * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
 | 
			
		||||
   * (aka React 18) with two boolean flags.
 | 
			
		||||
   */
 | 
			
		||||
  @Override
 | 
			
		||||
  protected ReactActivityDelegate createReactActivityDelegate() {
 | 
			
		||||
    return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate(
 | 
			
		||||
        this,
 | 
			
		||||
        getMainComponentName(),
 | 
			
		||||
        // If you opted-in for the New Architecture, we enable the Fabric Renderer.
 | 
			
		||||
        DefaultNewArchitectureEntryPoint.getFabricEnabled()));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Align the back button behavior with Android S
 | 
			
		||||
   * where moving root activities to background instead of finishing activities.
 | 
			
		||||
   * @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
 | 
			
		||||
   */
 | 
			
		||||
  @Override
 | 
			
		||||
  public void invokeDefaultOnBackPressed() {
 | 
			
		||||
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
 | 
			
		||||
      if (!moveTaskToBack(false)) {
 | 
			
		||||
        // For non-root activities, use the default implementation to finish them.
 | 
			
		||||
        super.invokeDefaultOnBackPressed();
 | 
			
		||||
      }
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Use the default back button implementation on Android S
 | 
			
		||||
    // because it's doing more than {@link Activity#moveTaskToBack} in fact.
 | 
			
		||||
    super.invokeDefaultOnBackPressed();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
package com.anonymous.Assemblr
 | 
			
		||||
 | 
			
		||||
import expo.modules.splashscreen.SplashScreenManager
 | 
			
		||||
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.KeyEvent
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.ReactActivity
 | 
			
		||||
import com.facebook.react.ReactActivityDelegate
 | 
			
		||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
 | 
			
		||||
import com.facebook.react.defaults.DefaultReactActivityDelegate
 | 
			
		||||
import com.github.kevinejohn.keyevent.KeyEventModule
 | 
			
		||||
 | 
			
		||||
import expo.modules.ReactActivityDelegateWrapper
 | 
			
		||||
 | 
			
		||||
class MainActivity : ReactActivity() {
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        // Set the theme to AppTheme BEFORE onCreate to support
 | 
			
		||||
        // coloring the background, status bar, and navigation bar.
 | 
			
		||||
        // This is required for expo-splash-screen.
 | 
			
		||||
        // setTheme(R.style.AppTheme);
 | 
			
		||||
        // @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af
 | 
			
		||||
        SplashScreenManager.registerOnActivity(this)
 | 
			
		||||
        // @generated end expo-splashscreen
 | 
			
		||||
        super.onCreate(null)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the name of the main component registered from JavaScript. This is used to schedule
 | 
			
		||||
     * rendering of the component.
 | 
			
		||||
     */
 | 
			
		||||
    override fun getMainComponentName(): String = "main"
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
 | 
			
		||||
     * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
 | 
			
		||||
     */
 | 
			
		||||
    override fun createReactActivityDelegate(): ReactActivityDelegate {
 | 
			
		||||
        return ReactActivityDelegateWrapper(
 | 
			
		||||
            this,
 | 
			
		||||
            BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
 | 
			
		||||
            object : DefaultReactActivityDelegate(
 | 
			
		||||
                this,
 | 
			
		||||
                mainComponentName,
 | 
			
		||||
                fabricEnabled
 | 
			
		||||
            ) {})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Align the back button behavior with Android S
 | 
			
		||||
     * where moving root activities to background instead of finishing activities.
 | 
			
		||||
     * @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
 | 
			
		||||
     */
 | 
			
		||||
    override fun invokeDefaultOnBackPressed() {
 | 
			
		||||
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
 | 
			
		||||
            if (!moveTaskToBack(false)) {
 | 
			
		||||
                // For non-root activities, use the default implementation to finish them.
 | 
			
		||||
                super.invokeDefaultOnBackPressed()
 | 
			
		||||
            }
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Use the default back button implementation on Android S
 | 
			
		||||
        // because it's doing more than [Activity.moveTaskToBack] in fact.
 | 
			
		||||
        super.invokeDefaultOnBackPressed()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
 | 
			
		||||
        KeyEventModule.getInstance().onKeyDownEvent(keyCode, event)
 | 
			
		||||
//        super.onKeyDown(keyCode, event)
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
 | 
			
		||||
        KeyEventModule.getInstance().onKeyUpEvent(keyCode, event);
 | 
			
		||||
//        super.onKeyUp(keyCode, event)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override fun onKeyMultiple(keyCode: Int, repeatCount: Int, event: KeyEvent): Boolean {
 | 
			
		||||
        KeyEventModule.getInstance().onKeyMultipleEvent(keyCode, repeatCount, event)
 | 
			
		||||
        return true;
 | 
			
		||||
//        return super.onKeyMultiple(keyCode, repeatCount, event)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
 | 
			
		||||
import android.app.Application;
 | 
			
		||||
import android.content.res.Configuration;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.PackageList;
 | 
			
		||||
import com.facebook.react.ReactApplication;
 | 
			
		||||
import com.facebook.react.ReactNativeHost;
 | 
			
		||||
import com.facebook.react.ReactPackage;
 | 
			
		||||
import com.facebook.react.config.ReactFeatureFlags;
 | 
			
		||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
 | 
			
		||||
import com.facebook.react.defaults.DefaultReactNativeHost;
 | 
			
		||||
import com.facebook.soloader.SoLoader;
 | 
			
		||||
 | 
			
		||||
import expo.modules.ApplicationLifecycleDispatcher;
 | 
			
		||||
import expo.modules.ReactNativeHostWrapper;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class MainApplication extends Application implements ReactApplication {
 | 
			
		||||
 | 
			
		||||
  private final ReactNativeHost mReactNativeHost =
 | 
			
		||||
    new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) {
 | 
			
		||||
      @Override
 | 
			
		||||
      public boolean getUseDeveloperSupport() {
 | 
			
		||||
        return BuildConfig.DEBUG;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Override
 | 
			
		||||
      protected List<ReactPackage> getPackages() {
 | 
			
		||||
        @SuppressWarnings("UnnecessaryLocalVariable")
 | 
			
		||||
        List<ReactPackage> packages = new PackageList(this).getPackages();
 | 
			
		||||
        // Packages that cannot be autolinked yet can be added manually here, for example:
 | 
			
		||||
        // packages.add(new MyReactNativePackage());
 | 
			
		||||
        return packages;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Override
 | 
			
		||||
      protected String getJSMainModuleName() {
 | 
			
		||||
        return ".expo/.virtual-metro-entry";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Override
 | 
			
		||||
      protected boolean isNewArchEnabled() {
 | 
			
		||||
        return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @Override
 | 
			
		||||
      protected Boolean isHermesEnabled() {
 | 
			
		||||
        return BuildConfig.IS_HERMES_ENABLED;
 | 
			
		||||
      }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public ReactNativeHost getReactNativeHost() {
 | 
			
		||||
    return mReactNativeHost;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void onCreate() {
 | 
			
		||||
    super.onCreate();
 | 
			
		||||
    SoLoader.init(this, /* native exopackage */ false);
 | 
			
		||||
    if (!BuildConfig.REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS) {
 | 
			
		||||
      ReactFeatureFlags.unstable_useRuntimeSchedulerAlways = false;
 | 
			
		||||
    }
 | 
			
		||||
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
 | 
			
		||||
      // If you opted-in for the New Architecture, we load the native entry point for this app.
 | 
			
		||||
      DefaultNewArchitectureEntryPoint.load();
 | 
			
		||||
    }
 | 
			
		||||
    ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
 | 
			
		||||
    ApplicationLifecycleDispatcher.onApplicationCreate(this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void onConfigurationChanged(@NonNull Configuration newConfig) {
 | 
			
		||||
    super.onConfigurationChanged(newConfig);
 | 
			
		||||
    ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
package com.anonymous.Assemblr
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import android.content.res.Configuration
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.PackageList
 | 
			
		||||
import com.facebook.react.ReactApplication
 | 
			
		||||
import com.facebook.react.ReactNativeHost
 | 
			
		||||
import com.facebook.react.ReactPackage
 | 
			
		||||
import com.facebook.react.ReactHost
 | 
			
		||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
 | 
			
		||||
import com.facebook.react.defaults.DefaultReactNativeHost
 | 
			
		||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
 | 
			
		||||
import com.facebook.soloader.SoLoader
 | 
			
		||||
import com.github.kevinejohn.keyevent.KeyEventPackage
 | 
			
		||||
import expo.modules.ApplicationLifecycleDispatcher
 | 
			
		||||
import expo.modules.ReactNativeHostWrapper
 | 
			
		||||
import com.asterinet.react.tcpsocket.TcpSocketPackage;
 | 
			
		||||
import kjd.reactnative.bluetooth.RNBluetoothClassicPackage;
 | 
			
		||||
 | 
			
		||||
class MainApplication : Application(), ReactApplication {
 | 
			
		||||
 | 
			
		||||
    override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
 | 
			
		||||
        this,
 | 
			
		||||
        object : DefaultReactNativeHost(this) {
 | 
			
		||||
            override fun getPackages(): List<ReactPackage> {
 | 
			
		||||
                val packages = PackageList(this).packages
 | 
			
		||||
                packages.add(PdfToBitmapPackage())
 | 
			
		||||
                packages.add(TcpSocketPackage())
 | 
			
		||||
                packages.add(MyTcpSocketPackage())
 | 
			
		||||
                packages.add(KeyEventPackage())
 | 
			
		||||
                packages.add(RNBluetoothClassicPackage())
 | 
			
		||||
                return packages
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
 | 
			
		||||
 | 
			
		||||
            override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
 | 
			
		||||
 | 
			
		||||
            override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
 | 
			
		||||
            override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override val reactHost: ReactHost
 | 
			
		||||
        get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        super.onCreate()
 | 
			
		||||
        SoLoader.init(this, OpenSourceMergedSoMapping)
 | 
			
		||||
        if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
 | 
			
		||||
            // If you opted-in for the New Architecture, we load the native entry point for this app.
 | 
			
		||||
            load()
 | 
			
		||||
        }
 | 
			
		||||
        ApplicationLifecycleDispatcher.onApplicationCreate(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onConfigurationChanged(newConfig: Configuration) {
 | 
			
		||||
        super.onConfigurationChanged(newConfig)
 | 
			
		||||
        ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.bridge.ReactApplicationContext;
 | 
			
		||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
 | 
			
		||||
import com.facebook.react.bridge.ReactMethod;
 | 
			
		||||
import com.facebook.react.bridge.Promise;
 | 
			
		||||
import com.facebook.react.bridge.ReadableArray;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class MyTcpSocketModule extends ReactContextBaseJavaModule {
 | 
			
		||||
    public MyTcpSocketModule(ReactApplicationContext reactContext) {
 | 
			
		||||
        super(reactContext);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return "MyTcpSocket";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ReactMethod
 | 
			
		||||
    public void writeToSocket(String ip, int port, ReadableArray data, Promise promise) {
 | 
			
		||||
        try (Socket socket = new Socket(ip, port)) {
 | 
			
		||||
            OutputStream output = socket.getOutputStream();
 | 
			
		||||
            for (int i = 0; i < data.size(); i++) {
 | 
			
		||||
                String item = data.getString(i);
 | 
			
		||||
                assert item != null;
 | 
			
		||||
                output.write(item.getBytes());
 | 
			
		||||
            }
 | 
			
		||||
            output.flush();
 | 
			
		||||
            promise.resolve("ok");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            promise.reject("ERROR", e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.ReactPackage;
 | 
			
		||||
import com.facebook.react.bridge.NativeModule;
 | 
			
		||||
import com.facebook.react.bridge.ReactApplicationContext;
 | 
			
		||||
import com.facebook.react.uimanager.ViewManager;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class MyTcpSocketPackage implements ReactPackage {
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
 | 
			
		||||
        List<NativeModule> modules = new ArrayList<>();
 | 
			
		||||
        modules.add(new MyTcpSocketModule(reactContext));
 | 
			
		||||
        return modules;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
 | 
			
		||||
        return Collections.emptyList();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
package com.anonymous.Assemblr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import android.graphics.Bitmap
 | 
			
		||||
import android.graphics.pdf.PdfRenderer
 | 
			
		||||
import android.os.ParcelFileDescriptor
 | 
			
		||||
import android.util.Base64
 | 
			
		||||
import com.facebook.react.bridge.Promise
 | 
			
		||||
import com.facebook.react.bridge.ReactApplicationContext
 | 
			
		||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
 | 
			
		||||
import com.facebook.react.bridge.ReactMethod
 | 
			
		||||
import com.facebook.react.bridge.WritableNativeArray
 | 
			
		||||
import java.io.ByteArrayOutputStream
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.io.FileOutputStream
 | 
			
		||||
import androidx.core.graphics.createBitmap
 | 
			
		||||
 | 
			
		||||
class PdfToBitmapModule(reactContext: ReactApplicationContext) :
 | 
			
		||||
    ReactContextBaseJavaModule(reactContext) {
 | 
			
		||||
    override fun getName(): String = "PdfToBitmap"
 | 
			
		||||
 | 
			
		||||
    @ReactMethod
 | 
			
		||||
    fun convertPdfToBitmaps(pdfBase64: String, promise: Promise) {
 | 
			
		||||
        try {
 | 
			
		||||
            // Decode base64 PDF to byte array
 | 
			
		||||
            val pdfBytes = Base64.decode(pdfBase64, Base64.DEFAULT)
 | 
			
		||||
 | 
			
		||||
            // Create temporary file for PDF
 | 
			
		||||
            val tempFile = File.createTempFile("tempPdf", ".pdf", reactApplicationContext.cacheDir)
 | 
			
		||||
            FileOutputStream(tempFile).use { fos ->
 | 
			
		||||
                fos.write(pdfBytes)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Initialize PdfRenderer
 | 
			
		||||
            val fd = ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY)
 | 
			
		||||
            val pdfRenderer = PdfRenderer(fd)
 | 
			
		||||
 | 
			
		||||
            // Convert each page to a bitmap
 | 
			
		||||
            val bitmapBase64List = WritableNativeArray()
 | 
			
		||||
            for (pageIndex in 0 until pdfRenderer.pageCount) {
 | 
			
		||||
                val page = pdfRenderer.openPage(pageIndex)
 | 
			
		||||
                val scaleFactor = if (page.width < 100) 100 else 5
 | 
			
		||||
                val bitmap = createBitmap(page.width * scaleFactor, page.height * scaleFactor)
 | 
			
		||||
                page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
 | 
			
		||||
 | 
			
		||||
                // Convert bitmap to base64
 | 
			
		||||
                val stream = ByteArrayOutputStream()
 | 
			
		||||
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
 | 
			
		||||
                val byteArray = stream.toByteArray()
 | 
			
		||||
                val base64String = Base64.encodeToString(byteArray, Base64.NO_WRAP)
 | 
			
		||||
                bitmapBase64List.pushString(base64String)
 | 
			
		||||
 | 
			
		||||
                // Clean up
 | 
			
		||||
                bitmap.recycle()
 | 
			
		||||
                page.close()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Clean up renderer and file
 | 
			
		||||
            pdfRenderer.close()
 | 
			
		||||
            tempFile.delete()
 | 
			
		||||
 | 
			
		||||
            promise.resolve(bitmapBase64List)
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            promise.reject("PDF_CONVERSION_ERROR", "Failed to convert PDF to bitmaps: ${e.message}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
package com.anonymous.Assemblr
 | 
			
		||||
 | 
			
		||||
import com.facebook.react.ReactPackage
 | 
			
		||||
import com.facebook.react.bridge.NativeModule
 | 
			
		||||
import com.facebook.react.bridge.ReactApplicationContext
 | 
			
		||||
import com.facebook.react.uimanager.ViewManager
 | 
			
		||||
 | 
			
		||||
class PdfToBitmapPackage : ReactPackage {
 | 
			
		||||
    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
 | 
			
		||||
        return listOf(PdfToBitmapModule(reactContext))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
 | 
			
		||||
        return emptyList()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/drawable-hdpi/splashscreen_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.0 KiB  | 
| 
		 Before Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/drawable-mdpi/splashscreen_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.0 KiB  | 
| 
		 Before Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
| 
		 Before Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 58 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 19 KiB  | 
@@ -1,3 +1,6 @@
 | 
			
		||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
  <item android:drawable="@color/splashscreen_background"/>
 | 
			
		||||
  <item>
 | 
			
		||||
    <bitmap android:gravity="center" android:src="@drawable/splashscreen_logo"/>
 | 
			
		||||
  </item>
 | 
			
		||||
</layer-list>
 | 
			
		||||
@@ -17,7 +17,8 @@
 | 
			
		||||
       android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
 | 
			
		||||
       android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
 | 
			
		||||
       android:insetTop="@dimen/abc_edit_text_inset_top_material"
 | 
			
		||||
       android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
 | 
			
		||||
       android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
 | 
			
		||||
       >
 | 
			
		||||
 | 
			
		||||
    <selector>
 | 
			
		||||
        <!--
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 4.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB  | 
| 
		 Before Width: | Height: | Size: 6.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.6 KiB  | 
| 
		 Before Width: | Height: | Size: 3.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 Before Width: | Height: | Size: 6.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.6 KiB  | 
| 
		 Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB  | 
| 
		 Before Width: | Height: | Size: 8.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.6 KiB  | 
| 
		 Before Width: | Height: | Size: 10 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.0 KiB  | 
| 
		 Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 19 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.5 KiB  | 
@@ -1,17 +1,13 @@
 | 
			
		||||
<resources xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
 | 
			
		||||
    <item name="android:textColor">@android:color/black</item>
 | 
			
		||||
    <item name="android:editTextStyle">@style/ResetEditText</item>
 | 
			
		||||
  <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
 | 
			
		||||
    <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
 | 
			
		||||
    <item name="colorPrimary">@color/colorPrimary</item>
 | 
			
		||||
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
 | 
			
		||||
    <item name="android:statusBarColor">#ffffff</item>
 | 
			
		||||
    <item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
 | 
			
		||||
  </style>
 | 
			
		||||
  <style name="ResetEditText" parent="@android:style/Widget.EditText">
 | 
			
		||||
    <item name="android:padding">0dp</item>
 | 
			
		||||
    <item name="android:textColorHint">#c8c8c8</item>
 | 
			
		||||
    <item name="android:textColor">@android:color/black</item>
 | 
			
		||||
  </style>
 | 
			
		||||
  <style name="Theme.App.SplashScreen" parent="AppTheme">
 | 
			
		||||
    <item name="android:windowBackground">@drawable/splashscreen</item>
 | 
			
		||||
  <style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
 | 
			
		||||
    <item name="windowSplashScreenBackground">@color/splashscreen_background</item>
 | 
			
		||||
    <item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_logo</item>
 | 
			
		||||
    <item name="postSplashScreenTheme">@style/AppTheme</item>
 | 
			
		||||
  </style>
 | 
			
		||||
</resources>
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
			
		||||
 *
 | 
			
		||||
 * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
 | 
			
		||||
 * directory of this source tree.
 | 
			
		||||
 */
 | 
			
		||||
package com.anonymous.Assemblr;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import com.facebook.react.ReactInstanceManager;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class responsible of loading Flipper inside your React Native application. This is the release
 | 
			
		||||
 * flavor of it so it's empty as we don't want to load Flipper.
 | 
			
		||||
 */
 | 
			
		||||
public class ReactNativeFlipper {
 | 
			
		||||
  public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
 | 
			
		||||
    // Do nothing as we don't want to initialize Flipper on Release.
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,40 +1,37 @@
 | 
			
		||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    ext {
 | 
			
		||||
        buildToolsVersion = findProperty('android.buildToolsVersion') ?: '33.0.0'
 | 
			
		||||
        minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
 | 
			
		||||
        compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '33')
 | 
			
		||||
        targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '33')
 | 
			
		||||
        kotlinVersion = findProperty('android.kotlinVersion') ?: '1.8.10'
 | 
			
		||||
        frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'
 | 
			
		||||
 | 
			
		||||
        // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
 | 
			
		||||
        ndkVersion = "23.1.7779620"
 | 
			
		||||
    }
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath('com.android.tools.build:gradle:7.4.2')
 | 
			
		||||
        classpath('com.facebook.react:react-native-gradle-plugin')
 | 
			
		||||
    }
 | 
			
		||||
  repositories {
 | 
			
		||||
    google()
 | 
			
		||||
    mavenCentral()
 | 
			
		||||
  }
 | 
			
		||||
  dependencies {
 | 
			
		||||
    classpath('com.android.tools.build:gradle')
 | 
			
		||||
    classpath('com.facebook.react:react-native-gradle-plugin')
 | 
			
		||||
    classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def reactNativeAndroidDir = new File(
 | 
			
		||||
  providers.exec {
 | 
			
		||||
    workingDir(rootDir)
 | 
			
		||||
    commandLine("node", "--print", "require.resolve('react-native/package.json')")
 | 
			
		||||
  }.standardOutput.asText.get().trim(),
 | 
			
		||||
  "../android"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        maven {
 | 
			
		||||
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
 | 
			
		||||
            url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
 | 
			
		||||
        }
 | 
			
		||||
        maven {
 | 
			
		||||
            // Android JSC is installed from npm
 | 
			
		||||
            url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist'))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        google()
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
        maven { url 'https://www.jitpack.io' }
 | 
			
		||||
  repositories {
 | 
			
		||||
    maven {
 | 
			
		||||
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
 | 
			
		||||
      url(reactNativeAndroidDir)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    google()
 | 
			
		||||
    mavenCentral()
 | 
			
		||||
    maven { url 'https://www.jitpack.io' }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply plugin: "expo-root-project"
 | 
			
		||||
apply plugin: "com.facebook.react.rootproject"
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,8 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
 | 
			
		||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
 | 
			
		||||
android.useAndroidX=true
 | 
			
		||||
 | 
			
		||||
# Automatically convert third-party libraries to use AndroidX
 | 
			
		||||
android.enableJetifier=true
 | 
			
		||||
 | 
			
		||||
# Version of flipper SDK to use with React Native
 | 
			
		||||
FLIPPER_VERSION=0.182.0
 | 
			
		||||
# Enable AAPT2 PNG crunching
 | 
			
		||||
android.enablePngCrunchInReleaseBuilds=true
 | 
			
		||||
 | 
			
		||||
# Use this property to specify which architecture you want to build.
 | 
			
		||||
# You can also override it from the CLI using
 | 
			
		||||
@@ -38,7 +35,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
 | 
			
		||||
# your application. You should enable this flag either if you want
 | 
			
		||||
# to write custom TurboModules/Fabric components OR use libraries that
 | 
			
		||||
# are providing them.
 | 
			
		||||
newArchEnabled=false
 | 
			
		||||
newArchEnabled=true
 | 
			
		||||
 | 
			
		||||
# Use this property to enable or disable the Hermes JS engine.
 | 
			
		||||
# If set to false, you will be using JSC instead.
 | 
			
		||||
@@ -54,3 +51,9 @@ expo.webp.animated=false
 | 
			
		||||
 | 
			
		||||
# Enable network inspector
 | 
			
		||||
EX_DEV_CLIENT_NETWORK_INSPECTOR=true
 | 
			
		||||
 | 
			
		||||
# Use legacy packaging to compress native libraries in the resulting APK.
 | 
			
		||||
expo.useLegacyPackaging=false
 | 
			
		||||
 | 
			
		||||
# Whether the app is configured to use edge-to-edge via the app config or `react-native-edge-to-edge` plugin
 | 
			
		||||
expo.edgeToEdgeEnabled=false
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								android/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,6 +1,7 @@
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
 | 
			
		||||
networkTimeout=10000
 | 
			
		||||
validateDistributionUrl=true
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								android/gradlew
									
									
									
									
										vendored
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						@@ -15,6 +15,8 @@
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
# SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
#
 | 
			
		||||
@@ -55,7 +57,7 @@
 | 
			
		||||
#       Darwin, MinGW, and NonStop.
 | 
			
		||||
#
 | 
			
		||||
#   (3) This script is generated from the Groovy template
 | 
			
		||||
#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
			
		||||
#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
			
		||||
#       within the Gradle project.
 | 
			
		||||
#
 | 
			
		||||
#       You can find Gradle at https://github.com/gradle/gradle/.
 | 
			
		||||
@@ -80,13 +82,11 @@ do
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 | 
			
		||||
 | 
			
		||||
APP_NAME="Gradle"
 | 
			
		||||
# This is normally unused
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
APP_BASE_NAME=${0##*/}
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
			
		||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
 | 
			
		||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
 | 
			
		||||
 | 
			
		||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
			
		||||
MAX_FD=maximum
 | 
			
		||||
@@ -133,22 +133,29 @@ location of your Java installation."
 | 
			
		||||
    fi
 | 
			
		||||
else
 | 
			
		||||
    JAVACMD=java
 | 
			
		||||
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
    if ! command -v java >/dev/null 2>&1
 | 
			
		||||
    then
 | 
			
		||||
        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Increase the maximum file descriptors if we can.
 | 
			
		||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
 | 
			
		||||
    case $MAX_FD in #(
 | 
			
		||||
      max*)
 | 
			
		||||
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
 | 
			
		||||
        # shellcheck disable=SC2039,SC3045
 | 
			
		||||
        MAX_FD=$( ulimit -H -n ) ||
 | 
			
		||||
            warn "Could not query maximum file descriptor limit"
 | 
			
		||||
    esac
 | 
			
		||||
    case $MAX_FD in  #(
 | 
			
		||||
      '' | soft) :;; #(
 | 
			
		||||
      *)
 | 
			
		||||
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
 | 
			
		||||
        # shellcheck disable=SC2039,SC3045
 | 
			
		||||
        ulimit -n "$MAX_FD" ||
 | 
			
		||||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
 | 
			
		||||
    esac
 | 
			
		||||
@@ -193,11 +200,15 @@ if "$cygwin" || "$msys" ; then
 | 
			
		||||
    done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Collect all arguments for the java command;
 | 
			
		||||
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
 | 
			
		||||
#     shell script including quotes and variable substitutions, so put them in
 | 
			
		||||
#     double quotes to make sure that they get re-expanded; and
 | 
			
		||||
#   * put everything else in single quotes, so that it's not re-expanded.
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
			
		||||
 | 
			
		||||
# Collect all arguments for the java command:
 | 
			
		||||
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
 | 
			
		||||
#     and any embedded shellness will be escaped.
 | 
			
		||||
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
 | 
			
		||||
#     treated as '${Hostname}' itself on the command line.
 | 
			
		||||
 | 
			
		||||
set -- \
 | 
			
		||||
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								android/gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -13,6 +13,8 @@
 | 
			
		||||
@rem See the License for the specific language governing permissions and
 | 
			
		||||
@rem limitations under the License.
 | 
			
		||||
@rem
 | 
			
		||||
@rem SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
@rem
 | 
			
		||||
 | 
			
		||||
@if "%DEBUG%"=="" @echo off
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
@@ -26,6 +28,7 @@ if "%OS%"=="Windows_NT" setlocal
 | 
			
		||||
 | 
			
		||||
set DIRNAME=%~dp0
 | 
			
		||||
if "%DIRNAME%"=="" set DIRNAME=.
 | 
			
		||||
@rem This is normally unused
 | 
			
		||||
set APP_BASE_NAME=%~n0
 | 
			
		||||
set APP_HOME=%DIRNAME%
 | 
			
		||||
 | 
			
		||||
@@ -42,11 +45,11 @@ set JAVA_EXE=java.exe
 | 
			
		||||
%JAVA_EXE% -version >NUL 2>&1
 | 
			
		||||
if %ERRORLEVEL% equ 0 goto execute
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
echo. 1>&2
 | 
			
		||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
 | 
			
		||||
echo. 1>&2
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
 | 
			
		||||
echo location of your Java installation. 1>&2
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
@@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 | 
			
		||||
 | 
			
		||||
if exist "%JAVA_EXE%" goto execute
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
echo. 1>&2
 | 
			
		||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
 | 
			
		||||
echo. 1>&2
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
 | 
			
		||||
echo location of your Java installation. 1>&2
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,48 @@
 | 
			
		||||
pluginManagement {
 | 
			
		||||
  def reactNativeGradlePlugin = new File(
 | 
			
		||||
    providers.exec {
 | 
			
		||||
      workingDir(rootDir)
 | 
			
		||||
      commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
 | 
			
		||||
    }.standardOutput.asText.get().trim()
 | 
			
		||||
  ).getParentFile().absolutePath
 | 
			
		||||
  includeBuild(reactNativeGradlePlugin)
 | 
			
		||||
  
 | 
			
		||||
  def expoPluginsPath = new File(
 | 
			
		||||
    providers.exec {
 | 
			
		||||
      workingDir(rootDir)
 | 
			
		||||
      commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
 | 
			
		||||
    }.standardOutput.asText.get().trim(),
 | 
			
		||||
    "../android/expo-gradle-plugin"
 | 
			
		||||
  ).absolutePath
 | 
			
		||||
  includeBuild(expoPluginsPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
  id("com.facebook.react.settings")
 | 
			
		||||
  id("expo-autolinking-settings")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
 | 
			
		||||
  if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
 | 
			
		||||
    ex.autolinkLibrariesFromCommand()
 | 
			
		||||
  } else {
 | 
			
		||||
    ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
expoAutolinking.useExpoModules()
 | 
			
		||||
 | 
			
		||||
rootProject.name = 'Assemblr'
 | 
			
		||||
 | 
			
		||||
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
 | 
			
		||||
useExpoModules()
 | 
			
		||||
 | 
			
		||||
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
 | 
			
		||||
applyNativeModulesSettingsGradle(settings)
 | 
			
		||||
expoAutolinking.useExpoVersionCatalog()
 | 
			
		||||
 | 
			
		||||
include ':app'
 | 
			
		||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
 | 
			
		||||
includeBuild(expoAutolinking.reactNativeGradlePlugin)
 | 
			
		||||
 | 
			
		||||
include ':react-native-tcp-socket'
 | 
			
		||||
project(':react-native-tcp-socket').projectDir = new File(rootProject.projectDir, 	'../node_modules/react-native-tcp-socket/android')
 | 
			
		||||
 | 
			
		||||
include ':react-native-keyevent'
 | 
			
		||||
project(':react-native-keyevent').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyevent/android')
 | 
			
		||||
 | 
			
		||||
include ':react-native-bluetooth-classic'
 | 
			
		||||
project(':react-native-bluetooth-classic').projectDir = new File(rootProject.projectDir, 	'../node_modules/react-native-bluetooth-classic/android')
 | 
			
		||||
							
								
								
									
										10
									
								
								app.json
									
									
									
									
									
								
							
							
						
						@@ -8,14 +8,11 @@
 | 
			
		||||
            "usesCleartextTraffic": true
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        "react-native-keyevent-expo-config-plugin"
 | 
			
		||||
      ]
 | 
			
		||||
    ],
 | 
			
		||||
    "name": "Assemblr",
 | 
			
		||||
    "slug": "Assemblr",
 | 
			
		||||
    "version": "1.1.7",
 | 
			
		||||
    "version": "1.5.3",
 | 
			
		||||
    "orientation": "portrait",
 | 
			
		||||
    "icon": "./src/assets/icon.png",
 | 
			
		||||
    "userInterfaceStyle": "light",
 | 
			
		||||
@@ -28,7 +25,8 @@
 | 
			
		||||
      "src/**/*"
 | 
			
		||||
    ],
 | 
			
		||||
    "ios": {
 | 
			
		||||
      "supportsTablet": true
 | 
			
		||||
      "supportsTablet": true,
 | 
			
		||||
      "bundleIdentifier": "com.anonymous.Assemblr"
 | 
			
		||||
    },
 | 
			
		||||
    "android": {
 | 
			
		||||
      "adaptiveIcon": {
 | 
			
		||||
@@ -52,4 +50,4 @@
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,11 @@ module.exports = function (api) {
 | 
			
		||||
        presets: ['babel-preset-expo'],
 | 
			
		||||
        plugins: [
 | 
			
		||||
            'react-native-reanimated/plugin',
 | 
			
		||||
            'react-native-paper/babel'
 | 
			
		||||
        ]
 | 
			
		||||
            '@babel/plugin-proposal-nullish-coalescing-operator',
 | 
			
		||||
            '@babel/plugin-proposal-optional-chaining',
 | 
			
		||||
            '@babel/plugin-transform-arrow-functions',
 | 
			
		||||
            '@babel/plugin-transform-shorthand-properties',
 | 
			
		||||
            '@babel/plugin-transform-template-literals',
 | 
			
		||||
        ],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										130
									
								
								package.json
									
									
									
									
									
								
							
							
						
						@@ -9,61 +9,97 @@
 | 
			
		||||
    "web": "expo start --web"
 | 
			
		||||
  },
 | 
			
		||||
  "resolutions": {
 | 
			
		||||
    "react-native-reanimated": "3.3.0"
 | 
			
		||||
    "react": "19.0.0",
 | 
			
		||||
    "react-dom": "19.0.0",
 | 
			
		||||
    "react-native": "0.79.2",
 | 
			
		||||
    "@expo/config-plugins": "~10.0.0",
 | 
			
		||||
    "@expo/prebuild-config": "~9.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@expo/webpack-config": "^19.0.0",
 | 
			
		||||
    "@gorhom/bottom-sheet": "^4",
 | 
			
		||||
    "@react-native-community/datetimepicker": "7.2.0",
 | 
			
		||||
    "@react-native-picker/picker": "^2.5.1",
 | 
			
		||||
    "@react-navigation/bottom-tabs": "^6.5.8",
 | 
			
		||||
    "@react-navigation/native": "^6.1.7",
 | 
			
		||||
    "@reduxjs/toolkit": "^1.9.5",
 | 
			
		||||
    "@rneui/base": "^4.0.0-rc.7",
 | 
			
		||||
    "@rneui/themed": "^4.0.0-rc.8",
 | 
			
		||||
    "@shopify/flash-list": "1.4.3",
 | 
			
		||||
    "axios": "^1.5.0",
 | 
			
		||||
    "babel-plugin-module-resolver": "^5.0.0",
 | 
			
		||||
    "expo": "~49.0.8",
 | 
			
		||||
    "expo-application": "~5.3.0",
 | 
			
		||||
    "expo-build-properties": "~0.8.3",
 | 
			
		||||
    "expo-constants": "~14.4.2",
 | 
			
		||||
    "expo-dev-client": "~2.4.12",
 | 
			
		||||
    "expo-file-system": "~15.4.4",
 | 
			
		||||
    "expo-intent-launcher": "~10.7.0",
 | 
			
		||||
    "expo-secure-store": "~12.3.1",
 | 
			
		||||
    "expo-splash-screen": "~0.20.5",
 | 
			
		||||
    "expo-status-bar": "~1.6.0",
 | 
			
		||||
    "react": "18.2.0",
 | 
			
		||||
    "react-dom": "18.2.0",
 | 
			
		||||
    "react-native": "0.72.6",
 | 
			
		||||
    "react-native-gesture-handler": "~2.12.0",
 | 
			
		||||
    "@expo/webpack-config": "^19.0.1",
 | 
			
		||||
    "@gorhom/bottom-sheet": "^5.1.6",
 | 
			
		||||
    "@react-native-community/datetimepicker": "8.3.0",
 | 
			
		||||
    "@react-native-picker/picker": "2.11.0",
 | 
			
		||||
    "@react-navigation/bottom-tabs": "^6.6.1",
 | 
			
		||||
    "@react-navigation/native": "^6.1.18",
 | 
			
		||||
    "@reduxjs/toolkit": "^2.3.0",
 | 
			
		||||
    "@shopify/flash-list": "1.7.6",
 | 
			
		||||
    "@types/lodash": "^4.17.17",
 | 
			
		||||
    "axios": "^1.7.7",
 | 
			
		||||
    "eas-cli": "^13.0.0",
 | 
			
		||||
    "expo": "^53.0.9",
 | 
			
		||||
    "expo-application": "~6.1.4",
 | 
			
		||||
    "expo-av": "~15.1.4",
 | 
			
		||||
    "expo-build-properties": "~0.14.6",
 | 
			
		||||
    "expo-constants": "~17.1.6",
 | 
			
		||||
    "expo-crypto": "~14.1.4",
 | 
			
		||||
    "expo-dev-client": "~5.1.8",
 | 
			
		||||
    "expo-file-system": "~18.1.10",
 | 
			
		||||
    "expo-intent-launcher": "~12.1.4",
 | 
			
		||||
    "expo-secure-store": "~14.2.3",
 | 
			
		||||
    "expo-splash-screen": "~0.30.8",
 | 
			
		||||
    "expo-status-bar": "~2.2.3",
 | 
			
		||||
    "lodash": "^4.17.21",
 | 
			
		||||
    "prop-types": "^15.8.1",
 | 
			
		||||
    "react": "19.0.0",
 | 
			
		||||
    "react-dom": "19.0.0",
 | 
			
		||||
    "react-hook-form": "^7.57.0",
 | 
			
		||||
    "react-native": "0.79.2",
 | 
			
		||||
    "react-native-animatable": "^1.4.0",
 | 
			
		||||
    "react-native-bluetooth-classic": "^1.73.0-rc.13",
 | 
			
		||||
    "react-native-bluetooth-serial": "lucassouza16/react-native-bluetooth-serial",
 | 
			
		||||
    "react-native-gesture-handler": "~2.24.0",
 | 
			
		||||
    "react-native-image-pan-zoom": "^2.1.12",
 | 
			
		||||
    "react-native-image-zoom-viewer": "^3.0.1",
 | 
			
		||||
    "react-native-keyevent": "^0.3.1",
 | 
			
		||||
    "react-native-keyevent-expo-config-plugin": "^1.0.49",
 | 
			
		||||
    "react-native-keyevent": "^0.3.2",
 | 
			
		||||
    "react-native-modal": "^13.0.1",
 | 
			
		||||
    "react-native-paper": "^5.10.6",
 | 
			
		||||
    "react-native-paper": "^5.12.5",
 | 
			
		||||
    "react-native-picker-select": "^9.3.1",
 | 
			
		||||
    "react-native-progress": "^5.0.1",
 | 
			
		||||
    "react-native-progress-circle-updated": "^2.2.1",
 | 
			
		||||
    "react-native-radio-buttons-group": "^3.0.5",
 | 
			
		||||
    "react-native-reanimated": "3.3.0",
 | 
			
		||||
    "react-native-radio-buttons-group": "^3.1.0",
 | 
			
		||||
    "react-native-reanimated": "~3.17.4",
 | 
			
		||||
    "react-native-responsive-dimension": "^1.0.0",
 | 
			
		||||
    "react-native-responsive-dimensions": "^3.1.1",
 | 
			
		||||
    "react-native-responsive-fontsize": "^0.5.1",
 | 
			
		||||
    "react-native-safe-area-context": "4.6.3",
 | 
			
		||||
    "react-native-screens": "~3.22.0",
 | 
			
		||||
    "react-native-svg": "13.9.0",
 | 
			
		||||
    "react-native-toast-message": "^2.1.7",
 | 
			
		||||
    "react-native-vector-icons": "^10.0.0",
 | 
			
		||||
    "react-native-web": "~0.19.6",
 | 
			
		||||
    "react-native-webview": "13.2.2",
 | 
			
		||||
    "react-redux": "^8.1.2",
 | 
			
		||||
    "redux": "^4.2.1",
 | 
			
		||||
    "rn-openapp": "^2.1.2"
 | 
			
		||||
    "react-native-safe-area-context": "5.4.0",
 | 
			
		||||
    "react-native-screens": "~4.10.0",
 | 
			
		||||
    "react-native-serialport-bluetooth": "^0.4.11",
 | 
			
		||||
    "react-native-svg": "15.11.2",
 | 
			
		||||
    "react-native-tcp-socket": "^6.3.0",
 | 
			
		||||
    "react-native-toast-message": "^2.2.1",
 | 
			
		||||
    "react-native-vector-icons": "^10.2.0",
 | 
			
		||||
    "react-native-web": "^0.20.0",
 | 
			
		||||
    "react-native-webview": "13.13.5",
 | 
			
		||||
    "react-native-zpl-code": "^0.2.3",
 | 
			
		||||
    "react-redux": "^9.1.2",
 | 
			
		||||
    "redux": "^5.0.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@babel/core": "^7.20.0",
 | 
			
		||||
    "@types/react": "~18.2.14",
 | 
			
		||||
    "typescript": "^5.1.3"
 | 
			
		||||
    "@babel/core": "^7.26.0",
 | 
			
		||||
    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
 | 
			
		||||
    "@babel/plugin-proposal-optional-chaining": "^7.21.0",
 | 
			
		||||
    "@babel/plugin-transform-arrow-functions": "^7.24.7",
 | 
			
		||||
    "@babel/plugin-transform-shorthand-properties": "^7.24.7",
 | 
			
		||||
    "@babel/plugin-transform-template-literals": "^7.24.7",
 | 
			
		||||
    "@babel/preset-env": "^7.26.0",
 | 
			
		||||
    "@babel/runtime": "^7.25.7",
 | 
			
		||||
    "@react-native-community/cli": "^18.0.0",
 | 
			
		||||
    "@types/react": "~19.0.10",
 | 
			
		||||
    "babel-plugin-module-resolver": "^5.0.2",
 | 
			
		||||
    "typescript": "~5.8.3"
 | 
			
		||||
  },
 | 
			
		||||
  "private": true
 | 
			
		||||
  "expo": {
 | 
			
		||||
    "doctor": {
 | 
			
		||||
      "reactNativeDirectoryCheck": {
 | 
			
		||||
        "exclude": [
 | 
			
		||||
          "eas-cli",
 | 
			
		||||
          "prop-types",
 | 
			
		||||
          "react-native-vector-icons",
 | 
			
		||||
          "react-native-image-pan-zoom"
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						@@ -1,31 +1,23 @@
 | 
			
		||||
import {StyleSheet, Text, View} from 'react-native';
 | 
			
		||||
import {StyleSheet} from 'react-native';
 | 
			
		||||
import {Provider} from "react-redux";
 | 
			
		||||
 | 
			
		||||
import {useFonts} from 'expo-font';
 | 
			
		||||
import {store} from "./redux/store";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import React, {useEffect} from "react";
 | 
			
		||||
import CommonPage from "./screens/CommonPage/CommonPage";
 | 
			
		||||
import {BottomSheetModalProvider} from "@gorhom/bottom-sheet";
 | 
			
		||||
import {GestureHandlerRootView} from "react-native-gesture-handler";
 | 
			
		||||
import Toast from "react-native-toast-message";
 | 
			
		||||
import Constants from "expo-constants";
 | 
			
		||||
import KeyEvent from "react-native-keyevent";
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
    let [fontsLoading] = useFonts({
 | 
			
		||||
        // 'SF Pro Text': require('./assets/fonts/SF-Pro-Text-Regular.otf')
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    if (!fontsLoading)
 | 
			
		||||
        return <View><Text>Loading...</Text></View>
 | 
			
		||||
    return (
 | 
			
		||||
        <Provider store={store}>
 | 
			
		||||
            <>
 | 
			
		||||
            </>
 | 
			
		||||
            <GestureHandlerRootView style={{flex: 1}}>
 | 
			
		||||
                <BottomSheetModalProvider>
 | 
			
		||||
                    <CommonPage/>
 | 
			
		||||
 | 
			
		||||
                </BottomSheetModalProvider>
 | 
			
		||||
            </GestureHandlerRootView>
 | 
			
		||||
 | 
			
		||||
        </Provider>
 | 
			
		||||
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,10 @@
 | 
			
		||||
import axios, {AxiosHeaders, AxiosRequestConfig, AxiosRequestHeaders, InternalAxiosRequestConfig} from 'axios';
 | 
			
		||||
import * as SecureStore from 'expo-secure-store';
 | 
			
		||||
import {useDispatch} from "react-redux";
 | 
			
		||||
import {logout} from "../features/auth/authSlice";
 | 
			
		||||
import {store} from "../redux/store";
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
 | 
			
		||||
export const baseUrl = 'https://assemblr.denco.store';
 | 
			
		||||
// export const baseUrl = 'http://192.168.1.101:5000';
 | 
			
		||||
const apiClient = axios.create({
 | 
			
		||||
    baseURL: baseUrl
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
apiClient.interceptors.request.use(async (config) => {
 | 
			
		||||
    const accessToken = await SecureStore.getItemAsync('accessToken');
 | 
			
		||||
    if (!config.headers) {
 | 
			
		||||
        config.headers = new AxiosHeaders();
 | 
			
		||||
    }
 | 
			
		||||
    if (accessToken) {
 | 
			
		||||
        config.headers.set('Authorization', `Bearer ${accessToken}`, true);
 | 
			
		||||
    }
 | 
			
		||||
    config.validateStatus = (status) => {
 | 
			
		||||
        if (status == 401) {
 | 
			
		||||
            SecureStore.deleteItemAsync('accessToken');
 | 
			
		||||
            store.dispatch(logout());
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return config;
 | 
			
		||||
}, function (error) {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default apiClient;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,20 @@
 | 
			
		||||
import apiClient from "./apiClient";
 | 
			
		||||
import {Assembly} from "../types/assembly";
 | 
			
		||||
import {closeCancelAssemblyModal} from "../features/cancelAssemblyModal/cancelAssemblyModalSlice";
 | 
			
		||||
 | 
			
		||||
const router = '/assembly';
 | 
			
		||||
 | 
			
		||||
export type CreateAssemblyResponse = {
 | 
			
		||||
    ok: boolean,
 | 
			
		||||
    message: string,
 | 
			
		||||
    assemblyId: number,
 | 
			
		||||
    statusCode: AssemblyCreationStatusCode,
 | 
			
		||||
    userName?: string
 | 
			
		||||
}
 | 
			
		||||
const assemblyApi = {
 | 
			
		||||
    create: async (orderId: number): Promise<{
 | 
			
		||||
        ok: boolean,
 | 
			
		||||
        message: string,
 | 
			
		||||
        assemblyId: number,
 | 
			
		||||
        statusCode: AssemblyCreationStatusCode,
 | 
			
		||||
        userName?: string
 | 
			
		||||
    }> => {
 | 
			
		||||
    create: async (orderId: number): Promise<CreateAssemblyResponse> => {
 | 
			
		||||
        let response = await apiClient.post(`${router}/create`, {orderId});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    close: async (assemblyId: number): Promise<{ ok: boolean, message: string }> => {
 | 
			
		||||
    close: async (assemblyId: number): Promise<{ ok: boolean, message: string, reward: number }> => {
 | 
			
		||||
        let response = await apiClient.post(`${router}/close`, {assemblyId});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
@@ -39,9 +38,21 @@ const assemblyApi = {
 | 
			
		||||
        let response = await apiClient.post(`${router}/confirm`, {assemblyId});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    confirmCurrent: async (): Promise<{ ok: boolean, message: string }> => {
 | 
			
		||||
        let response = await apiClient.post(`${router}/confirmCurrent`);
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    cancelById: async (assemblyId: number): Promise<{ ok: boolean, message: string }> => {
 | 
			
		||||
        let response = await apiClient.post(`${router}/cancelById`, {assemblyId});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    attachCrpt: async (orderProductId: number, crpt: string): Promise<{ ok: boolean, message: string }> => {
 | 
			
		||||
        let response = await apiClient.post(`${router}/attachCrpt`, {orderProductId, crpt});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    needCrpt: async (orderProductId: number): Promise<{ needCrpt: boolean }> => {
 | 
			
		||||
        let response = await apiClient.get(`${router}/needCrpt`, {params: {orderProductId}});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								src/api/balanceApi.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
import {BalanceInfo, BalanceTransaction} from "../types/balance";
 | 
			
		||||
import apiClient from "./apiClient";
 | 
			
		||||
 | 
			
		||||
const router = '/balance';
 | 
			
		||||
const balanceApi = {
 | 
			
		||||
    getTransactions: async (page: number): Promise<{ balanceTransactions: BalanceTransaction[] }> => {
 | 
			
		||||
        const response = await apiClient.get(`${router}/transactions`, {params: {page}});
 | 
			
		||||
        return response.data;
 | 
			
		||||
    },
 | 
			
		||||
    getBalanceInfo: async (): Promise<BalanceInfo> => {
 | 
			
		||||
        const response = await apiClient.get(`${router}/info`);
 | 
			
		||||
        return response.data;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default balanceApi;
 | 
			
		||||
@@ -1,14 +1,17 @@
 | 
			
		||||
import apiClient from "./apiClient";
 | 
			
		||||
import {Order} from "../types/order";
 | 
			
		||||
import * as inspector from "inspector";
 | 
			
		||||
import {OrderStatus} from "../features/ordersFilter/ordersFilterSlice";
 | 
			
		||||
import {ShippingWarehouse} from "../types/shippingWarehouse";
 | 
			
		||||
import {City} from "../types/city";
 | 
			
		||||
 | 
			
		||||
const router = '/orders';
 | 
			
		||||
 | 
			
		||||
const ordersApi = {
 | 
			
		||||
    getOrders: async (page: number, orderBy: string, desc: boolean, shipmentDate: string, status: number, shipmentWarehouseId: number): Promise<Order[]> => {
 | 
			
		||||
    getOrders: async ({page, orderBy, desc, status, shipmentDate, shipmentWarehouseId}: {
 | 
			
		||||
        page: number,
 | 
			
		||||
        orderBy: string,
 | 
			
		||||
        desc: boolean,
 | 
			
		||||
        shipmentDate: string,
 | 
			
		||||
        status: number,
 | 
			
		||||
        shipmentWarehouseId: number
 | 
			
		||||
    }): Promise<Order[]> => {
 | 
			
		||||
        const params = {
 | 
			
		||||
            page: page,
 | 
			
		||||
            orderBy: orderBy,
 | 
			
		||||
@@ -22,18 +25,14 @@ const ordersApi = {
 | 
			
		||||
    },
 | 
			
		||||
    getOrdersByProduct: async (params: {
 | 
			
		||||
        productId: number,
 | 
			
		||||
        orderBy: "createdOn" | "shipmentDate",
 | 
			
		||||
        orderBy: string,
 | 
			
		||||
        desc: boolean,
 | 
			
		||||
        status: OrderStatus,
 | 
			
		||||
        shipmentDate: string,
 | 
			
		||||
        shippingWarehouse: ShippingWarehouse,
 | 
			
		||||
        city: City
 | 
			
		||||
        shippingWarehouseId: number,
 | 
			
		||||
    }): Promise<Order[]> => {
 | 
			
		||||
        let response = await apiClient.get(`${router}/getByProductId`, {
 | 
			
		||||
            params: {
 | 
			
		||||
                ...params,
 | 
			
		||||
                shippingWarehouse: params.shippingWarehouse.id,
 | 
			
		||||
                city: params.city.id
 | 
			
		||||
                shippingWarehouse: params.shippingWarehouseId,
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return response.data;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,9 @@ import apiClient from "./apiClient";
 | 
			
		||||
const router = '/printing';
 | 
			
		||||
 | 
			
		||||
const printingApi = {
 | 
			
		||||
    getLabel: async (orderId: number): Promise<Uint8Array> => {
 | 
			
		||||
        let response = await apiClient.get(`${router}/getLabel?orderId=${orderId}`, {responseType: 'arraybuffer'});
 | 
			
		||||
        return new Uint8Array(response.data);
 | 
			
		||||
 | 
			
		||||
    getLabel: async (orderId: number): Promise<{ labels: string[] }> => {
 | 
			
		||||
        let response = await apiClient.get(`${router}/getLabel?orderId=${orderId}&format=zpl`);
 | 
			
		||||
        return response.data
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
export default printingApi;
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/reward.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 18 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/scanner.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/icons/settings/check.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.8 KiB  | 
							
								
								
									
										93
									
								
								src/components/Animations/AnimationsView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,93 @@
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import {StyleSheet, View, Image} from "react-native";
 | 
			
		||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import * as Animatable from 'react-native-animatable';
 | 
			
		||||
import DText from "../DText/DText";
 | 
			
		||||
import {useSelector} from "react-redux";
 | 
			
		||||
import {RootState, useAppDispatch} from "../../redux/store";
 | 
			
		||||
import {hideReward} from "../../features/animations/animationsSlice";
 | 
			
		||||
 | 
			
		||||
// const width = responsiveWidth(20)
 | 
			
		||||
const AnimationsView: FC = () => {
 | 
			
		||||
    const dispatch = useAppDispatch();
 | 
			
		||||
    const state = useSelector((state: RootState) => state.animations);
 | 
			
		||||
    const [currentAnimation, setCurrentAnimation] = useState('bounceInRight');
 | 
			
		||||
    const [animationStage, setAnimationStage] = useState('in'); // Управляет текущей стадией анимации
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        // После завершения анимации входа, начинаем анимацию выхода
 | 
			
		||||
        if (animationStage === 'out') {
 | 
			
		||||
            setCurrentAnimation('bounceOutRight');
 | 
			
		||||
        }
 | 
			
		||||
    }, [animationStage]);
 | 
			
		||||
 | 
			
		||||
    const onAnimationEnd = () => {
 | 
			
		||||
        if (animationStage === 'in') {
 | 
			
		||||
            // После завершения анимации входа, переходим к анимации выхода
 | 
			
		||||
            setAnimationStage('out');
 | 
			
		||||
        } else if (animationStage === "out") {
 | 
			
		||||
            dispatch(hideReward());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const startAnimation = () => {
 | 
			
		||||
        setCurrentAnimation("bounceInRight");
 | 
			
		||||
        setAnimationStage('in');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (state.isRewardAnimationVisible)
 | 
			
		||||
            startAnimation();
 | 
			
		||||
 | 
			
		||||
    }, [state.isRewardAnimationVisible]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <View style={{...style.container, display: state.isRewardAnimationVisible ? "flex" : "none"}}>
 | 
			
		||||
            <Animatable.View
 | 
			
		||||
                style={{
 | 
			
		||||
                    backgroundColor: "white",
 | 
			
		||||
                    borderRadius: responsiveWidth(3),
 | 
			
		||||
                    // width: width,
 | 
			
		||||
                    paddingHorizontal: responsiveWidth(2),
 | 
			
		||||
                    display: "flex",
 | 
			
		||||
                    flexDirection: "row",
 | 
			
		||||
                    alignItems: "center",
 | 
			
		||||
                    gap: responsiveWidth(1),
 | 
			
		||||
                    zIndex: 1,
 | 
			
		||||
                    elevation: 10,
 | 
			
		||||
                    justifyContent: "center"
 | 
			
		||||
                }}
 | 
			
		||||
                animation={currentAnimation}
 | 
			
		||||
                duration={1000} // Продолжительность анимации
 | 
			
		||||
                easing="ease-in-out" // Тип анимации
 | 
			
		||||
                iterationCount={1} // Бесконечное повторение
 | 
			
		||||
                onAnimationEnd={onAnimationEnd}
 | 
			
		||||
            >
 | 
			
		||||
                <View style={{
 | 
			
		||||
                    height: responsiveHeight(5)
 | 
			
		||||
                }}>
 | 
			
		||||
                    <Image
 | 
			
		||||
                        style={{
 | 
			
		||||
                            height: responsiveHeight(5),
 | 
			
		||||
                            width:responsiveWidth(5),
 | 
			
		||||
                            resizeMode: "contain"
 | 
			
		||||
                        }}
 | 
			
		||||
                        source={require('assets/icons/reward.png')}/>
 | 
			
		||||
                </View>
 | 
			
		||||
                <DText>+{state.rewardAmount.toLocaleString('ru-RU')}₽</DText>
 | 
			
		||||
 | 
			
		||||
            </Animatable.View>
 | 
			
		||||
        </View>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const style = StyleSheet.create({
 | 
			
		||||
    container: {
 | 
			
		||||
        position: "absolute",
 | 
			
		||||
        right: 0,
 | 
			
		||||
        top: 0,
 | 
			
		||||
        marginTop: responsiveHeight(10),
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
export default AnimationsView;
 | 
			
		||||
@@ -5,7 +5,7 @@ import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import DText from "../DText/DText";
 | 
			
		||||
import DTitle from "../DTitle/DTitle";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
export type BasicButtonProps = {
 | 
			
		||||
    label: string;
 | 
			
		||||
    style?: StyleProp<ViewStyle>;
 | 
			
		||||
    containerStyle?: StyleProp<ViewStyle>;
 | 
			
		||||
@@ -14,7 +14,7 @@ type Props = {
 | 
			
		||||
    disabled?: boolean
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const BasicButton: FC<Props> = ({label, onPress, containerStyle, style, isUnset = false, disabled = false}) => {
 | 
			
		||||
const BasicButton: FC<BasicButtonProps> = ({label, onPress, containerStyle, style, isUnset = false, disabled = false}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <TouchableOpacity style={containerStyle} disabled={disabled} onPress={onPress}>
 | 
			
		||||
            <View style={[styles.container, style, disabled ? {backgroundColor: "#A0A0A0"} : {}, containerStyle]}>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
import React, {FC, ReactElement} from "react";
 | 
			
		||||
import {StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle} from 'react-native';
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import React, {FC, ReactNode} from "react";
 | 
			
		||||
import {StyleProp, StyleSheet, TextStyle} from 'react-native';
 | 
			
		||||
import DText from "../DText/DText";
 | 
			
		||||
import {responsiveScreenFontSize, responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import {responsiveScreenFontSize} from "react-native-responsive-dimensions";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    children: string;
 | 
			
		||||
    children: ReactNode;
 | 
			
		||||
    style?: StyleProp<TextStyle>;
 | 
			
		||||
}
 | 
			
		||||
const DTitle: FC<Props> = ({children, style}) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ const Hyperlink: React.FC<HyperlinkProps> = ({url, children}) => {
 | 
			
		||||
            if (supported) {
 | 
			
		||||
                Linking.openURL(url);
 | 
			
		||||
            } else {
 | 
			
		||||
                console.log("Don't know how to open URI: " + url);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,13 @@ import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensi
 | 
			
		||||
import DTitle from "../../DTitle/DTitle";
 | 
			
		||||
import BasicButton from "../../BasicButton/BasicButton";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
export type AcceptModalProps = {
 | 
			
		||||
    visible: boolean;
 | 
			
		||||
    text: string;
 | 
			
		||||
    onAccepted: () => void;
 | 
			
		||||
    onRefused: () => void;
 | 
			
		||||
}
 | 
			
		||||
const AcceptModal: FC<Props> = ({visible, text, onAccepted, onRefused}) => {
 | 
			
		||||
const AcceptModal: FC<AcceptModalProps> = ({visible, text, onAccepted, onRefused}) => {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Modal isVisible={visible}>
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,6 @@ const ImageZoomModal: FC = () => {
 | 
			
		||||
                </View>
 | 
			
		||||
                <ImageViewer
 | 
			
		||||
                    imageUrls={imageUrls.map(imageUrl => {
 | 
			
		||||
                        console.log(imageUrl)
 | 
			
		||||
                        return {
 | 
			
		||||
                            url: imageUrl
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,9 @@ const SelectProductElement: FC<Props> = React.memo(({product, onPress}) => {
 | 
			
		||||
                    <View style={styles.descriptionContent}>
 | 
			
		||||
 | 
			
		||||
                        <DText>{product.productName}</DText>
 | 
			
		||||
                        <DText style={{textAlign: "justify"}}>{}</DText>
 | 
			
		||||
                        <DText>Заказов: {product.ordersCount}</DText>
 | 
			
		||||
                        <DText style={{textAlign: "justify"}}>""</DText>
 | 
			
		||||
 | 
			
		||||
                        <DText>Артикул DENCO: {product.dencoArticle}</DText>
 | 
			
		||||
                    </View>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								src/components/Modals/SortingModal/SortingButton.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,19 @@
 | 
			
		||||
import {View} from "react-native";
 | 
			
		||||
import {RadioButton} from "react-native-paper";
 | 
			
		||||
import DText from "../../DText/DText";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    value: string;
 | 
			
		||||
    label: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SortingButton: FC<Props> = ({value, label}) => {
 | 
			
		||||
    return (<View style={{display: "flex", flexDirection: "row", alignItems: "center"}}>
 | 
			
		||||
            <RadioButton value={value}/>
 | 
			
		||||
            <DText>{label}</DText>
 | 
			
		||||
        </View>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default SortingButton;
 | 
			
		||||
							
								
								
									
										24
									
								
								src/components/Modals/SortingModal/SortingButtons.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,24 @@
 | 
			
		||||
import {ControllerRenderProps} from 'react-hook-form';
 | 
			
		||||
import {FilterState} from "../../../features/filterSlice/filterSlice";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {RadioButton} from "react-native-paper";
 | 
			
		||||
import SortingButton from "./SortingButton";
 | 
			
		||||
import {View} from 'react-native';
 | 
			
		||||
 | 
			
		||||
type Props = ControllerRenderProps<FilterState, "sorting">;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const SortingButtons: FC<Props> = ({value, onChange, disabled}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <RadioButton.Group value={value} onValueChange={onChange}>
 | 
			
		||||
            <View style={{display: "flex", flexDirection: "column"}}>
 | 
			
		||||
                <SortingButton value={"shipment_date_desc"} label={"Дата отгрузки по возрастанию"}/>
 | 
			
		||||
                <SortingButton value={"shipment_date_asc"} label={"Дата отгрузки по убыванию"}/>
 | 
			
		||||
                <SortingButton value={"created_date_desc"} label={"Дата создание по возрастанию"}/>
 | 
			
		||||
                <SortingButton value={"created_date_asc"} label={"Дата создания по убыванию"}/>
 | 
			
		||||
            </View>
 | 
			
		||||
 | 
			
		||||
        </RadioButton.Group>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
export default SortingButtons;
 | 
			
		||||
@@ -1,185 +1,37 @@
 | 
			
		||||
import {FC, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
 | 
			
		||||
import {BottomSheetModal} from "@gorhom/bottom-sheet";
 | 
			
		||||
import {disableDim, enableDim} from "../../../features/interface/interfaceSlice";
 | 
			
		||||
import {StyleSheet, View} from "react-native";
 | 
			
		||||
import BasicButton from "../../BasicButton/BasicButton";
 | 
			
		||||
import {useDispatch, useSelector} from "react-redux";
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import RadioGroup from 'react-native-radio-buttons-group';
 | 
			
		||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import {blue} from "../../../css/colors";
 | 
			
		||||
import {Picker} from "@react-native-picker/picker";
 | 
			
		||||
import DateTimePicker from '@react-native-community/datetimepicker';
 | 
			
		||||
import {RootState} from "../../../redux/store";
 | 
			
		||||
import {
 | 
			
		||||
    closeOrdersFilterModal,
 | 
			
		||||
    orderStatuses, setCity,
 | 
			
		||||
    setDesc,
 | 
			
		||||
    setOrderBy, setShipmentDate, setShippingWarehouse, setStatus
 | 
			
		||||
} from "../../../features/ordersFilter/ordersFilterSlice";
 | 
			
		||||
import ShippingWarehouseSelect from "../../ShippingWarehouseSelect/ShippingWarehouseSelect";
 | 
			
		||||
import CitySelect from "../../CitySelect/CitySelect";
 | 
			
		||||
import {useEffect, useRef} from "react";
 | 
			
		||||
import {BottomSheetModal, BottomSheetView} from "@gorhom/bottom-sheet";
 | 
			
		||||
import {useSelector} from "react-redux";
 | 
			
		||||
import {RootState, useAppDispatch} from "../../../redux/store";
 | 
			
		||||
import {closeFilter} from "../../../features/filterSlice/filterSlice";
 | 
			
		||||
import SortingModalBody from "./SortingModalBody";
 | 
			
		||||
import {View} from "react-native";
 | 
			
		||||
 | 
			
		||||
export type SortingModalHandles = {
 | 
			
		||||
    present: () => void;
 | 
			
		||||
    dismiss: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type SortingModalElement = {
 | 
			
		||||
    id: string;
 | 
			
		||||
    label: string;
 | 
			
		||||
    value: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const createRadioButton = (element: SortingModalElement) => {
 | 
			
		||||
    return {
 | 
			
		||||
        id: element.id,
 | 
			
		||||
        label: element.label,
 | 
			
		||||
        value: element.value,
 | 
			
		||||
        size: RFPercentage(5),
 | 
			
		||||
        color: blue,
 | 
			
		||||
        labelStyle: {
 | 
			
		||||
            fontSize: responsiveWidth(3),
 | 
			
		||||
            fontWeight: "500" as const
 | 
			
		||||
        },
 | 
			
		||||
        borderSize: RFPercentage(0.5)
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SortingModal = () => {
 | 
			
		||||
    const state = useSelector((state: RootState) => state.ordersFilter);
 | 
			
		||||
    const shipmentWarehouseSelectorState = useSelector((state: RootState) => state.shippingWarehouseSelect);
 | 
			
		||||
    const citySelectorState = useSelector((state: RootState) => state.citySelect);
 | 
			
		||||
 | 
			
		||||
    const elements = [
 | 
			
		||||
        {id: 'createdOnAsc', value: 'createdOnAsc', label: 'Дата создания по возрастанию'},
 | 
			
		||||
        {id: 'createdOnDesc', value: 'createdOnDesc', label: 'Дата создания по убыванию'},
 | 
			
		||||
        {id: 'shipmentDateAsc', value: 'shipmentDateAsc', label: 'Дата отгрузки по возрастанию'},
 | 
			
		||||
        {id: 'shipmentDateDesc', value: 'shipmentDateDesc', label: 'Дата отгрузки по убыванию'},
 | 
			
		||||
    ];
 | 
			
		||||
    const [showShipmentPicker, setShowShipmentPicker] = useState(false);
 | 
			
		||||
    const snapPoints = useMemo(() => ['60%', '60%'], []);
 | 
			
		||||
    const dispatch = useDispatch();
 | 
			
		||||
export const SortingModal = () => {
 | 
			
		||||
    const dispatch = useAppDispatch();
 | 
			
		||||
    const modalRef = useRef<BottomSheetModal>(null);
 | 
			
		||||
    const dismiss = () => {
 | 
			
		||||
    const visible = useSelector((state: RootState) => state.filter.visible);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!modalRef.current) return;
 | 
			
		||||
        dispatch(disableDim());
 | 
			
		||||
        modalRef.current.dismiss();
 | 
			
		||||
    }
 | 
			
		||||
    const present = () => {
 | 
			
		||||
        if (!modalRef.current) return;
 | 
			
		||||
        modalRef.current.present();
 | 
			
		||||
        dispatch(enableDim());
 | 
			
		||||
    }
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (state.isVisible) present();
 | 
			
		||||
        else dismiss();
 | 
			
		||||
    }, [state.isVisible]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        dispatch(setShippingWarehouse(shipmentWarehouseSelectorState.selectedShippingWarehouse));
 | 
			
		||||
    }, [shipmentWarehouseSelectorState.selectedShippingWarehouse]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        dispatch(setCity(citySelectorState.selectedCity));
 | 
			
		||||
    }, [citySelectorState.selectedCity]);
 | 
			
		||||
        if (visible) {
 | 
			
		||||
            modalRef.current.present();
 | 
			
		||||
        } else {
 | 
			
		||||
            modalRef.current.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
    }, [visible]);
 | 
			
		||||
    return (
 | 
			
		||||
        <BottomSheetModal
 | 
			
		||||
            onDismiss={() => dispatch(closeFilter())}
 | 
			
		||||
            ref={modalRef}
 | 
			
		||||
            snapPoints={snapPoints}
 | 
			
		||||
            onDismiss={() => {
 | 
			
		||||
                dispatch(disableDim());
 | 
			
		||||
                dispatch(closeOrdersFilterModal())
 | 
			
		||||
            }}>
 | 
			
		||||
            <View style={styles.container}>
 | 
			
		||||
                <View style={styles.content}>
 | 
			
		||||
                    <RadioGroup selectedId={state.orderBy + (state.desc ? "Desc" : "Asc")}
 | 
			
		||||
                                onPress={(event) => {
 | 
			
		||||
                                    const orderRegex = /(Asc|Desc)$/;
 | 
			
		||||
                                    const orderMatch = event.match(orderRegex);
 | 
			
		||||
                                    if (!orderMatch) return;
 | 
			
		||||
                                    const isDesc = orderMatch[0] === 'Desc';
 | 
			
		||||
                                    const orderByField = event.replace(orderRegex, '');
 | 
			
		||||
                                    if (!["createdOn", "shipmentDate"].includes(orderByField)) return
 | 
			
		||||
                                    dispatch(setDesc(isDesc));
 | 
			
		||||
                                    dispatch(setOrderBy(orderByField as "createdOn" | "shipmentDate"));
 | 
			
		||||
        >
 | 
			
		||||
            <BottomSheetView>
 | 
			
		||||
                <View>
 | 
			
		||||
 | 
			
		||||
                                }}
 | 
			
		||||
                                containerStyle={styles.radioButtons}
 | 
			
		||||
                                radioButtons={elements.map(createRadioButton)}/>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    <View style={styles.selectors}>
 | 
			
		||||
                        {/*<View style={styles.selector}>*/}
 | 
			
		||||
                        {/*    <Picker selectedValue={state.status}*/}
 | 
			
		||||
                        {/*            onValueChange={(value, event) => dispatch(setStatus(value))}>*/}
 | 
			
		||||
                        {/*        {orderStatuses.map((status) => {*/}
 | 
			
		||||
                        {/*            return (*/}
 | 
			
		||||
                        {/*                <Picker.Item*/}
 | 
			
		||||
                        {/*                    key={status.key}*/}
 | 
			
		||||
                        {/*                    label={status.label}*/}
 | 
			
		||||
                        {/*                    value={status.key}*/}
 | 
			
		||||
                        {/*                    style={{fontSize: responsiveWidth(3)}}*/}
 | 
			
		||||
                        {/*                />*/}
 | 
			
		||||
                        {/*            )*/}
 | 
			
		||||
                        {/*        })}*/}
 | 
			
		||||
                        {/*    </Picker>*/}
 | 
			
		||||
                        {/*</View>*/}
 | 
			
		||||
 | 
			
		||||
                        <ShippingWarehouseSelect/>
 | 
			
		||||
                        {/*<CitySelect/>*/}
 | 
			
		||||
                    </View>
 | 
			
		||||
 | 
			
		||||
                    {/*<BasicButton onPress={() => setShowShipmentPicker(oldValue => !oldValue)}*/}
 | 
			
		||||
                    {/*             label={"Выбрать дату отгрузки"}/>*/}
 | 
			
		||||
                    {/*{showShipmentPicker &&*/}
 | 
			
		||||
                    {/*    <DateTimePicker value={new Date(state.shipmentDate)}*/}
 | 
			
		||||
                    {/*                    onChange={(event) => {*/}
 | 
			
		||||
                    {/*                        if (!event.nativeEvent.timestamp) return;*/}
 | 
			
		||||
                    {/*                        setShowShipmentPicker(false);*/}
 | 
			
		||||
                    {/*                        if (event.type === 'set') {*/}
 | 
			
		||||
                    {/*                            const selectedDate = new Date(event.nativeEvent.timestamp);*/}
 | 
			
		||||
                    {/*                            dispatch(setShipmentDate(selectedDate.toISOString()));*/}
 | 
			
		||||
                    {/*                        }*/}
 | 
			
		||||
                    {/*                    }}/>}*/}
 | 
			
		||||
                    <SortingModalBody/>
 | 
			
		||||
                </View>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                <BasicButton label={"Закрыть"} style={styles.button} onPress={() => {
 | 
			
		||||
                    dispatch(closeOrdersFilterModal());
 | 
			
		||||
                }}/>
 | 
			
		||||
 | 
			
		||||
            </View>
 | 
			
		||||
            </BottomSheetView>
 | 
			
		||||
        </BottomSheetModal>
 | 
			
		||||
    )
 | 
			
		||||
};
 | 
			
		||||
const styles = StyleSheet.create({
 | 
			
		||||
    container: {
 | 
			
		||||
        width: "100%",
 | 
			
		||||
        height: "100%",
 | 
			
		||||
        flex: 1,
 | 
			
		||||
        padding: RFPercentage(3),
 | 
			
		||||
        flexDirection: "column",
 | 
			
		||||
        justifyContent: "space-between",
 | 
			
		||||
        rowGap: responsiveHeight(1)
 | 
			
		||||
    },
 | 
			
		||||
    radioButtons: {
 | 
			
		||||
        alignItems: "flex-start"
 | 
			
		||||
    },
 | 
			
		||||
    content: {
 | 
			
		||||
        rowGap: responsiveHeight(1)
 | 
			
		||||
    },
 | 
			
		||||
    button: {
 | 
			
		||||
 | 
			
		||||
        marginTop: "auto"
 | 
			
		||||
    },
 | 
			
		||||
    selectors: {
 | 
			
		||||
        rowGap: responsiveHeight(1)
 | 
			
		||||
    },
 | 
			
		||||
    selector: {
 | 
			
		||||
        borderWidth: responsiveWidth(0.1),
 | 
			
		||||
        borderRadius: responsiveWidth(1)
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default SortingModal;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								src/components/Modals/SortingModal/SortingModalBody.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,43 @@
 | 
			
		||||
import {closeFilter, FilterState, setFilterState} from "../../../features/filterSlice/filterSlice";
 | 
			
		||||
import {Controller, useForm} from "react-hook-form";
 | 
			
		||||
import {Button, View} from "react-native";
 | 
			
		||||
import ShippingWarehouseSelect from "../../ShippingWarehouseSelect/ShippingWarehouseSelect";
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import SortingButtons from "./SortingButtons";
 | 
			
		||||
import {useSelector} from "react-redux";
 | 
			
		||||
import {RootState, useAppDispatch} from "../../../redux/store";
 | 
			
		||||
 | 
			
		||||
const SortingModalBody = () => {
 | 
			
		||||
    const currentState = useSelector((state: RootState) => state.filter.state);
 | 
			
		||||
    const dispatch = useAppDispatch();
 | 
			
		||||
    const {control, handleSubmit} = useForm<FilterState>({
 | 
			
		||||
        defaultValues: currentState,
 | 
			
		||||
    })
 | 
			
		||||
    const onSubmit = (data: FilterState) => {
 | 
			
		||||
        dispatch(setFilterState(data));
 | 
			
		||||
        dispatch(closeFilter())
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <View style={{
 | 
			
		||||
            padding: RFPercentage(1),
 | 
			
		||||
            display: "flex",
 | 
			
		||||
            flexDirection: "column",
 | 
			
		||||
            gap: RFPercentage(1),
 | 
			
		||||
        }}>
 | 
			
		||||
 | 
			
		||||
            <Controller
 | 
			
		||||
                name={"sorting"}
 | 
			
		||||
                control={control}
 | 
			
		||||
                render={({field}) => (<SortingButtons {...field}/>)}
 | 
			
		||||
            />
 | 
			
		||||
            <Controller control={control} name={"shippingWarehouseId"}
 | 
			
		||||
                        render={({field}) => (
 | 
			
		||||
                            <ShippingWarehouseSelect
 | 
			
		||||
                                controllerProps={field}/>)}/>
 | 
			
		||||
            <Button title={"Применить"} onPress={handleSubmit(onSubmit)}/>
 | 
			
		||||
        </View>
 | 
			
		||||
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default SortingModalBody;
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import {FC, useEffect, useRef} from "react";
 | 
			
		||||
import {GestureResponderEvent, StyleSheet, Text, TextInput, View} from "react-native";
 | 
			
		||||
import {StyleSheet, TextInput, View} from "react-native";
 | 
			
		||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import Modal from "react-native-modal";
 | 
			
		||||
@@ -11,15 +11,18 @@ import {closeScanModal, setScannedData} from "../../features/scanModal/scanModal
 | 
			
		||||
 | 
			
		||||
const ScanModal: FC = () => {
 | 
			
		||||
    const inputRef = useRef<TextInput | null>(null);
 | 
			
		||||
    const visible = useSelector((state: RootState) => state.scanModal.isVisible);
 | 
			
		||||
    const scannerState = useSelector((state: RootState) => state.scanner);
 | 
			
		||||
    const state = useSelector((state: RootState) => state.scanModal);
 | 
			
		||||
    const getDefaultLabel = () => "Наведите сканер на штрихкод товара или заказа";
 | 
			
		||||
    const dispatch = useDispatch();
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (visible) inputRef.current?.focus();
 | 
			
		||||
    }, [visible]);
 | 
			
		||||
        if (state.isVisible) inputRef.current?.focus();
 | 
			
		||||
    }, [state.isVisible]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Modal isVisible={visible}>
 | 
			
		||||
        <Modal isVisible={state.isVisible}>
 | 
			
		||||
            <View style={styles.container}>
 | 
			
		||||
                <DText style={styles.text}>Наведите сканер на штрихкод товара или заказа</DText>
 | 
			
		||||
                <DText style={styles.text}>{state.customLabel || getDefaultLabel()}</DText>
 | 
			
		||||
                <BasicButton onPress={() => {
 | 
			
		||||
                    dispatch(closeScanModal());
 | 
			
		||||
                }} style={styles.cancelButton} label={"Отмена"}/>
 | 
			
		||||
@@ -31,7 +34,7 @@ const ScanModal: FC = () => {
 | 
			
		||||
                    style={styles.pseudoInput}
 | 
			
		||||
                    ref={inputRef}
 | 
			
		||||
                    autoFocus={true}
 | 
			
		||||
                    showSoftInputOnFocus={false}
 | 
			
		||||
                    // showSoftInputOnFocus={false}
 | 
			
		||||
                />
 | 
			
		||||
            </View>
 | 
			
		||||
        </Modal>
 | 
			
		||||
@@ -60,7 +63,6 @@ const styles = StyleSheet.create({
 | 
			
		||||
        width: responsiveWidth(30)
 | 
			
		||||
    },
 | 
			
		||||
    pseudoInput: {
 | 
			
		||||
        backgroundColor: "red",
 | 
			
		||||
        opacity: 0,
 | 
			
		||||
        position: "absolute",
 | 
			
		||||
        zIndex: -1
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ const SearchBar: FC<Props> = ({onSearch, onProductSelected}) => {
 | 
			
		||||
            }} style={styles.scanButton} label={"Поиск"}/>
 | 
			
		||||
            <View style={styles.scanImageWrapper}>
 | 
			
		||||
                <TouchableOpacity onPress={() => {
 | 
			
		||||
                    dispatch(openScanModal());
 | 
			
		||||
                    dispatch(openScanModal({customLabel: undefined, data: undefined}));
 | 
			
		||||
                }}>
 | 
			
		||||
                    <Image style={styles.scanImage} source={require('assets/icons/scan.png')}/>
 | 
			
		||||
                </TouchableOpacity>
 | 
			
		||||
@@ -101,6 +101,7 @@ const styles = StyleSheet.create({
 | 
			
		||||
        borderBottomLeftRadius: responsiveWidth(1),
 | 
			
		||||
        paddingLeft: responsiveHeight(2),
 | 
			
		||||
        fontSize: RFPercentage(2),
 | 
			
		||||
        color:"black",
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,40 @@
 | 
			
		||||
import {FC, useEffect} from "react";
 | 
			
		||||
import {useDispatch, useSelector} from "react-redux";
 | 
			
		||||
import {RootState} from "../../redux/store";
 | 
			
		||||
import {Picker} from "@react-native-picker/picker";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select';
 | 
			
		||||
import {ControllerRenderProps} from "react-hook-form";
 | 
			
		||||
import {FilterState} from "../../features/filterSlice/filterSlice";
 | 
			
		||||
import {ShippingWarehouse} from "../../types/shippingWarehouse";
 | 
			
		||||
import generalApi from "../../api/generalApi";
 | 
			
		||||
import {
 | 
			
		||||
    initializeShippingWarehouseSelect,
 | 
			
		||||
    selectShippingWarehouse
 | 
			
		||||
} from "../../features/shippingWarehouseSelect/shippingWarehouseSelectSlice";
 | 
			
		||||
import {responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import {View} from "react-native";
 | 
			
		||||
 | 
			
		||||
const ShippingWarehouseSelect: FC = () => {
 | 
			
		||||
    const state = useSelector((state: RootState) => state.shippingWarehouseSelect);
 | 
			
		||||
    const dispatch = useDispatch();
 | 
			
		||||
type Props = {
 | 
			
		||||
    selectProps?: Omit<PickerSelectProps, "items" | "onValueChange">;
 | 
			
		||||
    controllerProps?: ControllerRenderProps<FilterState, "shippingWarehouseId">
 | 
			
		||||
}
 | 
			
		||||
const ShippingWarehouseSelect: FC<Props> = (props) => {
 | 
			
		||||
    const [items, setItems] = useState<ShippingWarehouse[]>([]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (state.initialized) return;
 | 
			
		||||
        generalApi.getShippingWarehouses().then(shippingWarehouses =>
 | 
			
		||||
            dispatch(initializeShippingWarehouseSelect(shippingWarehouses)))
 | 
			
		||||
        generalApi.getShippingWarehouses().then(response => {
 | 
			
		||||
            setItems(response);
 | 
			
		||||
        })
 | 
			
		||||
    }, []);
 | 
			
		||||
    return (
 | 
			
		||||
        <View style={{
 | 
			
		||||
            borderWidth: responsiveWidth(0.1),
 | 
			
		||||
            borderRadius: responsiveWidth(1)
 | 
			
		||||
        }}>
 | 
			
		||||
            <Picker
 | 
			
		||||
                selectedValue={state.selectedShippingWarehouse?.id}
 | 
			
		||||
                onValueChange={(value, event) => dispatch(selectShippingWarehouse({shippingWarehouseId: value}))}
 | 
			
		||||
            >
 | 
			
		||||
                {state.shippingWarehouses.map(shippingWarehouse => (
 | 
			
		||||
                    <Picker.Item
 | 
			
		||||
                        key={shippingWarehouse.id}
 | 
			
		||||
                        label={shippingWarehouse.name}
 | 
			
		||||
                        value={shippingWarehouse.id}
 | 
			
		||||
                        style={{fontSize: responsiveWidth(3)}}
 | 
			
		||||
                    />
 | 
			
		||||
                ))}
 | 
			
		||||
            </Picker>
 | 
			
		||||
        </View>
 | 
			
		||||
 | 
			
		||||
        <RNPickerSelect
 | 
			
		||||
            useNativeAndroidPickerStyle={true}
 | 
			
		||||
            style={{
 | 
			
		||||
                viewContainer: {
 | 
			
		||||
                    borderWidth: 1,
 | 
			
		||||
                    borderColor: "#9EA0A4",
 | 
			
		||||
                    borderRadius: "1%"
 | 
			
		||||
                }
 | 
			
		||||
            }}
 | 
			
		||||
            placeholder={{label: "Все склады", value: -1, color: "#9EA0A4"}}
 | 
			
		||||
            {...props.selectProps}
 | 
			
		||||
            onValueChange={(value, _) => {
 | 
			
		||||
                if (typeof value !== 'number') return;
 | 
			
		||||
                props.controllerProps?.onChange(value);
 | 
			
		||||
            }}
 | 
			
		||||
            value={props.controllerProps?.value}
 | 
			
		||||
            itemKey={"value"}
 | 
			
		||||
            items={items.map(sw => ({label: sw.name, value: sw.id, color:"black"}))}/>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,16 @@
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {StyleSheet, View, Image, TouchableOpacity, GestureResponderEvent} from "react-native";
 | 
			
		||||
import {GestureResponderEvent, Image, StyleSheet, TouchableOpacity, View} from "react-native";
 | 
			
		||||
import DText from "../DText/DText";
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
import {responsiveWidth} from "react-native-responsive-dimensions";
 | 
			
		||||
import {useAppDispatch} from "../../redux/store";
 | 
			
		||||
import {openFilter} from "../../features/filterSlice/filterSlice";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    onPress?: (event: GestureResponderEvent) => void
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
const SortingButton: FC<Props> = ({onPress}) => {
 | 
			
		||||
const SortingButton: FC = () => {
 | 
			
		||||
    const dispatch = useAppDispatch();
 | 
			
		||||
    const onPress = (event: GestureResponderEvent) => {
 | 
			
		||||
        dispatch(openFilter())
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <TouchableOpacity onPress={onPress}>
 | 
			
		||||
            <View style={styles.container}>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								src/connectors/PdfToBitmap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,15 @@
 | 
			
		||||
import {NativeModules} from 'react-native';
 | 
			
		||||
 | 
			
		||||
interface PdfToBitmapInterface {
 | 
			
		||||
    convertPdfToBitmaps(pdfBase64: string): Promise<string[]>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const { PdfToBitmap } = NativeModules as { PdfToBitmap: PdfToBitmapInterface };
 | 
			
		||||
 | 
			
		||||
export async function convertPdfToBitmaps(pdfBase64: string): Promise<string[]> {
 | 
			
		||||
    try {
 | 
			
		||||
        return await PdfToBitmap.convertPdfToBitmaps(pdfBase64);
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        throw new Error(`Failed to convert PDF to bitmaps: ${error}`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								src/connectors/myTcpSocket.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,13 @@
 | 
			
		||||
import { NativeModules } from 'react-native';
 | 
			
		||||
 | 
			
		||||
const { MyTcpSocket } = NativeModules;
 | 
			
		||||
 | 
			
		||||
interface MyTcpSocketInterface {
 | 
			
		||||
    writeToSocket(ip: string, port: number, data: string[]): Promise<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const myTcpSocket: MyTcpSocketInterface = {
 | 
			
		||||
    writeToSocket: async (ip: string, port: number, data: string[]): Promise<string> => {
 | 
			
		||||
        return await MyTcpSocket.writeToSocket(ip, port, data);
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										25
									
								
								src/contexts/apiContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
			
		||||
import {createContext, FC, ReactNode, useContext} from "react";
 | 
			
		||||
 | 
			
		||||
type ApiState = {
 | 
			
		||||
    onLogout: () => void;
 | 
			
		||||
};
 | 
			
		||||
const apiContext = createContext<ApiState | undefined>(undefined);
 | 
			
		||||
 | 
			
		||||
export const useApiContext = () => {
 | 
			
		||||
    const context = useContext(apiContext);
 | 
			
		||||
    if (!context) throw new Error('useApiContext must be used within ApiContextProvider');
 | 
			
		||||
    return context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ApiContextProviderProps = {
 | 
			
		||||
    children: ReactNode;
 | 
			
		||||
    state: ApiState;
 | 
			
		||||
}
 | 
			
		||||
export const ApiContextProvider: FC<ApiContextProviderProps> = ({children, state}) => {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <ApiContextProvider state={state}>
 | 
			
		||||
            {children}
 | 
			
		||||
        </ApiContextProvider>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
export const background = "#F5F5F5";
 | 
			
		||||
export const blue = "#2478F8";
 | 
			
		||||
export const gray = '#A5A5A5';
 | 
			
		||||
export const gray = '#A5A5A5';
 | 
			
		||||
export const red = "#e03131"
 | 
			
		||||
export const blueButton = '#2478F8'
 | 
			
		||||
							
								
								
									
										29
									
								
								src/features/animations/animationsSlice.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
			
		||||
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
 | 
			
		||||
 | 
			
		||||
interface AnimationsSlice {
 | 
			
		||||
    isRewardAnimationVisible: boolean;
 | 
			
		||||
    rewardAmount: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: AnimationsSlice = {
 | 
			
		||||
    isRewardAnimationVisible: false,
 | 
			
		||||
    rewardAmount: 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const animationsSlice = createSlice({
 | 
			
		||||
    name: 'animations',
 | 
			
		||||
    initialState,
 | 
			
		||||
    reducers: {
 | 
			
		||||
        showReward: (state, action: PayloadAction<{ reward: number }>) => {
 | 
			
		||||
            state.rewardAmount = action.payload.reward;
 | 
			
		||||
            state.isRewardAnimationVisible = true;
 | 
			
		||||
        },
 | 
			
		||||
        hideReward: (state) => {
 | 
			
		||||
            state.isRewardAnimationVisible = false;
 | 
			
		||||
            state.rewardAmount = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const {showReward, hideReward} = animationsSlice.actions;
 | 
			
		||||
export default animationsSlice.reducer;
 | 
			
		||||
@@ -10,11 +10,13 @@ export interface AssemblyState {
 | 
			
		||||
    assembly?: Assembly;
 | 
			
		||||
    selectedProductId?: number;
 | 
			
		||||
    localState?: ASSEMBLY_STATE;
 | 
			
		||||
    selectedProduct?: OrderProduct
 | 
			
		||||
    selectedProduct?: OrderProduct;
 | 
			
		||||
    acceptModalVisible: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: AssemblyState = {
 | 
			
		||||
    localState: ASSEMBLY_STATE.NOT_STARTED
 | 
			
		||||
    localState: ASSEMBLY_STATE.NOT_STARTED,
 | 
			
		||||
    acceptModalVisible: false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const assembly = createSlice({
 | 
			
		||||
@@ -31,12 +33,18 @@ export const assembly = createSlice({
 | 
			
		||||
            state.assembly = action.payload;
 | 
			
		||||
            state.localState = action.payload.state;
 | 
			
		||||
        },
 | 
			
		||||
        skipCrpt: (state) => {
 | 
			
		||||
            if (!state.assembly) return;
 | 
			
		||||
            state.assembly.state = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS;
 | 
			
		||||
            state.localState = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        startAssembly: (state) => {
 | 
			
		||||
            if (!state.assembly) return;
 | 
			
		||||
            state.assembly.createdAt = (new Date()).toDateString();
 | 
			
		||||
 | 
			
		||||
            state.assembly.state = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS;
 | 
			
		||||
            state.localState = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS;
 | 
			
		||||
            state.assembly.state = ASSEMBLY_STATE.SCANNING_CRPT;
 | 
			
		||||
            state.localState = ASSEMBLY_STATE.SCANNING_CRPT;
 | 
			
		||||
        },
 | 
			
		||||
        endAssembly: (state) => {
 | 
			
		||||
            if (!state.assembly) return;
 | 
			
		||||
@@ -94,6 +102,12 @@ export const assembly = createSlice({
 | 
			
		||||
            state.localState = ASSEMBLY_STATE.NOT_STARTED
 | 
			
		||||
            state.selectedProductId = undefined;
 | 
			
		||||
            state.selectedProduct = undefined;
 | 
			
		||||
        },
 | 
			
		||||
        openAcceptModal: (state) => {
 | 
			
		||||
            state.acceptModalVisible = true;
 | 
			
		||||
        },
 | 
			
		||||
        closeAcceptModal: (state) => {
 | 
			
		||||
            state.acceptModalVisible = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
@@ -107,6 +121,10 @@ export const {
 | 
			
		||||
    endAssembly,
 | 
			
		||||
    confirmAssembly,
 | 
			
		||||
    setLocalState,
 | 
			
		||||
    reset
 | 
			
		||||
    reset,
 | 
			
		||||
    openAcceptModal,
 | 
			
		||||
    closeAcceptModal,
 | 
			
		||||
    skipCrpt
 | 
			
		||||
 | 
			
		||||
} = assembly.actions;
 | 
			
		||||
export default assembly.reducer;
 | 
			
		||||
							
								
								
									
										71
									
								
								src/features/balance/balanceSlice.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,71 @@
 | 
			
		||||
import {BalanceInfo, BalanceTransaction} from "../../types/balance";
 | 
			
		||||
import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
 | 
			
		||||
import balanceApi from "../../api/balanceApi";
 | 
			
		||||
 | 
			
		||||
const name = 'balance';
 | 
			
		||||
 | 
			
		||||
interface TransactionsState {
 | 
			
		||||
    items: BalanceTransaction[];
 | 
			
		||||
    isLoading: boolean;
 | 
			
		||||
    currentPage: number;
 | 
			
		||||
    hasNext: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface BalanceState {
 | 
			
		||||
    balance: number;
 | 
			
		||||
    transactions: TransactionsState;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const transactionsInitialState: TransactionsState = {
 | 
			
		||||
    currentPage: 1,
 | 
			
		||||
    hasNext: true,
 | 
			
		||||
    isLoading: false,
 | 
			
		||||
    items: []
 | 
			
		||||
}
 | 
			
		||||
const initialState: BalanceState = {
 | 
			
		||||
    balance: 0,
 | 
			
		||||
    transactions: transactionsInitialState
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const fetchTransactions = createAsyncThunk(
 | 
			
		||||
    `${name}/fetchTransactions`,
 | 
			
		||||
    async (page: number, _): Promise<BalanceTransaction[]> => {
 | 
			
		||||
        const response = await balanceApi.getTransactions(page);
 | 
			
		||||
        return response.balanceTransactions;
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export const fetchBalance = createAsyncThunk(
 | 
			
		||||
    `${name}/fetchBalance`,
 | 
			
		||||
    async (_): Promise<BalanceInfo> => {
 | 
			
		||||
        return await balanceApi.getBalanceInfo();
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
export const balanceSlice = createSlice({
 | 
			
		||||
    name: name,
 | 
			
		||||
    initialState,
 | 
			
		||||
    reducers: {
 | 
			
		||||
        refreshTransactions: (state) => {
 | 
			
		||||
            state.transactions = transactionsInitialState;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    extraReducers: (builder) => {
 | 
			
		||||
        builder.addCase(fetchTransactions.pending, (state, action) => {
 | 
			
		||||
            state.transactions.isLoading = true;
 | 
			
		||||
        })
 | 
			
		||||
        builder.addCase(fetchTransactions.fulfilled, (state, action) => {
 | 
			
		||||
            state.transactions.isLoading = false;
 | 
			
		||||
            state.transactions.hasNext = action.payload.length > 0;
 | 
			
		||||
            state.transactions.items = [...state.transactions.items, ...action.payload];
 | 
			
		||||
            state.transactions.currentPage = state.transactions.currentPage + 1;
 | 
			
		||||
        })
 | 
			
		||||
        builder.addCase(fetchBalance.fulfilled, (state, action) => {
 | 
			
		||||
            state.balance = action.payload.balance;
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const {refreshTransactions} = balanceSlice.actions;
 | 
			
		||||
 | 
			
		||||
export default balanceSlice.reducer;
 | 
			
		||||
							
								
								
									
										38
									
								
								src/features/filterSlice/filterSlice.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,38 @@
 | 
			
		||||
import {createSlice} from "@reduxjs/toolkit";
 | 
			
		||||
 | 
			
		||||
export type FilterState = {
 | 
			
		||||
    sorting: string;
 | 
			
		||||
    shippingWarehouseId: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FilterSliceState {
 | 
			
		||||
    visible: boolean;
 | 
			
		||||
    state: FilterState
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: FilterSliceState = {
 | 
			
		||||
    visible: false,
 | 
			
		||||
    state: {
 | 
			
		||||
        sorting: 'shipment_date_desc',
 | 
			
		||||
        shippingWarehouseId: -1,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const filterSlice = createSlice({
 | 
			
		||||
    name: 'filter',
 | 
			
		||||
    initialState,
 | 
			
		||||
    reducers: {
 | 
			
		||||
        openFilter: (state) => {
 | 
			
		||||
            state.visible = true;
 | 
			
		||||
        },
 | 
			
		||||
        closeFilter: (state) => {
 | 
			
		||||
            state.visible = false;
 | 
			
		||||
        },
 | 
			
		||||
        setFilterState: (state, action) => {
 | 
			
		||||
            state.state = action.payload;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const {openFilter, closeFilter, setFilterState} = filterSlice.actions;
 | 
			
		||||
export default filterSlice.reducer;
 | 
			
		||||
@@ -89,7 +89,6 @@ export const ordersFilterSlice = createSlice({
 | 
			
		||||
            state.city = action.payload;
 | 
			
		||||
        },
 | 
			
		||||
        setPage: (state, action: PayloadAction<number>) => {
 | 
			
		||||
            console.log(action)
 | 
			
		||||
            state.page = action.payload;
 | 
			
		||||
        },
 | 
			
		||||
        nextPage: (state) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,44 @@
 | 
			
		||||
import {createSlice} from "@reduxjs/toolkit";
 | 
			
		||||
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
 | 
			
		||||
 | 
			
		||||
export interface ScanModalState {
 | 
			
		||||
    isVisible: boolean;
 | 
			
		||||
    scannedData?: string
 | 
			
		||||
    scannedData?: string;
 | 
			
		||||
    customLabel?: string;
 | 
			
		||||
    data?: any;
 | 
			
		||||
    uuid?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: ScanModalState = {
 | 
			
		||||
    isVisible: false,
 | 
			
		||||
    scannedData: undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const scanModalSlice = createSlice({
 | 
			
		||||
    name: 'scanModal',
 | 
			
		||||
    initialState,
 | 
			
		||||
    reducers: {
 | 
			
		||||
        openScanModal: (state) => {
 | 
			
		||||
        openScanModalFormContext(state, action: PayloadAction<{ uuid: string }>) {
 | 
			
		||||
            state.isVisible = true;
 | 
			
		||||
            state.uuid = action.payload.uuid;
 | 
			
		||||
        },
 | 
			
		||||
        openScanModal: (state, action: PayloadAction<{ customLabel?: string, data?: any }>) => {
 | 
			
		||||
            state.isVisible = true
 | 
			
		||||
            if (!action) return;
 | 
			
		||||
            state.customLabel = action.payload.customLabel;
 | 
			
		||||
            state.data = action.payload.data;
 | 
			
		||||
        },
 | 
			
		||||
        closeScanModal: (state) => {
 | 
			
		||||
            state.isVisible = false
 | 
			
		||||
            state.customLabel = undefined;
 | 
			
		||||
            state.data = undefined;
 | 
			
		||||
        },
 | 
			
		||||
        setScannedData: (state, action) => {
 | 
			
		||||
            state.scannedData = action.payload;
 | 
			
		||||
        },
 | 
			
		||||
        resolveUuid: (state) => {
 | 
			
		||||
            state.uuid = undefined;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const {openScanModal, closeScanModal, setScannedData} = scanModalSlice.actions;
 | 
			
		||||
export const {openScanModal, closeScanModal, setScannedData, openScanModalFormContext,resolveUuid} = scanModalSlice.actions;
 | 
			
		||||
export default scanModalSlice.reducer;
 | 
			
		||||
							
								
								
									
										30
									
								
								src/features/scannerState/scannerState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,30 @@
 | 
			
		||||
import {BluetoothDevice} from "react-native-bluetooth-classic";
 | 
			
		||||
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
 | 
			
		||||
 | 
			
		||||
export interface ScannerState {
 | 
			
		||||
    isConnected: boolean;
 | 
			
		||||
    deviceAddress?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: ScannerState = {
 | 
			
		||||
    isConnected: false,
 | 
			
		||||
    deviceAddress: undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const scannerSlice = createSlice({
 | 
			
		||||
    name: "scannerState",
 | 
			
		||||
    initialState,
 | 
			
		||||
    reducers: {
 | 
			
		||||
        setDevice(state, action: PayloadAction<{ deviceAddress: string }>) {
 | 
			
		||||
            state.deviceAddress = action.payload.deviceAddress;
 | 
			
		||||
        },
 | 
			
		||||
        setIsConnected(state, action: PayloadAction<{ isConnected: boolean }>) {
 | 
			
		||||
            state.isConnected = action.payload.isConnected
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const {setDevice, setIsConnected} = scannerSlice.actions
 | 
			
		||||
export default scannerSlice.reducer
 | 
			
		||||