Compare commits

...

2 Commits

Author SHA1 Message Date
Ammar Ahmed
a7fe799f22 mobile: fix file upload notifications on android 2025-11-20 14:09:56 +05:00
Ammar Ahmed
d0e5bec780 mobile: improve file uploads in background 2025-11-17 09:54:54 +05:00
7 changed files with 261 additions and 211 deletions

View File

@@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RequestOptions } from "@notesnook/core";
import { Platform } from "react-native";
import { isImage, RequestOptions } from "@notesnook/core";
import { PermissionsAndroid, Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import { ToastManager } from "../../services/event-manager";
import { useAttachmentStore } from "../../stores/use-attachment-store";
@@ -31,6 +31,7 @@ import {
FileSizeResult,
getUploadedFileSize
} from "./utils";
import Upload from "@ammarahmed/react-native-upload";
export async function uploadFile(
filename: string,
@@ -64,47 +65,96 @@ export async function uploadFile(
);
}
const fileSize = (await RNFetchBlob.fs.stat(filePath)).size;
const fileInfo = await RNFetchBlob.fs.stat(filePath);
const remoteFileSize = await getUploadedFileSize(filename);
if (remoteFileSize === FileSizeResult.Error) return false;
if (remoteFileSize > FileSizeResult.Empty && remoteFileSize === fileSize) {
if (
remoteFileSize > FileSizeResult.Empty &&
remoteFileSize === fileInfo.size
) {
DatabaseLogger.log(`File ${filename} is already uploaded.`);
return true;
}
DatabaseLogger.info(`Starting upload: ${filename}`);
let attachmentInfo = await db.attachments.attachment(filename);
const uploadRequest = RNFetchBlob.config({
//@ts-ignore
IOSBackgroundTask: !globalThis["IS_SHARE_EXTENSION"]
})
.fetch(
"PUT",
url,
{
...headers,
"content-type": ""
},
RNFetchBlob.wrap(filePath)
)
.uploadProgress((sent, total) => {
useAttachmentStore
.getState()
.setProgress(sent, total, filename, 0, "upload");
DatabaseLogger.info(
`File upload progress: ${filename}, ${sent}/${total}`
);
});
DatabaseLogger.info(
`Starting upload of ${filename} at path: ${fileInfo.path}`
);
if (Platform.OS === "android") {
const status = await PermissionsAndroid.request(
"android.permission.POST_NOTIFICATIONS"
);
if (status !== "granted") {
ToastManager.show({
message: `The permission to show file upload notification was disallowed by the user.`,
type: "info"
});
}
}
const upload = Upload.create({
customUploadId: filename,
path: Platform.OS === "ios" ? "file://" + fileInfo.path : fileInfo.path,
url: url,
method: "PUT",
headers: {
...headers,
"content-type": "application/octet-stream"
},
appGroup: IOS_APPGROUPID,
notification: {
filename:
attachmentInfo && isImage(attachmentInfo?.mimeType)
? "image"
: attachmentInfo?.filename || "file",
enabled: true,
enableRingTone: true,
autoClear: true,
onProgressTitle: `Uploading ${attachmentInfo?.filename || "file"}`,
onCancelledTitle: "Upload cancelled",
onProgressMessage: "Uploading file",
onErrorTitle: "Uploading failed",
onErrorMessage: "Uploading failed",
onCancelledMessage: "Cancelled",
onCompleteTitle: "Upload complete",
onCompleteMessage: "Uploading"
}
}).onChange((event) => {
switch (event.status) {
case "running":
case "pending":
useAttachmentStore
.getState()
.setProgress(
event.uploadedBytes || 0,
event.totalBytes || fileInfo.size,
filename,
0,
"upload"
);
DatabaseLogger.info(
`File upload progress: ${filename}, ${event.uploadedBytes}/${
event.totalBytes || fileInfo.size
}`
);
break;
case "completed":
console.log("Upload completed");
break;
}
});
console.log("STARTING UPLOAD");
const result = await upload.start();
cancelToken.cancel = async () => {
useAttachmentStore.getState().remove(filename);
uploadRequest.cancel();
upload.cancel();
};
const uploadResponse = await uploadRequest;
const status = uploadResponse.info().status;
const status = result.responseCode || 0;
const uploaded = status >= 200 && status < 300;
useAttachmentStore.getState().remove(filename);
@@ -114,12 +164,12 @@ export async function uploadFile(
throw new Error(
`${status}, name: ${fileInfo.filename}, length: ${
fileInfo.size
}, info: ${JSON.stringify(uploadResponse.info())}`
}, info: ${JSON.stringify(result.error)}`
);
}
const attachment = await db.attachments.attachment(filename);
if (!attachment) return false;
await checkUpload(filename, requestOptions.chunkSize, attachment.size);
attachmentInfo = await db.attachments.attachment(filename);
if (!attachmentInfo) return false;
await checkUpload(filename, requestOptions.chunkSize, attachmentInfo.size);
DatabaseLogger.info(`File upload status: ${filename}, ${status}`);
return uploaded;
} catch (e) {

View File

@@ -194,7 +194,9 @@ const camera = async (options: PickerOptions) => {
options
);
})
.catch((e) => {});
.catch((e) => {
console.log(e);
});
} catch (e) {
ToastManager.show({
heading: (e as Error).message,

View File

@@ -5,6 +5,7 @@
#import "RNShortcuts.h"
#import "RNBootSplash.h"
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
#import "RNFileUploader.h"
@implementation AppDelegate
@@ -60,4 +61,8 @@
return rootView;
}
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
[RNFileUploader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
}
@end

View File

@@ -1397,6 +1397,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-upload (6.19.0):
- React
- react-native-webview (13.13.5):
- DoubleConversion
- glog
@@ -2086,6 +2088,7 @@ DEPENDENCIES:
- "react-native-share-extension (from `../../node_modules/@ammarahmed/react-native-share-extension`)"
- "react-native-sodium (from `../../node_modules/@ammarahmed/react-native-sodium`)"
- react-native-theme-switch-animation (from `../../node_modules/react-native-theme-switch-animation`)
- "react-native-upload (from `../../node_modules/@ammarahmed/react-native-upload`)"
- react-native-webview (from `../../node_modules/react-native-webview`)
- React-nativeconfig (from `../../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
@@ -2286,6 +2289,8 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@ammarahmed/react-native-sodium"
react-native-theme-switch-animation:
:path: "../../node_modules/react-native-theme-switch-animation"
react-native-upload:
:path: "../../node_modules/@ammarahmed/react-native-upload"
react-native-webview:
:path: "../../node_modules/react-native-webview"
React-nativeconfig:
@@ -2475,6 +2480,7 @@ SPEC CHECKSUMS:
react-native-share-extension: fdc6aaab51591a2d445df239c446aaa3a99658ec
react-native-sodium: 285eec063e4232cb67347ef6a434b85e588d38cb
react-native-theme-switch-animation: d90fe2de0d9e87a63cd6235d98cba6e7054e9a10
react-native-upload: 3dd0a33be0399b54cc38749aa8ed8dab1205783c
react-native-webview: 079eca50edf657503318b66687dadfb903731aa8
React-nativeconfig: ecf4dc92c40b97e2b3f0c619938f78bfd6507b08
React-NativeModulesApple: f457bbfb30fb3bc41979b1a87b99d292d7340d39

View File

@@ -9,6 +9,7 @@
"react": "18.2.0"
},
"dependencies": {
"@ammarahmed/react-native-upload": "^6.26.0",
"@ammarahmed/notifee-react-native": "7.4.9",
"@callstack/repack": "~5.1.2",
"@bam.tech/react-native-image-resizer": "3.0.11",

View File

@@ -1,7 +1,7 @@
const isGithubRelease = false;
const config = {
commands: require('@callstack/repack/commands/rspack'),
// commands: require('@callstack/repack/commands/rspack'),
project: {
android: {
sourceDir: './android'

File diff suppressed because it is too large Load Diff