seven365-zyprinter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/Package.swift +43 -0
  2. package/README.md +186 -0
  3. package/Seven365Zyprinter.podspec +27 -0
  4. package/android/build.gradle +58 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/mycompany/plugins/example/Example.java +342 -0
  7. package/android/src/main/java/com/mycompany/plugins/example/ExamplePlugin.java +161 -0
  8. package/android/src/main/res/.gitkeep +0 -0
  9. package/dist/docs.json +229 -0
  10. package/dist/esm/definitions.d.ts +56 -0
  11. package/dist/esm/definitions.js +2 -0
  12. package/dist/esm/definitions.js.map +1 -0
  13. package/dist/esm/index.d.ts +4 -0
  14. package/dist/esm/index.js +7 -0
  15. package/dist/esm/index.js.map +1 -0
  16. package/dist/esm/web.d.ts +49 -0
  17. package/dist/esm/web.js +40 -0
  18. package/dist/esm/web.js.map +1 -0
  19. package/dist/plugin.cjs.js +54 -0
  20. package/dist/plugin.cjs.js.map +1 -0
  21. package/dist/plugin.js +57 -0
  22. package/dist/plugin.js.map +1 -0
  23. package/ios/Seven365Zyprinter.podspec +28 -0
  24. package/ios/Sources/Plugin/ZyprintPlugin.swift +161 -0
  25. package/ios/Sources/Plugin/ZywellSDK.swift +358 -0
  26. package/ios/Sources/Seven365Zyprinter-Umbrella.h +16 -0
  27. package/ios/Sources/module.modulemap +12 -0
  28. package/ios/Sources/sources/BLEManager.h +658 -0
  29. package/ios/Sources/sources/BLEManager.m +2842 -0
  30. package/ios/Sources/sources/GCD/Documentation.html +47 -0
  31. package/ios/Sources/sources/GCD/GCDAsyncSocket.h +1226 -0
  32. package/ios/Sources/sources/GCD/GCDAsyncSocket.m +8560 -0
  33. package/ios/Sources/sources/GCD/GCDAsyncUdpSocket.h +1036 -0
  34. package/ios/Sources/sources/GCD/GCDAsyncUdpSocket.m +5632 -0
  35. package/ios/Sources/sources/GCD/PrinterManager.h +91 -0
  36. package/ios/Sources/sources/GCD/PrinterManager.m +513 -0
  37. package/ios/Sources/sources/GCD/WifiManager.h +91 -0
  38. package/ios/Sources/sources/GCD/WifiManager.m +510 -0
  39. package/ios/Sources/sources/ImageTranster.h +38 -0
  40. package/ios/Sources/sources/ImageTranster.m +389 -0
  41. package/ios/Sources/sources/POSBLEManager.h +759 -0
  42. package/ios/Sources/sources/POSBLEManager.m +834 -0
  43. package/ios/Sources/sources/POSSDK.h +93 -0
  44. package/ios/Sources/sources/POSWIFIManager.h +116 -0
  45. package/ios/Sources/sources/POSWIFIManager.m +260 -0
  46. package/ios/Sources/sources/POSWIFIManagerAsync.h +745 -0
  47. package/ios/Sources/sources/POSWIFIManagerAsync.m +1847 -0
  48. package/ios/Sources/sources/PosCommand.h +633 -0
  49. package/ios/Sources/sources/PosCommand.m +1019 -0
  50. package/ios/Sources/sources/TscCommand.h +723 -0
  51. package/ios/Sources/sources/TscCommand.m +566 -0
  52. package/ios/Tests/ExamplePluginTests/ExamplePluginTests.swift +15 -0
  53. package/package.json +339 -0
package/Package.swift ADDED
@@ -0,0 +1,43 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "Seven365Zyprinter",
6
+ platforms: [.iOS(.v14)],
7
+ products: [
8
+ .library(
9
+ name: "Seven365Zyprinter",
10
+ targets: ["Seven365ZyprinterPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "Seven365ZyprinterPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources",
23
+ exclude: [
24
+ "sources/GCD/Documentation.html"
25
+ ],
26
+ sources: [
27
+ "Plugin/ZyprintPlugin.swift",
28
+ "Plugin/ZywellSDK.swift",
29
+ "sources"
30
+ ],
31
+ publicHeadersPath: "Plugin",
32
+ cSettings: [
33
+ .headerSearchPath("sources"),
34
+ .headerSearchPath("sources/GCD"),
35
+ .headerSearchPath("Plugin")
36
+ ]
37
+ ),
38
+ .testTarget(
39
+ name: "Seven365ZyprinterPluginTests",
40
+ dependencies: ["Seven365ZyprinterPlugin"],
41
+ path: "ios/Tests/ExamplePluginTests")
42
+ ]
43
+ )
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # seven365-zyprinter
2
+
3
+ plugin for integration of zyprinter
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install seven365-zyprinter
9
+ npx cap sync
10
+ ```
11
+
12
+ ## API
13
+
14
+ <docgen-index>
15
+
16
+ * [`echo(...)`](#echo)
17
+ * [`discoverPrinters()`](#discoverprinters)
18
+ * [`discoverBluetoothPrinters()`](#discoverbluetoothprinters)
19
+ * [`discoverWiFiPrinters(...)`](#discoverwifiprinters)
20
+ * [`connectToPrinter(...)`](#connecttoprinter)
21
+ * [`disconnectFromPrinter(...)`](#disconnectfromprinter)
22
+ * [`printText(...)`](#printtext)
23
+ * [`printReceipt(...)`](#printreceipt)
24
+ * [`getPrinterStatus(...)`](#getprinterstatus)
25
+ * [Interfaces](#interfaces)
26
+ * [Type Aliases](#type-aliases)
27
+
28
+ </docgen-index>
29
+
30
+ <docgen-api>
31
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
32
+
33
+ ### echo(...)
34
+
35
+ ```typescript
36
+ echo(options: { value: string; }) => Promise<{ value: string; }>
37
+ ```
38
+
39
+ | Param | Type |
40
+ | ------------- | ------------------------------- |
41
+ | **`options`** | <code>{ value: string; }</code> |
42
+
43
+ **Returns:** <code>Promise&lt;{ value: string; }&gt;</code>
44
+
45
+ --------------------
46
+
47
+
48
+ ### discoverPrinters()
49
+
50
+ ```typescript
51
+ discoverPrinters() => Promise<{ printers: ZyPrinter[]; }>
52
+ ```
53
+
54
+ **Returns:** <code>Promise&lt;{ printers: ZyPrinter[]; }&gt;</code>
55
+
56
+ --------------------
57
+
58
+
59
+ ### discoverBluetoothPrinters()
60
+
61
+ ```typescript
62
+ discoverBluetoothPrinters() => Promise<{ printers: ZyPrinter[]; }>
63
+ ```
64
+
65
+ **Returns:** <code>Promise&lt;{ printers: ZyPrinter[]; }&gt;</code>
66
+
67
+ --------------------
68
+
69
+
70
+ ### discoverWiFiPrinters(...)
71
+
72
+ ```typescript
73
+ discoverWiFiPrinters(options?: { networkRange?: string | undefined; } | undefined) => Promise<{ printers: ZyPrinter[]; }>
74
+ ```
75
+
76
+ | Param | Type |
77
+ | ------------- | --------------------------------------- |
78
+ | **`options`** | <code>{ networkRange?: string; }</code> |
79
+
80
+ **Returns:** <code>Promise&lt;{ printers: ZyPrinter[]; }&gt;</code>
81
+
82
+ --------------------
83
+
84
+
85
+ ### connectToPrinter(...)
86
+
87
+ ```typescript
88
+ connectToPrinter(options: { identifier: string; }) => Promise<{ connected: boolean; }>
89
+ ```
90
+
91
+ | Param | Type |
92
+ | ------------- | ------------------------------------ |
93
+ | **`options`** | <code>{ identifier: string; }</code> |
94
+
95
+ **Returns:** <code>Promise&lt;{ connected: boolean; }&gt;</code>
96
+
97
+ --------------------
98
+
99
+
100
+ ### disconnectFromPrinter(...)
101
+
102
+ ```typescript
103
+ disconnectFromPrinter(options: { identifier: string; }) => Promise<{ disconnected: boolean; }>
104
+ ```
105
+
106
+ | Param | Type |
107
+ | ------------- | ------------------------------------ |
108
+ | **`options`** | <code>{ identifier: string; }</code> |
109
+
110
+ **Returns:** <code>Promise&lt;{ disconnected: boolean; }&gt;</code>
111
+
112
+ --------------------
113
+
114
+
115
+ ### printText(...)
116
+
117
+ ```typescript
118
+ printText(options: { text: string; identifier: string; }) => Promise<{ success: boolean; }>
119
+ ```
120
+
121
+ | Param | Type |
122
+ | ------------- | -------------------------------------------------- |
123
+ | **`options`** | <code>{ text: string; identifier: string; }</code> |
124
+
125
+ **Returns:** <code>Promise&lt;{ success: boolean; }&gt;</code>
126
+
127
+ --------------------
128
+
129
+
130
+ ### printReceipt(...)
131
+
132
+ ```typescript
133
+ printReceipt(options: { template: Record<string, any>; identifier: string; }) => Promise<{ success: boolean; }>
134
+ ```
135
+
136
+ | Param | Type |
137
+ | ------------- | ----------------------------------------------------------------------------------------------- |
138
+ | **`options`** | <code>{ template: <a href="#record">Record</a>&lt;string, any&gt;; identifier: string; }</code> |
139
+
140
+ **Returns:** <code>Promise&lt;{ success: boolean; }&gt;</code>
141
+
142
+ --------------------
143
+
144
+
145
+ ### getPrinterStatus(...)
146
+
147
+ ```typescript
148
+ getPrinterStatus(options: { identifier: string; }) => Promise<{ status: string; paperStatus: string; connected: boolean; }>
149
+ ```
150
+
151
+ | Param | Type |
152
+ | ------------- | ------------------------------------ |
153
+ | **`options`** | <code>{ identifier: string; }</code> |
154
+
155
+ **Returns:** <code>Promise&lt;{ status: string; paperStatus: string; connected: boolean; }&gt;</code>
156
+
157
+ --------------------
158
+
159
+
160
+ ### Interfaces
161
+
162
+
163
+ #### ZyPrinter
164
+
165
+ | Prop | Type |
166
+ | -------------------- | ------------------------------------------- |
167
+ | **`identifier`** | <code>string</code> |
168
+ | **`model`** | <code>string</code> |
169
+ | **`status`** | <code>string</code> |
170
+ | **`connectionType`** | <code>'bluetooth' \| 'wifi' \| 'usb'</code> |
171
+ | **`ipAddress`** | <code>string</code> |
172
+ | **`port`** | <code>number</code> |
173
+ | **`rssi`** | <code>number</code> |
174
+
175
+
176
+ ### Type Aliases
177
+
178
+
179
+ #### Record
180
+
181
+ Construct a type with a set of properties K of type T
182
+
183
+ <code>{
184
  [P in K]: T;
1
185
  }</code>
186
+
187
+ </docgen-api>
188
+ # seven365-zyprinter-sdk
@@ -0,0 +1,27 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = 'Seven365Zyprinter'
3
+ s.version = '0.0.1'
4
+ s.summary = 'Capacitor plugin for Zywell/Zyprint thermal printer integration'
5
+ s.license = 'MIT'
6
+ s.homepage = 'https://github.com/Seven365-Pte-Ltd/plateful-pos-mobile'
7
+ s.author = 'joelralph'
8
+ s.source = { :git => 'https://github.com/Seven365-Pte-Ltd/plateful-pos-mobile', :tag => s.version.to_s }
9
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
10
+ s.exclude_files = 'ios/Sources/sources/POSWIFIManagerAsync.{h,m}'
11
+ s.ios.deployment_target = '14.0'
12
+ s.dependency 'Capacitor'
13
+ s.swift_version = '5.1'
14
+
15
+ # Framework dependencies
16
+ s.frameworks = 'CoreBluetooth', 'SystemConfiguration', 'CFNetwork'
17
+
18
+ # Public headers for Objective-C SDK - expose to Swift
19
+ s.public_header_files = 'ios/Sources/sources/**/*.h'
20
+
21
+
22
+ # Explicitly disable bridging header (not supported in frameworks)
23
+ s.pod_target_xcconfig = {
24
+ 'SWIFT_OBJC_BRIDGING_HEADER' => '',
25
+ 'DEFINES_MODULE' => 'YES'
26
+ }
27
+ end
@@ -0,0 +1,58 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.7.2'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace "com.mycompany.plugins.example"
22
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ }
49
+
50
+
51
+ dependencies {
52
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
53
+ implementation project(':capacitor-android')
54
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
+ testImplementation "junit:junit:$junitVersion"
56
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
58
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,342 @@
1
+ package com.mycompany.plugins.example;
2
+
3
+ import android.bluetooth.BluetoothAdapter;
4
+ import android.bluetooth.BluetoothDevice;
5
+ import android.bluetooth.BluetoothSocket;
6
+ import android.content.Context;
7
+ import android.util.Log;
8
+ import android.os.Handler;
9
+ import android.os.Looper;
10
+
11
+ import com.getcapacitor.JSArray;
12
+ import com.getcapacitor.JSObject;
13
+
14
+ import java.io.IOException;
15
+ import java.io.OutputStream;
16
+ import java.net.Socket;
17
+ import java.util.HashMap;
18
+ import java.util.Map;
19
+ import java.util.Set;
20
+ import java.util.UUID;
21
+
22
+ public class Zyprint {
23
+
24
+ private static final String TAG = "Zyprint";
25
+ private Map<String, PrinterConnection> connectedPrinters = new HashMap<>();
26
+ private Handler mainHandler = new Handler(Looper.getMainLooper());
27
+
28
+ // Callback interfaces
29
+ public interface PrinterDiscoveryCallback {
30
+ void onPrintersFound(JSArray printers);
31
+ void onError(String error);
32
+ }
33
+
34
+ public interface ConnectionCallback {
35
+ void onConnected();
36
+ void onError(String error);
37
+ }
38
+
39
+ public interface DisconnectionCallback {
40
+ void onDisconnected();
41
+ void onError(String error);
42
+ }
43
+
44
+ public interface PrintCallback {
45
+ void onSuccess();
46
+ void onError(String error);
47
+ }
48
+
49
+ public interface StatusCallback {
50
+ void onStatus(String status, String paperStatus, boolean connected);
51
+ void onError(String error);
52
+ }
53
+
54
+ public String echo(String value) {
55
+ Log.i(TAG, "Echo: " + value);
56
+ return value;
57
+ }
58
+
59
+ public void discoverPrinters(PrinterDiscoveryCallback callback) {
60
+ new Thread(() -> {
61
+ try {
62
+ JSArray printers = new JSArray();
63
+
64
+ // Discover Bluetooth printers
65
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
66
+ if (bluetoothAdapter != null && bluetoothAdapter.isEnabled()) {
67
+ Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
68
+
69
+ for (BluetoothDevice device : pairedDevices) {
70
+ // Filter for printer devices (you may need to adjust this based on Zywell printer naming)
71
+ if (device.getName() != null &&
72
+ (device.getName().toLowerCase().contains("zywell") ||
73
+ device.getName().toLowerCase().contains("zyprint") ||
74
+ device.getName().toLowerCase().contains("printer"))) {
75
+
76
+ JSObject printer = new JSObject();
77
+ printer.put("identifier", device.getAddress());
78
+ printer.put("model", device.getName());
79
+ printer.put("status", device.getBondState() == BluetoothDevice.BOND_BONDED ? "ready" : "offline");
80
+ printers.put(printer);
81
+ }
82
+ }
83
+ }
84
+
85
+ mainHandler.post(() -> callback.onPrintersFound(printers));
86
+
87
+ } catch (Exception e) {
88
+ Log.e(TAG, "Error discovering printers", e);
89
+ mainHandler.post(() -> callback.onError("Discovery failed: " + e.getMessage()));
90
+ }
91
+ }).start();
92
+ }
93
+
94
+ public void connectToPrinter(String identifier, ConnectionCallback callback) {
95
+ new Thread(() -> {
96
+ try {
97
+ PrinterConnection connection = new PrinterConnection();
98
+
99
+ // Try to connect via Bluetooth
100
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
101
+ if (bluetoothAdapter != null) {
102
+ BluetoothDevice device = bluetoothAdapter.getRemoteDevice(identifier);
103
+
104
+ if (connection.connectBluetooth(device)) {
105
+ connectedPrinters.put(identifier, connection);
106
+ mainHandler.post(callback::onConnected);
107
+ return;
108
+ }
109
+ }
110
+
111
+ // If Bluetooth fails, try WiFi (if identifier is an IP address)
112
+ if (identifier.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
113
+ if (connection.connectWiFi(identifier, 9100)) {
114
+ connectedPrinters.put(identifier, connection);
115
+ mainHandler.post(callback::onConnected);
116
+ return;
117
+ }
118
+ }
119
+
120
+ mainHandler.post(() -> callback.onError("Connection failed"));
121
+
122
+ } catch (Exception e) {
123
+ Log.e(TAG, "Error connecting to printer", e);
124
+ mainHandler.post(() -> callback.onError("Connection failed: " + e.getMessage()));
125
+ }
126
+ }).start();
127
+ }
128
+
129
+ public void disconnectFromPrinter(String identifier, DisconnectionCallback callback) {
130
+ PrinterConnection connection = connectedPrinters.get(identifier);
131
+ if (connection != null) {
132
+ connection.disconnect();
133
+ connectedPrinters.remove(identifier);
134
+ callback.onDisconnected();
135
+ } else {
136
+ callback.onError("Printer not connected");
137
+ }
138
+ }
139
+
140
+ public void printText(String text, String identifier, PrintCallback callback) {
141
+ PrinterConnection connection = connectedPrinters.get(identifier);
142
+ if (connection == null) {
143
+ callback.onError("Printer not connected");
144
+ return;
145
+ }
146
+
147
+ new Thread(() -> {
148
+ try {
149
+ byte[] data = formatTextForPrinter(text);
150
+ if (connection.sendData(data)) {
151
+ mainHandler.post(callback::onSuccess);
152
+ } else {
153
+ mainHandler.post(() -> callback.onError("Print failed"));
154
+ }
155
+ } catch (Exception e) {
156
+ Log.e(TAG, "Error printing text", e);
157
+ mainHandler.post(() -> callback.onError("Print failed: " + e.getMessage()));
158
+ }
159
+ }).start();
160
+ }
161
+
162
+ public void printReceipt(JSObject template, String identifier, PrintCallback callback) {
163
+ PrinterConnection connection = connectedPrinters.get(identifier);
164
+ if (connection == null) {
165
+ callback.onError("Printer not connected");
166
+ return;
167
+ }
168
+
169
+ new Thread(() -> {
170
+ try {
171
+ byte[] data = formatReceiptForPrinter(template);
172
+ if (connection.sendData(data)) {
173
+ mainHandler.post(callback::onSuccess);
174
+ } else {
175
+ mainHandler.post(() -> callback.onError("Print failed"));
176
+ }
177
+ } catch (Exception e) {
178
+ Log.e(TAG, "Error printing receipt", e);
179
+ mainHandler.post(() -> callback.onError("Print failed: " + e.getMessage()));
180
+ }
181
+ }).start();
182
+ }
183
+
184
+ public void getPrinterStatus(String identifier, StatusCallback callback) {
185
+ PrinterConnection connection = connectedPrinters.get(identifier);
186
+ if (connection == null) {
187
+ callback.onStatus("offline", "unknown", false);
188
+ return;
189
+ }
190
+
191
+ new Thread(() -> {
192
+ try {
193
+ // Send status command (this would be specific to Zywell protocol)
194
+ byte[] statusCommand = {0x10, 0x04, 0x01}; // Example status command
195
+
196
+ if (connection.sendData(statusCommand)) {
197
+ // In a real implementation, you'd read the response and parse it
198
+ mainHandler.post(() -> callback.onStatus("ready", "ok", true));
199
+ } else {
200
+ mainHandler.post(() -> callback.onStatus("error", "unknown", true));
201
+ }
202
+ } catch (Exception e) {
203
+ Log.e(TAG, "Error getting printer status", e);
204
+ mainHandler.post(() -> callback.onError("Status check failed: " + e.getMessage()));
205
+ }
206
+ }).start();
207
+ }
208
+
209
+ private byte[] formatTextForPrinter(String text) {
210
+ try {
211
+ // ESC/POS commands for text printing
212
+ byte[] initPrinter = {0x1B, 0x40}; // ESC @
213
+ byte[] textBytes = text.getBytes("UTF-8");
214
+ byte[] lineFeed = {0x0A, 0x0A, 0x0A}; // Line feeds
215
+ byte[] cutPaper = {0x1D, 0x56, 0x41, 0x10}; // Cut command
216
+
217
+ byte[] result = new byte[initPrinter.length + textBytes.length + lineFeed.length + cutPaper.length];
218
+ int offset = 0;
219
+
220
+ System.arraycopy(initPrinter, 0, result, offset, initPrinter.length);
221
+ offset += initPrinter.length;
222
+
223
+ System.arraycopy(textBytes, 0, result, offset, textBytes.length);
224
+ offset += textBytes.length;
225
+
226
+ System.arraycopy(lineFeed, 0, result, offset, lineFeed.length);
227
+ offset += lineFeed.length;
228
+
229
+ System.arraycopy(cutPaper, 0, result, offset, cutPaper.length);
230
+
231
+ return result;
232
+ } catch (Exception e) {
233
+ Log.e(TAG, "Error formatting text", e);
234
+ return new byte[0];
235
+ }
236
+ }
237
+
238
+ private byte[] formatReceiptForPrinter(JSObject template) {
239
+ try {
240
+ StringBuilder receiptText = new StringBuilder();
241
+
242
+ // Initialize printer
243
+ receiptText.append("\u001B@"); // ESC @
244
+
245
+ // Center align
246
+ receiptText.append("\u001B\u0061\u0001"); // ESC a 1
247
+
248
+ // Header
249
+ if (template.has("header")) {
250
+ receiptText.append(template.getString("header")).append("\n\n");
251
+ }
252
+
253
+ // Left align for items
254
+ receiptText.append("\u001B\u0061\u0000"); // ESC a 0
255
+
256
+ // Items
257
+ if (template.has("items")) {
258
+ JSArray items = template.getJSArray("items");
259
+ for (int i = 0; i < items.length(); i++) {
260
+ JSObject item = items.getJSObject(i);
261
+ String name = item.optString("name", "");
262
+ String price = item.optString("price", "");
263
+ receiptText.append(name).append("\t").append(price).append("\n");
264
+ }
265
+ }
266
+
267
+ // Total
268
+ if (template.has("total")) {
269
+ receiptText.append("\nTotal: ").append(template.getString("total")).append("\n");
270
+ }
271
+
272
+ // Line feeds and cut
273
+ receiptText.append("\n\n\n");
274
+ receiptText.append("\u001D\u0056\u0041\u0010"); // Cut command
275
+
276
+ return receiptText.toString().getBytes("UTF-8");
277
+ } catch (Exception e) {
278
+ Log.e(TAG, "Error formatting receipt", e);
279
+ return new byte[0];
280
+ }
281
+ }
282
+
283
+ private static class PrinterConnection {
284
+ private BluetoothSocket bluetoothSocket;
285
+ private Socket wifiSocket;
286
+ private OutputStream outputStream;
287
+
288
+ public boolean connectBluetooth(BluetoothDevice device) {
289
+ try {
290
+ // UUID for printer service (this might need to be specific to Zywell)
291
+ UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
292
+ bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
293
+ bluetoothSocket.connect();
294
+ outputStream = bluetoothSocket.getOutputStream();
295
+ return true;
296
+ } catch (Exception e) {
297
+ Log.e(TAG, "Bluetooth connection failed", e);
298
+ return false;
299
+ }
300
+ }
301
+
302
+ public boolean connectWiFi(String ipAddress, int port) {
303
+ try {
304
+ wifiSocket = new Socket(ipAddress, port);
305
+ outputStream = wifiSocket.getOutputStream();
306
+ return true;
307
+ } catch (Exception e) {
308
+ Log.e(TAG, "WiFi connection failed", e);
309
+ return false;
310
+ }
311
+ }
312
+
313
+ public boolean sendData(byte[] data) {
314
+ try {
315
+ if (outputStream != null) {
316
+ outputStream.write(data);
317
+ outputStream.flush();
318
+ return true;
319
+ }
320
+ } catch (IOException e) {
321
+ Log.e(TAG, "Error sending data", e);
322
+ }
323
+ return false;
324
+ }
325
+
326
+ public void disconnect() {
327
+ try {
328
+ if (outputStream != null) {
329
+ outputStream.close();
330
+ }
331
+ if (bluetoothSocket != null) {
332
+ bluetoothSocket.close();
333
+ }
334
+ if (wifiSocket != null) {
335
+ wifiSocket.close();
336
+ }
337
+ } catch (IOException e) {
338
+ Log.e(TAG, "Error disconnecting", e);
339
+ }
340
+ }
341
+ }
342
+ }