diff --git a/.dockerignore b/.dockerignore
--- a/.dockerignore
+++ b/.dockerignore
@@ -19,6 +19,7 @@
!native/cpp/CommonCpp/grpc
!native/expo-modules/android-lifecycle/package.json
!native/expo-modules/aes-crypto/package.json
+!native/expo-modules/thumbhash/package.json
web/node_modules
web/dist
diff --git a/keyserver/Dockerfile b/keyserver/Dockerfile
--- a/keyserver/Dockerfile
+++ b/keyserver/Dockerfile
@@ -126,6 +126,8 @@
native/expo-modules/android-lifecycle/
COPY --chown=comm native/expo-modules/aes-crypto/package.json \
native/expo-modules/aes-crypto/
+COPY --chown=comm native/expo-modules/thumbhash/package.json \
+ native/expo-modules/thumbhash/
COPY --chown=comm services/electron-update-server/package.json \
services/electron-update-server/
diff --git a/native/expo-modules/thumbhash/android/build.gradle b/native/expo-modules/thumbhash/android/build.gradle
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/android/build.gradle
@@ -0,0 +1,92 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'maven-publish'
+
+group = 'app.comm.android.thumbhash'
+version = '0.0.1'
+
+buildscript {
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
+ if (expoModulesCorePlugin.exists()) {
+ apply from: expoModulesCorePlugin
+ applyKotlinExpoModulesCorePlugin()
+ }
+
+ // Simple helper that allows the root project to override versions declared by this library.
+ ext.safeExtGet = { prop, fallback ->
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+ }
+
+ // Ensures backward compatibility
+ ext.getKotlinVersion = {
+ if (ext.has("kotlinVersion")) {
+ ext.kotlinVersion()
+ } else {
+ ext.safeExtGet("kotlinVersion", "1.6.10")
+ }
+ }
+
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
+ }
+}
+
+// Creating sources with comments
+task androidSourcesJar(type: Jar) {
+ classifier = 'sources'
+ from android.sourceSets.main.java.srcDirs
+}
+
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ from components.release
+ // Add additional sourcesJar to artifacts
+ artifact(androidSourcesJar)
+ }
+ }
+ repositories {
+ maven {
+ url = mavenLocal().url
+ }
+ }
+ }
+}
+
+android {
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
+ }
+
+ defaultConfig {
+ minSdkVersion safeExtGet("minSdkVersion", 21)
+ targetSdkVersion safeExtGet("targetSdkVersion", 33)
+ versionCode 1
+ versionName "0.1.0"
+ }
+ lintOptions {
+ abortOnError false
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation project(':expo-modules-core')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
+ implementation 'com.facebook.react:react-native:+'
+}
diff --git a/native/expo-modules/thumbhash/android/src/main/AndroidManifest.xml b/native/expo-modules/thumbhash/android/src/main/AndroidManifest.xml
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/android/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/native/expo-modules/thumbhash/android/src/main/java/app/comm/android/thumbhash/ThumbhashModule.kt b/native/expo-modules/thumbhash/android/src/main/java/app/comm/android/thumbhash/ThumbhashModule.kt
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/android/src/main/java/app/comm/android/thumbhash/ThumbhashModule.kt
@@ -0,0 +1,14 @@
+package app.comm.android.thumbhash
+
+import expo.modules.kotlin.modules.Module
+import expo.modules.kotlin.modules.ModuleDefinition
+
+class ThumbhashModule : Module() {
+ override fun definition() = ModuleDefinition {
+ Name("Thumbhash")
+
+ AsyncFunction("generateThumbHash") {
+ "unimplemented"
+ }
+ }
+}
diff --git a/native/expo-modules/thumbhash/expo-module.config.json b/native/expo-modules/thumbhash/expo-module.config.json
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/expo-module.config.json
@@ -0,0 +1,9 @@
+{
+ "platforms": ["ios", "android"],
+ "ios": {
+ "modules": ["ThumbhashModule"]
+ },
+ "android": {
+ "modules": ["app.comm.android.thumbhash.ThumbhashModule"]
+ }
+}
diff --git a/native/expo-modules/thumbhash/ios/Thumbhash.podspec b/native/expo-modules/thumbhash/ios/Thumbhash.podspec
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/ios/Thumbhash.podspec
@@ -0,0 +1,27 @@
+require 'json'
+
+package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
+
+Pod::Spec.new do |s|
+ s.name = 'Thumbhash'
+ s.version = package['version']
+ s.summary = package['description']
+ s.description = package['description']
+ s.license = package['license']
+ s.author = 'Comm'
+ s.homepage = 'https://comm.app'
+ s.platform = :ios, '13.0'
+ s.swift_version = '5.4'
+ s.source = { git: 'https://github.com/CommE2E/comm' }
+ s.static_framework = true
+
+ s.dependency 'ExpoModulesCore'
+
+ # Swift/Objective-C compatibility
+ s.pod_target_xcconfig = {
+ 'DEFINES_MODULE' => 'YES',
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
+ }
+
+ s.source_files = "**/*.{h,m,swift}"
+end
diff --git a/native/expo-modules/thumbhash/ios/ThumbhashModule.swift b/native/expo-modules/thumbhash/ios/ThumbhashModule.swift
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/ios/ThumbhashModule.swift
@@ -0,0 +1,11 @@
+import ExpoModulesCore
+
+public class ThumbhashModule: Module {
+ public func definition() -> ModuleDefinition {
+ Name("Thumbhash")
+
+ AsyncFunction("generateThumbHash") { () -> String in
+ "unimplemented"
+ }
+ }
+}
diff --git a/native/expo-modules/thumbhash/package.json b/native/expo-modules/thumbhash/package.json
new file mode 100644
--- /dev/null
+++ b/native/expo-modules/thumbhash/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@commapp/thumbhash",
+ "version": "0.0.1",
+ "private": true,
+ "license": "BSD-3-Clause",
+ "description": "Thumbhash generator module",
+ "dependencies": {},
+ "devDependencies": {
+ "expo-module-scripts": "^3.0.3",
+ "expo-modules-core": "1.1.1"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+}
diff --git a/native/ios/Podfile.lock b/native/ios/Podfile.lock
--- a/native/ios/Podfile.lock
+++ b/native/ios/Podfile.lock
@@ -561,6 +561,8 @@
- SQLCipher-Amalgamation/standard (4.4.3):
- OpenSSL-Universal
- SQLCipher-Amalgamation/common
+ - Thumbhash (0.0.1):
+ - ExpoModulesCore
- Yoga (1.14.0)
DEPENDENCIES:
@@ -648,6 +650,7 @@
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- "SQLCipher-Amalgamation (from `../../node_modules/@commapp/sqlcipher-amalgamation`)"
+ - Thumbhash (from `../expo-modules/thumbhash/ios`)
- Yoga (from `../../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@@ -833,6 +836,8 @@
:path: "../node_modules/react-native-svg"
SQLCipher-Amalgamation:
:path: "../../node_modules/@commapp/sqlcipher-amalgamation"
+ Thumbhash:
+ :path: "../expo-modules/thumbhash/ios"
Yoga:
:path: "../../node_modules/react-native/ReactCommon/yoga"
@@ -934,6 +939,7 @@
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
SPTPersistentCache: df36ea46762d7cf026502bbb86a8b79d0080dff4
SQLCipher-Amalgamation: cbd36045fe7b458b8a442958a01aefdbc44c20f8
+ Thumbhash: 38f05b358a74ff8946820dc5f8330071e931925a
Yoga: d6133108734e69e8c0becc6ba587294b94829687
PODFILE CHECKSUM: 60ed9de6b14a66c6022cd82cafcb04594edd7eaf
diff --git a/native/package.json b/native/package.json
--- a/native/package.json
+++ b/native/package.json
@@ -52,6 +52,7 @@
"@commapp/android-lifecycle": "0.0.1",
"@commapp/aes-crypto": "0.0.1",
"@commapp/sqlcipher-amalgamation": "^4.4.3-a",
+ "@commapp/thumbhash": "0.0.1",
"@ethersproject/shims": "^5.7.0",
"@expo/react-native-action-sheet": "^3.14.0",
"@expo/vector-icons": "^13.0.0",
diff --git a/native/utils/thumbhash-module.js b/native/utils/thumbhash-module.js
new file mode 100644
--- /dev/null
+++ b/native/utils/thumbhash-module.js
@@ -0,0 +1,18 @@
+// @flow
+
+import { requireNativeModule } from 'expo-modules-core';
+import invariant from 'invariant';
+
+const platformUtilsModule: {
+ +generateThumbHash: (photoURI: string) => Promise,
+} = requireNativeModule('Thumbhash');
+
+async function generateThumbHash(photoURI: string): Promise {
+ invariant(
+ platformUtilsModule.generateThumbHash,
+ 'generateThumbHash() unavailable. Check if Thumbhash expo-module is autolinked',
+ );
+ return await platformUtilsModule.generateThumbHash(photoURI);
+}
+
+export { generateThumbHash };
diff --git a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"keyserver/addons/rust-node-addon",
"native/expo-modules/android-lifecycle",
"native/expo-modules/aes-crypto",
+ "native/expo-modules/thumbhash",
"services/electron-update-server",
"web/opaque-ke-wasm"
],