diff --git a/frontend/src/basic/RobotPage/Onboarding.tsx b/frontend/src/basic/RobotPage/Onboarding.tsx index 38d54aac..1d6d2fad 100644 --- a/frontend/src/basic/RobotPage/Onboarding.tsx +++ b/frontend/src/basic/RobotPage/Onboarding.tsx @@ -178,7 +178,7 @@ const Onboarding = ({ /> - {slot?.hashId ? ( + {slot?.nickname ? ( {t('Hi! My name is')} diff --git a/frontend/src/components/Dialogs/Profile.tsx b/frontend/src/components/Dialogs/Profile.tsx index 0a7760b7..1c2dcc40 100644 --- a/frontend/src/components/Dialogs/Profile.tsx +++ b/frontend/src/components/Dialogs/Profile.tsx @@ -64,7 +64,7 @@ const ProfileDialog = ({ open = false, onClose }: Props): JSX.Element => { - {garage.getSlot()?.nickname !== undefined && ( + {!garage.getSlot()?.nickname && (
{ - const cacheKey = `${size}px;${hash}`; + const cacheKey = `${hash};${size}`; if (this.assetsCache[cacheKey]) { return this.assetsCache[cacheKey]; } else { diff --git a/frontend/src/components/RobotAvatar/index.tsx b/frontend/src/components/RobotAvatar/index.tsx index 2ad86b83..bf9160c2 100644 --- a/frontend/src/components/RobotAvatar/index.tsx +++ b/frontend/src/components/RobotAvatar/index.tsx @@ -5,6 +5,7 @@ import { SendReceiveIcon } from '../Icons'; import placeholder from './placeholder.json'; // import { robohash } from './RobohashGenerator'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext'; +import { roboidentitiesClient } from '../../services/Roboidentities'; interface Props { shortAlias?: string | undefined; @@ -53,22 +54,21 @@ const RobotAvatar: React.FC = ({ const backgroundImage = `url(data:${backgroundData.mime};base64,${backgroundData.data})`; const className = placeholderType === 'loading' ? 'loadingAvatar' : 'generatingAvatar'; - // useEffect(() => { - // // TODO: HANDLE ANDROID AVATARS TOO (when window.NativeRobosats !== undefined) - // if (hashId !== undefined) { - // robohash - // .generate(hashId, small ? 'small' : 'large') - // .then((avatar) => { - // setAvatarSrc(avatar); - // }) - // .catch(() => { - // setAvatarSrc(''); - // }); - // setTimeout(() => { - // setActiveBackground(false); - // }, backgroundFadeTime); - // } - // }, [hashId]); + useEffect(() => { + if (hashId !== undefined) { + roboidentitiesClient + .generateRobohash(hashId, small ? 'small' : 'large') + .then((avatar) => { + setAvatarSrc(avatar); + }) + .catch(() => { + setAvatarSrc(''); + }); + setTimeout(() => { + setActiveBackground(false); + }, backgroundFadeTime); + } + }, [hashId]); useEffect(() => { if (shortAlias !== undefined) { diff --git a/frontend/src/models/Coordinator.model.ts b/frontend/src/models/Coordinator.model.ts index 09e74a30..6df6c550 100644 --- a/frontend/src/models/Coordinator.model.ts +++ b/frontend/src/models/Coordinator.model.ts @@ -6,6 +6,7 @@ import { type Order, type Garage, } from '.'; +import { roboidentitiesClient } from '../services/Roboidentities'; import { apiClient } from '../services/api'; import { validateTokenEntropy } from '../utils'; import { compareUpdateLimit } from './Limit.model'; @@ -174,9 +175,9 @@ export class Coordinator { }; generateAllMakerAvatars = async (data: [PublicOrder]): Promise => { - // for (const order of data) { - // void robohash.generate(order.maker_hash_id, 'small'); - // } + for (const order of data) { + roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small'); + } }; loadBook = (onDataLoad: () => void = () => {}): void => { diff --git a/frontend/src/models/Slot.model.ts b/frontend/src/models/Slot.model.ts index 1a564a7f..47a21c80 100644 --- a/frontend/src/models/Slot.model.ts +++ b/frontend/src/models/Slot.model.ts @@ -8,13 +8,12 @@ class Slot { this.token = token; this.hashId = sha256(sha256(this.token)); - this.nickname = ''; + this.nickname = null; roboidentitiesClient.generateRoboname(this.hashId).then((nickname) => { this.nickname = nickname; }); - // trigger RoboHash avatar generation in webworker and store in RoboHash class cache. - // void robohash.generate(this.hashId, 'small'); - // void robohash.generate(this.hashId, 'large'); + roboidentitiesClient.generateRobohash(this.hashId, 'small'); + roboidentitiesClient.generateRobohash(this.hashId, 'large'); this.robots = shortAliases.reduce((acc: Record, shortAlias: string) => { acc[shortAlias] = new Robot(robotAttributes); diff --git a/frontend/src/services/Roboidentities/RoboidentitiesNativeClient/index.ts b/frontend/src/services/Roboidentities/RoboidentitiesNativeClient/index.ts index 73f1f31f..be8c3252 100644 --- a/frontend/src/services/Roboidentities/RoboidentitiesNativeClient/index.ts +++ b/frontend/src/services/Roboidentities/RoboidentitiesNativeClient/index.ts @@ -1,20 +1,43 @@ import { type RoboidentitiesClient } from '..'; -import NativeRobosats from '../../Native'; class RoboidentitiesNativeClient implements RoboidentitiesClient { - constructor() { - window.NativeRobosats = new NativeRobosats(); - } - - public loading = true; + private robonames: Record = {}; + private robohashes: Record = {}; public generateRoboname: (initialString: string) => Promise = async (initialString) => { - const response = await window.NativeRobosats?.postMessage({ - category: 'roboIdentities', - type: 'roboname', - detail: initialString, - }); - return response ? Object.values(response)[0] : ''; + if (this.robonames[initialString]) { + return this.robonames[initialString]; + } else { + const response = await window.NativeRobosats?.postMessage({ + category: 'roboidentities', + type: 'roboname', + detail: initialString, + }); + const result = response ? Object.values(response)[0] : ''; + this.robonames[initialString] = result; + return result; + } + }; + + public generateRobohash: (initialString: string, size: string) => Promise = async ( + initialString, + size, + ) => { + const key = `${initialString};${size === 'small' ? 80 : 256}`; + + if (this.robohashes[key]) { + return this.robohashes[key]; + } else { + const response = await window.NativeRobosats?.postMessage({ + category: 'roboidentities', + type: 'robohash', + detail: key, + }); + const result = response ? Object.values(response)[0] : ''; + const image = `data:image/png;base64,${result}`; + this.robohashes[key] = image; + return image; + } }; } diff --git a/frontend/src/services/Roboidentities/RoboidentitiesWebClient/index.ts b/frontend/src/services/Roboidentities/RoboidentitiesWebClient/index.ts index 2d8b9112..643577b7 100644 --- a/frontend/src/services/Roboidentities/RoboidentitiesWebClient/index.ts +++ b/frontend/src/services/Roboidentities/RoboidentitiesWebClient/index.ts @@ -7,6 +7,15 @@ class RoboidentitiesClientWebClient implements RoboidentitiesClient { // resolve(generate_roboname(initialString)) }); }; + + public generateRobohash: (initialString: string, size: string) => Promise = async ( + initialString, + size, + ) => { + return new Promise(async (resolve, _reject) => { + // resolve(generate_roboname(initialString)) + }); + }; } export default RoboidentitiesClientWebClient; diff --git a/frontend/src/services/Roboidentities/index.ts b/frontend/src/services/Roboidentities/index.ts index 4901b072..b5568ddc 100644 --- a/frontend/src/services/Roboidentities/index.ts +++ b/frontend/src/services/Roboidentities/index.ts @@ -3,6 +3,7 @@ import RoboidentitiesClientWebClient from './RoboidentitiesWebClient'; export interface RoboidentitiesClient { generateRoboname: (initialString: string) => Promise; + generateRobohash: (initialString: string, size: string) => Promise; } export const roboidentitiesClient: RoboidentitiesClient = diff --git a/frontend/src/services/api/ApiNativeClient/index.ts b/frontend/src/services/api/ApiNativeClient/index.ts index 9ab27d91..6f794eec 100644 --- a/frontend/src/services/api/ApiNativeClient/index.ts +++ b/frontend/src/services/api/ApiNativeClient/index.ts @@ -30,7 +30,6 @@ class ApiNativeClient implements ApiClient { }; private readonly parseResponse = (response: Record): object => { - console.log('response', response); if (response.headers['set-cookie'] != null) { response.headers['set-cookie'].forEach((cookie: string) => { const keySplit: string[] = cookie.split('='); diff --git a/mobile/App.tsx b/mobile/App.tsx index d7367861..d61444be 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -132,8 +132,11 @@ const App = () => { } } else if (data.category === 'roboidentities') { if (data.type === 'roboname') { - const roboname = RoboIdentitiesModule.generateRoboname(data.detail); - injectMessageResolve(data.id, roboname); + const roboname = await RoboIdentitiesModule.generateRoboname(data.detail); + injectMessageResolve(data.id, { roboname }); + } else if (data.type === 'robohash') { + const robohash = await RoboIdentitiesModule.generateRobohash(data.detail); + injectMessageResolve(data.id, { robohash }); } } }; diff --git a/mobile/android/app/src/main/java/com/robosats/RoboIdentities.java b/mobile/android/app/src/main/java/com/robosats/RoboIdentities.java index afeee6d9..c37f8505 100644 --- a/mobile/android/app/src/main/java/com/robosats/RoboIdentities.java +++ b/mobile/android/app/src/main/java/com/robosats/RoboIdentities.java @@ -1,14 +1,22 @@ package com.robosats; +import android.util.Log; + public class RoboIdentities { static { System.loadLibrary("robonames"); + System.loadLibrary("robohash"); } public String generateRoboname(String initial_string) { return nativeGenerateRoboname(initial_string); } + public String generateRobohash(String initial_string) { + return nativeGenerateRobohash(initial_string); + } + // Native functions implemented in Rust. private static native String nativeGenerateRoboname(String initial_string); + private static native String nativeGenerateRobohash(String initial_string); } diff --git a/mobile/android/app/src/main/java/com/robosats/modules/RoboIdentitiesModule.java b/mobile/android/app/src/main/java/com/robosats/modules/RoboIdentitiesModule.java index a8caef81..c18d131b 100644 --- a/mobile/android/app/src/main/java/com/robosats/modules/RoboIdentitiesModule.java +++ b/mobile/android/app/src/main/java/com/robosats/modules/RoboIdentitiesModule.java @@ -2,9 +2,13 @@ package com.robosats.modules; import android.util.Log; +import com.facebook.react.bridge.Arguments; +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.WritableMap; +import com.facebook.react.modules.core.DeviceEventManagerModule; import com.robosats.RoboIdentities; public class RoboIdentitiesModule extends ReactContextBaseJavaModule { @@ -20,7 +24,14 @@ public class RoboIdentitiesModule extends ReactContextBaseJavaModule { } @ReactMethod - public String generateRoboname(String initial_string) { - return new RoboIdentities().generateRoboname(initial_string); + public void generateRoboname(String initial_string, final Promise promise) { + String roboname = new RoboIdentities().generateRoboname(initial_string); + promise.resolve(roboname); + } + + @ReactMethod + public void generateRobohash(String initial_string, final Promise promise) { + String robohash = new RoboIdentities().generateRobohash(initial_string); + promise.resolve(robohash); } } diff --git a/mobile/android/app/src/main/java/com/robosats/modules/TorModule.java b/mobile/android/app/src/main/java/com/robosats/modules/TorModule.java index 0705c347..224bc5d8 100644 --- a/mobile/android/app/src/main/java/com/robosats/modules/TorModule.java +++ b/mobile/android/app/src/main/java/com/robosats/modules/TorModule.java @@ -43,7 +43,6 @@ public class TorModule extends ReactContextBaseJavaModule { @ReactMethod public void sendRequest(String action, String url, String headers, String body, final Promise promise) throws JSONException { - Log.d("RobosatsUrl", url); OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout .readTimeout(30, TimeUnit.SECONDS) // Set read timeout @@ -75,7 +74,6 @@ public class TorModule extends ReactContextBaseJavaModule { @Override public void onResponse(Call call, Response response) throws IOException { - Log.d("RobosatsCode", String.valueOf(response.code())); String body = response.body() != null ? response.body().string() : "{}"; JSONObject headersJson = new JSONObject(); response.headers().names().forEach(name -> { diff --git a/mobile/android/app/src/main/jniLibs/arm64-v8a/librobohash.so b/mobile/android/app/src/main/jniLibs/arm64-v8a/librobohash.so new file mode 100755 index 00000000..8bc01999 Binary files /dev/null and b/mobile/android/app/src/main/jniLibs/arm64-v8a/librobohash.so differ diff --git a/mobile/android/app/src/main/jniLibs/armeabi-v7a/librobohash.so b/mobile/android/app/src/main/jniLibs/armeabi-v7a/librobohash.so new file mode 100755 index 00000000..3775d2f0 Binary files /dev/null and b/mobile/android/app/src/main/jniLibs/armeabi-v7a/librobohash.so differ diff --git a/mobile/native/RoboIdentitiesModule.ts b/mobile/native/RoboIdentitiesModule.ts index 78ac08a1..a5c3c83e 100644 --- a/mobile/native/RoboIdentitiesModule.ts +++ b/mobile/native/RoboIdentitiesModule.ts @@ -2,7 +2,8 @@ import { NativeModules } from 'react-native'; const { RoboIdentitiesModule } = NativeModules; interface RoboIdentitiesModuleInterface { - generateRoboname: (initialString: String) => String; + generateRoboname: (initialString: String) => Promise; + generateRobohash: (initialString: String) => Promise; } export default RoboIdentitiesModule as RoboIdentitiesModuleInterface;