diff --git a/android/app/build.gradle b/android/app/build.gradle index 31e26e2..ba1052c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -249,8 +249,6 @@ dependencies { } implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") - //implementation("io.iohk.atala:prism-api:v1.3.2") - // SICPA PEER-DID-JVM implementation("org.didcommx:peerdid:0.2.0") diff --git a/android/app/src/main/java/com/rootswallet/PrismModule.kt b/android/app/src/main/java/com/rootswallet/PrismModule.kt index 36db06f..a554d8a 100644 --- a/android/app/src/main/java/com/rootswallet/PrismModule.kt +++ b/android/app/src/main/java/com/rootswallet/PrismModule.kt @@ -7,7 +7,6 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.rootsid.wal.library.* -//import io.iohk.atala.prism.api.* import kotlinx.serialization.json.Json import kotlinx.serialization.encodeToString import kotlinx.serialization.decodeFromString @@ -65,25 +64,6 @@ class PrismModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } } - @ReactMethod - fun importCred(walJson: String, credAlias: String, credJson: String, promise: Promise) { - Log.d("PRISM_TAG","Importing credential for "+credAlias+" from wallet "+walJson); - thread(start = true) { - try { - val importedCredential = ImportedCredential( - credAlias, - Json.decodeFromString(credJson) - ) - var newWal = Json.decodeFromString(walJson); - newWal.importedCredentials.add(importedCredential) - //Log.d("PRISM_TAG","Credential imported",walJson) - promise.resolve(Json.encodeToString(newWal)); - } catch (e: Exception) { - promise.reject("Publish Error", e); - } - } - } - @ReactMethod fun issueCred(walJson: String, didAlias: String, credJson: String, promise: Promise) { Log.d("PRISM_TAG","Issuing credential for "+didAlias+" from wallet "+walJson); @@ -101,21 +81,6 @@ class PrismModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } } - //TODO deal with build errors regarding iog.api -// @ReactMethod -// fun verifyCred(walJson: String, credAlias: String, promise: Promise) { -// Log.d("PRISM_TAG","Verifying credential for "+credAlias+" from wallet "+walJson); -// thread(start = true) { -// try { -// var cliWal = Json.decodeFromString(walJson); -// var verResult = Json.encodeToString(verifyIssuedCredential(cliWal, credAlias)) -// Log.d("PRISM_TAG","Credential "+credAlias+" is " + verResult) -// promise.resolve(verResult); -// } catch (e: Exception) { -// promise.reject("Publish Error", e); -// } -// } -// } // @ReactMethod // public void fetch(final String path, final Promise promise) { // new Thread(new Runnable() { diff --git a/app.json b/app.json index 60a558f..3385b80 100644 --- a/app.json +++ b/app.json @@ -1,37 +1,34 @@ { "expo": { - "owner": "rootsid", "name": "rootswallet", "slug": "rootswallet", - "description": "Open Source Identity Wallet for grass roots efforts that matter", - "privacy": "unlisted", - "version": "0.0.1-alpha", + "version": "1.0.0", "orientation": "default", - "platforms": ["android"], - "githubUrl": "https://github.com/roots-id/rootswallet", - "icon": "./src/assets/LogoOnly1024.png", + "icon": "./assets/LogoOnly1024.png", "splash": { - "image": "./src/assets/WhiteTextExtraGlow.png", + "image": "./assets/WhiteTextExtraGlow.png", "resizeMode": "contain", "backgroundColor": "#111111" }, "updates": { - "enabled": true, - "fallbackToCacheTimeout": 10000 + "fallbackToCacheTimeout": 0 }, "assetBundlePatterns": [ "**/*" ], + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.rootswallet" + }, "android": { "adaptiveIcon": { - - "foregroundImage": "./src/assets/LogoOnly1024.png", + "foregroundImage": "./assets/LogoOnly1024.png", "backgroundColor": "#111111" }, "package": "com.rootswallet" }, "web": { - "favicon": "./src/assets/LogoOnly1024.png" + "favicon": "./assets/LogoOnly1024.png" } } } diff --git a/package.json b/package.json index ac9642a..fa59e4b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "@babel/preset-env": "^7.1.6", - "@react-native-async-storage/async-storage": "~1.15.0", + "@react-native-async-storage/async-storage": "^1.17.3", "@react-native-community/masked-view": "0.1.10", "@react-navigation/bottom-tabs": "^6.3.1", "@react-navigation/core": "6.2.1", @@ -28,21 +28,20 @@ "expo-secure-store": "~11.1.0", "expo-splash-screen": "~0.14.1", "expo-status-bar": "~1.2.0", - "expo-updates": "~0.11.7", + "expo-updates": "^0.11.6", "i18next": "^21.6.4", "react": "17.0.1", "react-dom": "17.0.1", "react-i18next": "^11.15.3", - "react-json-view": "^1.21.3", "react-native": "0.64.3", "react-native-gesture-handler": "~2.1.0", - "react-native-gifted-chat": "1.0.0-beta-3", + "react-native-gifted-chat": "^0.16.3", "react-native-localize": "^2.1.7", "react-native-paper": "^4.12.1", "react-native-qrcode-svg": "^6.1.2", "react-native-randombytes": "^3.6.1", "react-native-reanimated": "~2.3.1", - "react-native-safe-area-context": "^4.2.5", + "react-native-safe-area-context": "3.3.2", "react-native-screens": "~3.10.1", "react-native-svg": "^12.3.0", "react-native-uuid": "^2.0.1", diff --git a/src/assets/butch.png b/src/assets/butch.png deleted file mode 100644 index 2eaec22..0000000 Binary files a/src/assets/butch.png and /dev/null differ diff --git a/src/assets/darrell.png b/src/assets/darrell.png deleted file mode 100644 index 6677099..0000000 Binary files a/src/assets/darrell.png and /dev/null differ diff --git a/src/assets/esteban.png b/src/assets/esteban.png deleted file mode 100644 index 537d63b..0000000 Binary files a/src/assets/esteban.png and /dev/null differ diff --git a/src/assets/iog.png b/src/assets/iog.png deleted file mode 100644 index cc0461b..0000000 Binary files a/src/assets/iog.png and /dev/null differ diff --git a/src/assets/lance.png b/src/assets/lance.png deleted file mode 100644 index b3d0773..0000000 Binary files a/src/assets/lance.png and /dev/null differ diff --git a/src/assets/rodo.png b/src/assets/rodo.png deleted file mode 100644 index ab57542..0000000 Binary files a/src/assets/rodo.png and /dev/null differ diff --git a/src/assets/tony.png b/src/assets/tony.png deleted file mode 100644 index c700475..0000000 Binary files a/src/assets/tony.png and /dev/null differ diff --git a/src/models/index.ts b/src/models/index.ts index 5709338..2ec7d46 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,13 +1,11 @@ import { logger } from '../logging'; -const ID_SEPARATOR = "_" - //these types must be unique enough to use in regex without conflict export const MODEL_TYPE_CHAT = "rootsChatType" export const MODEL_TYPE_MESSAGE = "rootsMsgType" export const MODEL_TYPE_CREDENTIAL = "rootsCredentialType" export const MODEL_TYPE_CRED_REQUEST = "rootsCredRequestType" -export const MODEL_TYPE_REL = "rootsRelType" +export const MODEL_TYPE_USER = "rootsUserType" export function createChat(chatAlias: string, titlePrefix?: string) { const chat = { @@ -19,13 +17,13 @@ export function createChat(chatAlias: string, titlePrefix?: string) { return chat; } -export function createMessage(idText: string,bodyText: string,statusText: string,timeInMillis: number,relId: string,system?: boolean=false,cred?: Object=undefined) { +export function createMessage(idText: string,bodyText: string,statusText: string,timeInMillis: number,userId: string,system?: boolean=false,cred?: Object=undefined) { const msg = { id: idText, body: bodyText, type: statusText, createdTime: timeInMillis, - rel: relId, + user: userId, system: system, cred: cred, } @@ -33,27 +31,12 @@ export function createMessage(idText: string,bodyText: string,statusText: string return msg; } -export function createMessageId(chatAlias: string,relId: string,msgNum: number) { - let msgId = getStorageKey(chatAlias,MODEL_TYPE_MESSAGE)+ID_SEPARATOR+relId+ID_SEPARATOR+String(msgNum); - logger("roots - Generated msg id",msgId); - return msgId; -} - -export function createRel(relAlias: string, relName: string, relPicUrl: string) { - const rel = { - id: relAlias, - displayName: relName, - displayPictureUrl: relPicUrl, +export function createUser(userAlias: string, userName: string, userPicUrl: string) { + const user = { + id: userAlias, + displayName: userName, + displayPictureUrl: userPicUrl, } - logger("models - create rel model w/keys",Object.keys(rel)) - return rel; -} - -//---------------- Keys ----------------------- -export function getStorageKey(alias: string,type: string) { - return alias+ID_SEPARATOR+type -} - -export function getStorageKeys(aliases: string[], type: string) { - return aliases.map(alias => getStorageKey(alias,type)) + logger("models - create user model w/keys",Object.keys(user)) + return user; } \ No newline at end of file diff --git a/src/navigation/AuthStack.js b/src/navigation/AuthStack.js index 27c784b..9095620 100644 --- a/src/navigation/AuthStack.js +++ b/src/navigation/AuthStack.js @@ -27,7 +27,6 @@ import CreateWalletScreen from '../screens/CreateWalletScreen'; import ChatListScreen from '../screens/ChatListScreen'; import LoadingScreen from '../screens/LoadingScreen'; import LoginScreen from '../screens/LoginScreen'; -import ScanQRCodeScreen from '../screens/ScanQRCodeScreen' import ShowQRCodeScreen from '../screens/ShowQRCodeScreen' import StartChatScreen from '../screens/StartChatScreen'; @@ -186,15 +185,8 @@ export default function AuthStack() { ({ - headerTitle: (props) => , - headerRight: () => - navigation.navigate('Scan QR Code')} - />, + options={({ route }) => ({ + headerTitle: (props) => })} /> @@ -258,7 +250,6 @@ export default function AuthStack() { - )} diff --git a/src/relationships/index.ts b/src/relationships/index.ts deleted file mode 100644 index 07f1b2b..0000000 --- a/src/relationships/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -import * as models from '../models' -import { logger } from '../logging' -import * as store from '../store' - -import apLogo from '../assets/ATALAPRISM.png'; -import butchLogo from '../assets/butch.png' -import darrellLogo from '../assets/darrell.png' -import estebanLogo from '../assets/esteban.png' -import iogLogo from '../assets/iog.png' -import lanceLogo from '../assets/lance.png' -import perLogo from '../assets/smallBWPerson.png'; -import rodoLogo from '../assets/rodo.png' -import rwLogo from '../assets/LogoOnly1024.png'; -import tonyLogo from '../assets/tony.png' - -export const rootsLogo = rwLogo; -export const personLogo = perLogo; -export const prismLogo = apLogo; - -export const ROOTS_BOT = "did:prism:rootsbot1"; -export const PRISM_BOT = "did:prism:prismbot1"; -export const LIBRARY_BOT = "did:prism:librarybot1"; -const IOG_TECH = "did:prism:iogtech1"; -const ROOTSID = "did:prism:rootsid"; -const LANCE = "did:prism:lance"; -const TONY = "did:prism:tony"; -const DARRELL = "did:prism:darrell"; -const BUTCH = "did:prism:butch"; -const ESTEBAN = "did:prism:esteban"; -const RODO = "did:prism:rodolfo"; - -export const allRelsRegex = new RegExp(models.getStorageKey("",models.MODEL_TYPE_REL)+'*') - -//TODO unify aliases and storageKeys? -export async function createRelItem(alias: string, name: string, pic: string) { - try { - logger("create rel item",alias,name,pic); - if(getRelItem(alias)) { - logger("rels - rel already exists",alias) - return true; - } else { - logger("rels - rel did not exist",alias) - const relItem = models.createRel(alias, name, pic) - const relItemJson = JSON.stringify(relItem) - logger("rels - generated rel",relItemJson) - const result = await store.saveItem(models.getStorageKey(alias, models.MODEL_TYPE_REL), relItemJson) - logger("rels - created rel",alias,"?",result) - return result; - } - } catch(error) { - console.error("Failed to create rel",alias,error,error.stack) - return false - } -} - -export function getRelationships() { - logger("rels - getting rel items") - const relItemJsonArray = store.getItems(allRelsRegex) - logger("rels - got rel items",String(relItemJsonArray)) - const rels = relItemJsonArray.map(relItemJson => JSON.parse(relItemJson)) - return rels; -} - -export function getRelItem(relId) { - logger("rels - Getting rel",relId) - if(relId) { - const relItemJson = store.getItem(models.getStorageKey(relId,models.MODEL_TYPE_REL)); - logger("rels - Got rel json",relItemJson) - if(relItemJson) { - const relItem = JSON.parse(relItemJson) - logger("rels - rel w/keys",Object.keys(relItem)) - return relItem - } else { - logger("rels - rel not found",relId) - return relItemJson - } - } else { - logger("rels - can't get rel for undefined relId",relId) - } -} - -export async function initDemoRels() { - logger("rels - init demo rels") - await createRelItem(ROOTS_BOT,"RootsWallet",rootsLogo) - await createRelItem(PRISM_BOT,"Atala Prism",prismLogo) - await createRelItem(LIBRARY_BOT,"Library",personLogo) - await createRelItem(IOG_TECH, "IOG Tech Community",iogLogo); - await createRelItem(ROOTSID, "RootsID",rootsLogo); - await createRelItem(LANCE, "MeGrimLance",lanceLogo); - await createRelItem(TONY,"Tony.Rose",tonyLogo) - await createRelItem(DARRELL,"Darrell O'Donnell",darrellLogo) - await createRelItem(BUTCH,"Butch Clark",butchLogo) - await createRelItem(ESTEBAN,"Esteban Garcia",estebanLogo) - await createRelItem(RODO,"Rodolfo Miranda",rodoLogo) -} \ No newline at end of file diff --git a/src/roots/index.ts b/src/roots/index.ts index 622b80d..a4fdb05 100644 --- a/src/roots/index.ts +++ b/src/roots/index.ts @@ -3,18 +3,23 @@ import { logger } from '../logging' import PrismModule from '../prism' import { Reply } from 'react-native-gifted-chat'; import * as store from '../store' -import * as rel from '../relationships' import * as walletSchema from '../schemas/WalletSchema' +import rwLogo from '../assets/LogoOnly1024.png' +import perLogo from '../assets/smallBWPerson.png' +import apLogo from '../assets/ATALAPRISM.png' +export const rootsLogo = rwLogo; +export const personLogo = perLogo; +export const prismLogo = apLogo; + //msg types export const BLOCKCHAIN_URI_MSG_TYPE = "blockchainUri"; export const CREDENTIAL_JSON_MSG_TYPE = "jsonCredential"; export const DID_JSON_MSG_TYPE = "jsonDid"; export const PENDING_STATUS_MESSAGE = "rootsPendingStatus"; export const PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE = "rootsAcceptCredential" -export const PROMPT_OWN_CREDENTIAL_MSG_TYPE = "rootsOwnCredential" -export const PROMPT_PUBLISH_MSG_TYPE = "rootsPromptPublish"; -export const PRISM_LINK_MSG_TYPE = "rootsPrismLink" +export const PROMPT_PUBLISH_MSG_TYPE = "promptPublish"; +export const PRISM_LINK_MSG_TYPE = "prismLink" export const QR_CODE_MSG_TYPE = "rootsQRCodeMsgType" export const STATUS_MSG_TYPE = "status"; export const TEXT_MSG_TYPE = "text" @@ -22,22 +27,25 @@ export const TEXT_MSG_TYPE = "text" //meaningful literals export const ACHIEVEMENT_MSG_PREFIX = "You have a new achievement: "; export const PUBLISHED_TO_PRISM = "Published to Prism" -export const SHOW_CRED_QR_CODE = "Show Cred QR code" +export const SHOW_CRED_QR_CODES = "Show Cred QR codes" export const SHOW_DID_QR_CODE = "Show Chat QR code" //state literals export const CRED_ACCEPTED = "credAccepted" export const CRED_REJECTED = "credRejected" export const CRED_SENT = "credSent" -export const CRED_VERIFY = "credVerify" -export const CRED_VIEW = "credView" -export const PUBLISH_DID = "publishDID" -export const DO_NOT_PUBLISH_DID = "doNotPublishDID" -const allChatsRegex = new RegExp(models.getStorageKey("",models.MODEL_TYPE_CHAT)+'*') -const allCredsRegex = new RegExp(models.getStorageKey("",models.MODEL_TYPE_CREDENTIAL)+'*') -const allCredReqsRegex = new RegExp(models.getStorageKey("",models.MODEL_TYPE_CRED_REQUEST)+'*') -const allMsgsRegex = new RegExp(models.getStorageKey("",models.MODEL_TYPE_MESSAGE)+'*') +const ID_SEPARATOR = "_" + +const allChatsRegex = new RegExp(getStorageKey("",models.MODEL_TYPE_CHAT)+'*') +//const allCredsRegex = new RegExp(getStorageKey("",models.MODEL_TYPE_CREDENTIAL)+'*') +const allCredReqsRegex = new RegExp(getStorageKey("",models.MODEL_TYPE_CRED_REQUEST)+'*') +const allMsgsRegex = new RegExp(getStorageKey("",models.MODEL_TYPE_MESSAGE)+'*') +const allUsersRegex = new RegExp(getStorageKey("",models.MODEL_TYPE_USER)+'*') + +const ROOTS_BOT = "RootsWalletBot1" +const PRISM_BOT = "PrismBot1" +const LIBRARY_BOT = "LibraryBot1" export const TEST_WALLET_NAME = "testWalletName" const demo = true; @@ -51,11 +59,11 @@ export async function loadAll(walName: string,walPass: string) { const wallet = await loadWallet(walName, walPass); if(wallet) { const chats = await loadItems(allChatsRegex) - const rels = await loadItems(rel.allRelsRegex); + const users = await loadItems(allUsersRegex); const messages = await loadItems(allMsgsRegex); const credRequests = await loadItems(allCredReqsRegex); - const creds = await loadItems(allCredsRegex); - if(wallet && chats && rels && messages && credRequests) { + //const creds = await loadItems(allCredsRegex); + if(wallet && chats && users && messages && credRequests) { return wallet } else { logger("Failed to load all items") @@ -67,16 +75,70 @@ export async function loadAll(walName: string,walPass: string) { } } +//----------------- User ----------------- +//TODO unify aliases and storageKeys? +async function createUserItem(alias: string, name: string, pic: string) { + try { + if(getUserItem(alias)) { + logger("roots - user already exists",alias) + return true; + } else { + logger("roots - user did not exist",alias) + const userItem = models.createUser(alias, name, pic) + const userItemJson = JSON.stringify(userItem) + logger("generated user",userItemJson) + const result = await store.saveItem(getStorageKey(alias, models.MODEL_TYPE_USER), userItemJson) + logger("roots - created user",alias,"?",result) + return result; + } + } catch(error) { + console.error("Failed to create user",alias,error,error.stack) + return false + } +} + +export function getUserItem(userId) { + logger("roots - Getting user",userId) + if(userId) { + const userItemJson = store.getItem(getStorageKey(userId,models.MODEL_TYPE_USER)); + logger("roots - Got user json",userItemJson) + if(userItemJson) { + const userItem = JSON.parse(userItemJson) + logger("roots - user w/keys",Object.keys(userItem)) + return userItem + } else { + logger("roots - user not found",userId) + return userItemJson + } + } else { + logger("roots - can't get user for undefined userId",userId) + } +} + +async function loadUsers() { + try { + const aliases = getAllDidAliases(currentWal); + const result = await store.restoreItems(getStorageKeys(aliases,models.MODEL_TYPE_USER)); + if(result) { + logger("roots - successfully loaded chat items",aliases) + return true; + } + else { + console.error("roots - Failed to load chat items",aliases) + return false; + } + } catch(error) { + console.error("roots - Failed to load chat items",error,error.stack) + return false; + } +} + //----------------- Wallet --------------------- export async function createWallet(walName,mnemonic,walPass) { const prismWal = PrismModule.newWal(walName,mnemonic,walPass) const result = await updateWallet(walName,walPass,prismWal) if(result) { logger('Wallet created',store.getWallet(currentWal._id)) - if(demo) { - logger("roots - initializing demo") - await initDemo() - } return result; } else { logger('Could not create wallet',walName,walPass) @@ -197,16 +259,16 @@ export async function createChat (chatAlias, titlePrefix) { logger("roots - chat item created/existed?",chatItemCreated) const chatItem = getChatItem(chatDidAlias) logger("roots - chat item",chatItem) - //TODO what should the rel defaults be? - const chatRelCreated = await rel.createRelItem(chatDidAlias,"You",rel.personLogo) - logger("roots - chat rel created/existed?",chatRelCreated) - const chatRel = rel.getRelItem(chatDidAlias) + //TODO what should the user defaults be? + const chatUserCreated = await createUserItem(chatDidAlias,"You",personLogo) + logger("roots - chat user created/existed?",chatUserCreated) + const chatUser = getUserItem(chatDidAlias) - if(chatDidCreated && chatItemCreated && chatRelCreated) { - const sentWelcome = await sendMessage(chatItem,"Welcome to *"+chatAlias+"*",TEXT_MSG_TYPE,rel.getRelItem(rel.ROOTS_BOT)) + if(chatDidCreated && chatItemCreated && chatUserCreated) { + const sentWelcome = await sendMessage(chatItem,"Welcome to *"+chatAlias+"*",TEXT_MSG_TYPE,getUserItem(ROOTS_BOT)) if(sentWelcome) { await sendMessage(chatItem,"Would you like to publish this chat to Prism?", - PROMPT_PUBLISH_MSG_TYPE,rel.getRelItem(rel.PRISM_BOT)) + PROMPT_PUBLISH_MSG_TYPE,getUserItem(PRISM_BOT)) logger("Created chat and added welcome to chat",chatAlias,"with chatDid",chatDidAlias) } return true; @@ -224,7 +286,7 @@ async function createChatItem(chatAlias: string, titlePrefix: string) { return true } else { const chatItem = models.createChat(chatAlias, [], titlePrefix) - const savedChat = await store.saveItem(models.getStorageKey(chatAlias, models.MODEL_TYPE_CHAT), JSON.stringify(chatItem)) + const savedChat = await store.saveItem(getStorageKey(chatAlias, models.MODEL_TYPE_CHAT), JSON.stringify(chatItem)) if(savedChat) { logger('roots - new chat saved',chatAlias) return true @@ -238,7 +300,10 @@ async function createChatItem(chatAlias: string, titlePrefix: string) { //TODO iterate to verify DID connections if cache is expired export async function getAllChats () { const allChats = getChatItems(); - + if(allChats.length == 0 && demo) { + logger("roots - adding demo to chats") + await initDemo() + } const result = {paginator: {items: allChats}}; result.paginator.items.forEach(function (item, index) { logger("roots - getting chats",index+".",item.id); @@ -248,7 +313,7 @@ export async function getAllChats () { export function getChatItem(chatAlias: string) { logger("roots - getting chat item",chatAlias) - const chatJson = store.getItem(models.getStorageKey(chatAlias,models.MODEL_TYPE_CHAT)) + const chatJson = store.getItem(getStorageKey(chatAlias,models.MODEL_TYPE_CHAT)) logger("roots - got chat",chatJson) if(chatJson) { const chat = JSON.parse(chatJson) @@ -283,7 +348,7 @@ function getAllDidAliases(wallet) { async function loadChats() { try { const aliases = getAllDidAliases(currentWal); - const result = await store.restoreItems(models.getStorageKeys(aliases,models.MODEL_TYPE_CHAT)); + const result = await store.restoreItems(getStorageKeys(aliases,models.MODEL_TYPE_CHAT)); if(result) { logger("roots - successfully loaded chat items",aliases) return true; @@ -302,6 +367,7 @@ async function loadChats() { export async function publishChat(chat: Object) { if(!chat["published"]) { logger("roots - Publishing DID",chat.id,"to Prism") + isProcessing(true) try { const newWalJson = await PrismModule.publishDid(store.getWallet(currentWal._id), chat.id) const result = await updateWallet(currentWal._id,currentWal.passphrase,newWalJson) @@ -312,18 +378,22 @@ export async function publishChat(chat: Object) { const savedChat = await updateChat(chat); if(savedChat) { logger("Chat for published DID saved",chat.id) + isProcessing(false) return chat } else { //TODO since wallet is updated, should try to save chat again and again until successful logger("Could not save chat for published DID",chat.id) + isProcessing(false) return; } } else { logger("roots - During publish, could not update wallet") + isProcessing(false) return; } } catch(error) { logger("roots - Error publishing chat/DID",chat.id,error,error.stack) + isProcessing(false) } } else { logger("roots - ",chat.id,"is already",PUBLISHED_TO_PRISM) @@ -332,7 +402,7 @@ export async function publishChat(chat: Object) { } async function updateChat(chat: Object) { - const chatStoreId = models.getStorageKey(chat.id,models.MODEL_TYPE_CHAT); + const chatStoreId = getStorageKey(chat.id,models.MODEL_TYPE_CHAT); const updated = await store.updateItem(chatStoreId,JSON.stringify(chat)); if(updated) { logger("Updated chat storage",chatStoreId); @@ -366,6 +436,12 @@ function addMessageExtensions(msg) { return msg } +function createMessageId(chatAlias: string,userId: string,msgNum: number) { + let msgId = getStorageKey(chatAlias,models.MODEL_TYPE_MESSAGE)+ID_SEPARATOR+userId+ID_SEPARATOR+String(msgNum); + logger("roots - Generated msg id",msgId); + return msgId; +} + export function getMessages(chatAlias: string, startFromMsgId?: string) { const chMsgs = getMessageItems(chatAlias) logger("roots - Getting chat",chatAlias,chMsgs.length,"messages") @@ -395,7 +471,7 @@ export function getMessages(chatAlias: string, startFromMsgId?: string) { export function getMessageItems(chatAlias: string) { logger("roots - getting message items for chat",chatAlias) - const msgRegex = new RegExp('^'+models.getStorageKey(chatAlias,models.MODEL_TYPE_MESSAGE)+'*') + const msgRegex = new RegExp('^'+getStorageKey(chatAlias,models.MODEL_TYPE_MESSAGE)+'*') const msgItemJsonArray = store.getItems(msgRegex) logger("roots - got msg items",msgItemJsonArray.length) const chatMsgs = msgItemJsonArray.map( @@ -425,27 +501,25 @@ async function loadItems(regex: RegExp) { } } -export async function sendMessages(chat,msgs,msgType,relDisplay) { - msgs.map(async (msg) => await sendMessage(chat,msg.text,msgType,relDisplay)) +export async function sendMessages(chat,msgs,msgType,userDisplay) { + msgs.map(async (msg) => await sendMessage(chat,msg.text,msgType,userDisplay)) } //TODO unify aliases and storageKeys? -export async function sendMessage(chat,msgText,msgType,relDisplay,system=false,cred=undefined) { +export async function sendMessage(chat,msgText,msgType,userDisplay,system=false,cred=undefined) { const msgTime = Date.now() - logger("roots - rel",relDisplay.id,"sending\"",msgText,"\"to chat:",chat.id); - const msgId = models.createMessageId(chat.id,relDisplay.id,msgTime); - let msg = models.createMessage(msgId, msgText, msgType, msgTime, relDisplay.id, system, cred); + logger("roots - user",userDisplay.id,"sending",msgText,"to chat",chat.id); + const msgId = createMessageId(chat.id,userDisplay.id,msgTime); + let msg = models.createMessage(msgId, msgText, msgType, msgTime, userDisplay.id, system, cred); msg = addMessageExtensions(msg); try { - const msgJson = JSON.stringify(msg) - const result = await store.saveItem(msg.id,msgJson) + const result = await store.saveItem(msg.id,JSON.stringify(msg)) if(handlers["onReceivedMessage"]) { handlers["onReceivedMessage"](msg) } - logger("Sent/Stored message",msgJson) return msg } catch(error) { - console.error("Could not save message for rel",relDisplay.id,"w/msg",msgText,"to chat",chat.id,error,error.stack) + console.error("Could not save message for user",userDisplay.id,"w/msg",msgText,"to chat",chat.id,error,error.stack) return; } } @@ -453,18 +527,11 @@ export async function sendMessage(chat,msgText,msgType,relDisplay,system=false,c function addQuickReply(msg) { if(msg.type === PROMPT_PUBLISH_MSG_TYPE) { msg["quickReplies"] = {type: 'checkbox',keepIt: true, - values: [ - { - title: 'Add to Prism', - value: PROMPT_PUBLISH_MSG_TYPE+PUBLISH_DID, - messageId: msg.id, - }, - { - title: 'Keep private', - value: PROMPT_PUBLISH_MSG_TYPE+DO_NOT_PUBLISH_DID, + values: [{ + title: 'Yes', + value: PROMPT_PUBLISH_MSG_TYPE, messageId: msg.id, - } - ], + }], } } if(msg.type === PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE) { @@ -472,35 +539,21 @@ function addQuickReply(msg) { type: 'checkbox', keepIt: true, values: [{ - title: 'Accept', + title: 'Yes', value: PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE+CRED_ACCEPTED, - messageId: msg.id, - }, + messageId: msg.id,}, { - title: 'Reject', + title: 'No Thx!', value: PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE+CRED_REJECTED, messageId: msg.id, - } - ], - } - } - if(msg.type === PROMPT_OWN_CREDENTIAL_MSG_TYPE) { - msg["quickReplies"] = { - type: 'checkbox', - keepIt: true, - values: [ - { - title: 'View', - value: PROMPT_OWN_CREDENTIAL_MSG_TYPE+CRED_VIEW, - messageId: msg.id, - }] + }], } } return msg } -export async function processCredentialResponse(chat: Object, reply: Object) { - logger("roots - quick reply credential",chat.id,reply) +async function processCredentialResponse(chat: Object, reply: Object) { + logger("roots - Quick reply credential",chat.id,reply) const credReqAlias = getCredRequestAlias(reply.messageId) const replyJson = JSON.stringify(reply) //TODO should we allow updates to previous credRequest response? @@ -511,13 +564,7 @@ export async function processCredentialResponse(chat: Object, reply: Object) { } else { if(reply.value.endsWith(CRED_ACCEPTED)) { logger("roots - quick reply credential accepted",credReqAlias) - isProcessing(true) const accepted = await acceptCredential(chat, reply) - if(accepted) { - const credOwnMsg = await sendMessage(chat,"Credential accepted.",PROMPT_OWN_CREDENTIAL_MSG_TYPE,rel.getRelItem(rel.ROOTS_BOT)) - store.saveItem(getCredentialAlias(credOwnMsg.id),await getCredentialByMsgId(reply.messageId)) - } - isProcessing(false) return accepted; } else if (reply.value.endsWith(CRED_REJECTED)) { logger("roots - quick reply credential rejected",credReqAlias) @@ -529,38 +576,21 @@ export async function processCredentialResponse(chat: Object, reply: Object) { } } -export async function processPublishResponse(chat: Object, reply: Reply) { +async function processPublishResponse(chat: Object, reply: Reply) { logger("roots - Quick reply, started publsih chat",chat.id) - isProcessing(true) const pubChat = await publishChat(chat); - isProcessing(false) if(pubChat) { const linkMsg = await sendMessage(pubChat,"Your chat \""+pubChat.id+"\" has been" +"\t\t"+PUBLISHED_TO_PRISM+"\t\t"+SHOW_DID_QR_CODE +"\nhttps://explorer.cardano-testnet.iohkdev.io/en/transaction?id=0ce00bc602ef54dfc52b4106bebcafb72c2447bdf666cd609d50fd3a7e9d2474", - TEXT_MSG_TYPE,rel.getRelItem(rel.PRISM_BOT)) + TEXT_MSG_TYPE,getUserItem(PRISM_BOT)) if(linkMsg) { - const didMsg = await sendMessage(chat,JSON.stringify(getDid(chat.id)),DID_JSON_MSG_TYPE,rel.getRelItem(rel.PRISM_BOT),true); + const didMsg = await sendMessage(chat,JSON.stringify(getDid(chat.id)),DID_JSON_MSG_TYPE,getUserItem(PRISM_BOT),true); if(demo && didMsg) { - logger("roots - quick reply demo celebrating with credential",chat.id) await sendMessage(chat, - "To celebrate your publishing achievement a verifiable credential is being created for you.", - TEXT_MSG_TYPE,rel.getRelItem(rel.ROOTS_BOT)) - const cred = await issueDemoCredential(chat, reply) - logger("roots - quick reply demo credential issued",cred) - const credReqMsg = await sendMessage(chat, - "Do you want to accept this verifiable credential", - PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE,rel.getRelItem(rel.ROOTS_BOT)) - if(credReqMsg) { - const credAlias = getCredentialAlias(credReqMsg.id) - const credJson = JSON.stringify(cred.verifiedCredential) - logger("roots - cred request prepared",credAlias,credJson) - const savedCredReq = await store.saveItem(credAlias, credJson); - if(savedCredReq) { - logger("Successfully submitted demo cred req",credAlias,credJson) - } - } + "To celebrate your publishing achievement, can we send you a verifiable credential?", + PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE,getUserItem(ROOTS_BOT)) } } return pubChat @@ -576,19 +606,14 @@ export async function processQuickReply(chat: Object,replies: Object[]) { replies.forEach(async (reply) => { logger("roots - processing quick reply",chat.id,reply) - if(reply.value.startsWith(PROMPT_PUBLISH_MSG_TYPE)) { + if(reply.value === PROMPT_PUBLISH_MSG_TYPE) { logger("roots - process quick reply to publish DID") - if(reply.value.endsWith(PUBLISH_DID)) { - logger("roots - publishing DID") - return await processPublishResponse(chat,reply) - } else { - logger("roots - not publishing DID") - return; - } + return await processPublishResponse(chat,reply) } else if(reply.value.startsWith(PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE)) { - logger("roots - process quick reply for accepting credential") + logger("roots - process quick reply for credential") return await processCredentialResponse(chat,reply) - } else { + } + else { logger("roots - reply value not recognized, was",chat.id,reply.value) return; } @@ -602,141 +627,116 @@ export async function processQuickReply(chat: Object,replies: Object[]) { // ------------------ Credentials ---------- async function acceptCredential(chat: Object, reply: Object) { - const credAlias = getCredentialAlias(reply.messageId); - const verCredJson = await store.getItem(credAlias); - const verCred = JSON.parse(verCredJson) - const credHash = verCred.proof.hash - if (!getCredByHash(credHash)) { - logger("roots - accepting credential",credAlias,verCredJson) - const newWalJson = await PrismModule.importCred(store.getWallet(currentWal._id), credAlias, verCredJson); - if(newWalJson) { - const savedWal = await updateWallet(currentWal._id,currentWal.passphrase,newWalJson) - if(savedWal) { - const newCred = await getCredentialByMsgId(reply.messageId) - logger("Accepted credential",newCred.alias) - return true - } else { - console.error("Could not accept credential, unable to save wallet",credAlias,credHash) - return false - } - } else { - console.error("Could not import accepted credential",credAlias,credHash) - return false - } + if(demo) { + await createDemoCredential(chat, reply) } else { - console.error("Credential alias already in use",credAlias,credHash) - return false + //TODO accept non-demo credentials } } -export function getCredByHash(credHash: string) { - logger("roots - Getting imported credential",credHash) - - if(currentWal["importedCredentials"]) { - const cred = currentWal["importedCredentials"].find(cred => { - const curCredHash = cred.verifiedCredential.proof.hash - if(curCredHash === credHash) { - logger("roots - Found cred hash",curCredHash) +async function createCredential(chat: Object,credAlias: string,cred: Object) { + const credJson = JSON.stringify(cred) + logger("roots - issuing credential", credJson) + isProcessing(true) + const newWalJson = await PrismModule.issueCred(store.getWallet(currentWal._id), chat.id, credJson); + if(newWalJson) { + const savedWal = await updateWallet(currentWal._id,currentWal.passphrase,newWalJson) + if(savedWal) { + const newCred = getCredential(cred.alias) + //const saveCred = await saveCred(cred.alias) + const credIssuedMsg = await sendMessage(chat,"Here is your new credential that we\t\t" + PUBLISHED_TO_PRISM+"\t\t"+SHOW_CRED_QR_CODES+"\nhttps://explorer.cardano-testnet.iohkdev.io/en/transaction?id=0ce00bc602ef54dfc52b4106bebcafb72c2447bdf666cd609d50fd3a7e9d2474", + STATUS_MSG_TYPE, + getUserItem(ROOTS_BOT),false,newCred) + //const code = await QRCode.toDataURL() + if(credIssuedMsg) { + const credJsonMsg = await sendMessage(chat,JSON.stringify(newCred), + CREDENTIAL_JSON_MSG_TYPE, + getUserItem(PRISM_BOT),true) + isProcessing(false) + return true + } else { + console.warn("Unable to send confirmation msg after issuing cred") + isProcessing(false) return true } - else { - logger("roots - cred hash",curCredHash,"does not match",credHash) - return false - } - }) - if(cred) { - return cred + } else { + console.error("Could not create/issue credential, unable to save wallet") + isProcessing(false) + return false } } else { - logger("roots - No imported credential hash",credHash) - return; + console.error("Could not create/issue credential") + isProcessing(false) + return false } } -function getCredentialAlias(msgId) { - return msgId.replace(models.MODEL_TYPE_MESSAGE,models.MODEL_TYPE_CREDENTIAL) -} - -export async function getCredentialByMsgId(msgId) { - return await store.getItem(getCredentialAlias(msgId)) -} - -function getCredRequestAlias(msgId) { - return msgId.replace(models.MODEL_TYPE_MESSAGE,models.MODEL_TYPE_CRED_REQUEST) -} - -export function getIssuedCredential(credAlias) { - logger("roots - getting issued credential",credAlias) - +export function getCredentials(chatAlias: string) { + logger("roots - Getting credentials",chatAlias) + const longDid = getDid(chatAlias).uriLongForm if(currentWal["issuedCredentials"]) { - const cred = currentWal["issuedCredentials"].find(cred => { - if(cred["alias"] === credAlias) { + const creds = currentWal["issuedCredentials"].filter(cred => { + if(cred.claim.subjectDid === longDid) { logger("roots - Found alias",cred["alias"]) return true } else { - logger("roots - Alias",cred["alias"],"does not match",credAlias) + logger("roots - Alias",cred.claim.subjectDid,"is not",longDid) return false } }) - if(cred) { - logger("roots - got issued cred",cred) - return cred + if(creds && creds.length > 0) { + return creds } } else { - logger("roots - No issued credential for",credAlias) - return; + logger("roots - No issued credentials for",chatAlias) } + return; } -export function getIssuedCredentials(chatAlias: string) { - logger("roots - Getting issued credentials",chatAlias) - const longDid = getDid(chatAlias).uriLongForm +export function getCredential(credAlias) { + logger("roots - Getting credential",credAlias) + if(currentWal["issuedCredentials"]) { const creds = currentWal["issuedCredentials"].filter(cred => { - if(cred.claim.subjectDid === longDid) { + if(cred["alias"] === credAlias) { logger("roots - Found alias",cred["alias"]) return true } else { - logger("roots - Alias",cred.claim.subjectDid,"does not match",longDid) + logger("roots - Alias",cred["alias"],"is not",credAlias) return false } }) if(creds && creds.length > 0) { - return creds + return creds[0] } } else { - logger("roots - No issued credentials for",chatAlias) + logger("roots - No issued credentials") } return; } -async function issueCredential(chat: Object,credAlias: string,cred: Object) { - const credJson = JSON.stringify(cred) - logger("roots - issuing credential", credJson) - const newWalJson = await PrismModule.issueCred(store.getWallet(currentWal._id), chat.id, credJson); - if(newWalJson) { - const savedWal = await updateWallet(currentWal._id,currentWal.passphrase,newWalJson) - if(savedWal) { - const newCred = getIssuedCredential(cred.alias) - logger("roots - Issued credential",newCred.alias) - return newCred - } else { - console.error("roots - Could not issue credential, unable to save wallet") - return; - } - } else { - console.error("roots - Could not issue credential") - return; - } +function getCredentialAlias(msgId) { + return msgId.replace(models.MODEL_TYPE_MESSAGE,models.MODEL_TYPE_CREDENTIAL) +} + +export function getCredentialByMsgId(msgId) { + return getCredential(getCredentialAlias(msgId)) +} + +function getCredRequestAlias(msgId) { + return msgId.replace(models.MODEL_TYPE_MESSAGE,models.MODEL_TYPE_CRED_REQUEST) } -function verifyCredential(credAlias: string) { - //TODO fix gradle build problems so that we can verify. - logger("Verifying credential not implemented yet",credAlias) - //const errorArray = JSON.parse(PrismModule.verifyCred(credAlias)) -// logger("Credential verification not implemented yet",credAlias,errorArray) +//---------------- Keys ----------------------- + +function getStorageKey(alias: string,type: string) { + return alias+ID_SEPARATOR+type +} + +function getStorageKeys(aliases: string[], type: string) { + return aliases.map(alias => getStorageKey(alias,type)) } // ------------------ Session --------------- @@ -780,11 +780,11 @@ export function isProcessing(processing=false) { //----------- DEMO Stuff -------------------- -export async function issueDemoCredential(chat: Object,reply: Object) { +export async function createDemoCredential(chat: Object,reply: Object) { logger("roots - Trying to create demo credential for chat",chat.id,reply) const credMsgs = [] const credAlias = getCredentialAlias(reply.messageId) - if(chat["published"] && !getIssuedCredential(credAlias)) { + if(chat["published"] && !getCredential(credAlias)) { logger("roots - Chat is published and credential not found, creating....") const didLong = getDid(chat.id)[walletSchema.DID_URI_LONG_FORM] logger("roots - Creating demo credential for chat",chat.id,"w/long form did",didLong) @@ -808,44 +808,40 @@ export async function issueDemoCredential(chat: Object,reply: Object) { operationHash: "", revoked: false, } - logger("roots - issuing demo credential",cred) - isProcessing(true) - const issuedCred = await issueCredential(chat, credAlias, cred) - isProcessing(false) - return issuedCred; + return await createCredential(chat, credAlias, cred) } else { - logger("roots - Couldn't issue demo credential, is the chat published",chat["published"],"was the credential already found",getIssuedCredential(credAlias)) - return false + logger("roots - Couldn't create demo credential, is the chat published",chat["published"],"was the credential already found",getCredential(credAlias)) + return false; } // sendMessage(chat,"Valid credential", // STATUS_MSG_TYPE, -// rel.getRelDisplay(rel.ROOTS_BOT)) +// getUserDisplay(ROOTS_BOT)) // // -// sendMessage(chat,"Credential imported" +// sendMessage(chat,"Credential imported", // STATUS_MSG_TYPE, -// rel.getRelDisplay(rel.ROOTS_BOT)) +// getUserDisplay(ROOTS_BOT)) // sendMessage(chat,"Valid credential.", // STATUS_MSG_TYPE, -// rel.getRelDisplay(rel.ROOTS_BOT)) +// getUserDisplay(ROOTS_BOT)) // sendMessage(chat,"https://explorer.cardano-testnet.iohkdev.io/en/transaction?id=0ce00bc602ef54dfc52b4106bebcafb72c2447bdf666cd609d50fd3a7e9d2474", // BLOCKCHAIN_URI_MSG_TYPE, - // rel.getRelDisplay(rel.PRISM_BOT)) + // getUserDisplay(PRISM_BOT)) // sendMessage(chat,"Credential revoked", // STATUS_MSG_TYPE, -// rel.getRelDisplay(rel.ROOTS_BOT)) +// getUserDisplay(ROOTS_BOT)) // sendMessage(chat,"Invalid credential.", // STATUS_MSG_TYPE, -// rel.getRelDisplay(rel.ROOTS_BOT)) +// getUserDisplay(ROOTS_BOT)) } async function initDemo() { - const rels = await rel.initDemoRels() + const users = await initDemoUserDisplays() const intro = await initDemoIntro() // const achievements = await initDemoAchievements() // const library = await initDemoLibrary() // const resume = await initDemoResume() - const result = (rels && intro) + const result = (users && intro) return result; } @@ -854,16 +850,16 @@ async function initDemoAchievements() { await sendMessage(achieveCh,ACHIEVEMENT_MSG_PREFIX+"Opened RootsWallet!", STATUS_MSG_TYPE, - rel.getRelItem(rel.ROOTS_BOT)) + getUserItem(ROOTS_BOT)) await sendMessage(achieveCh,"{subject: you,issuer: RootsWallet,credential: Opened RootsWallet}", CREDENTIAL_JSON_MSG_TYPE, - rel.getRelItem(rel.ROOTS_BOT)) + getUserItem(ROOTS_BOT)) await sendMessage(achieveCh,ACHIEVEMENT_MSG_PREFIX+"Clicked Example!", STATUS_MSG_TYPE, - rel.getRelItem(rel.ROOTS_BOT)) + getUserItem(ROOTS_BOT)) await sendMessage(achieveCh,"{subject: you,issuer: RootsWallet,credential: Clicked Example}", CREDENTIAL_JSON_MSG_TYPE, - rel.getRelItem(rel.ROOTS_BOT)) + getUserItem(ROOTS_BOT)) } async function initDemoIntro() { @@ -879,6 +875,19 @@ async function initDemoResume() { const resumeCh = await createChat("Resume/CV Chat","Coming Soon - ") } +async function initDemoUserDisplays() { + await createUserItem(ROOTS_BOT, + "RootsWallet", + rootsLogo) + await createUserItem(PRISM_BOT, + "Atala Prism", + prismLogo) + await createUserItem( + LIBRARY_BOT, + "Library", + personLogo) +} + export function isDemo() { return demo } diff --git a/src/screens/ChatScreen.js b/src/screens/ChatScreen.js index 84a20fb..839173b 100644 --- a/src/screens/ChatScreen.js +++ b/src/screens/ChatScreen.js @@ -7,8 +7,13 @@ import { Actions, ActionsProps, Bubble, ChatInput, //import { useInterval } from 'usehooks-ts' //import { BarCodeScanner } from 'expo-barcode-scanner'; //import emojiUtils from 'emoji-utils'; -import {getRelItem} from '../relationships' -import * as roots from '../roots'; + +import { BLOCKCHAIN_URI_MSG_TYPE, createDemoCredential, getMessages, + getChatItem, getCredentials, getDid, getFakePromise, + getFakePromiseAsync, getQuickReplyResultMessage, getUserItem, isDemo, isProcessing, + processQuickReply, PUBLISHED_TO_PRISM, + sendMessage, sendMessages, startChatSession, + TEXT_MSG_TYPE } from '../roots'; import Loading from '../components/Loading'; const { PrismModule } = NativeModules; @@ -16,7 +21,7 @@ const { PrismModule } = NativeModules; export default function ChatScreen({ route, navigation }) { console.log("ChatScreen - route params",route.params) // const [ user, setUser ] = useState(user); - const [chat, setChat] = useState(roots.getChatItem(route.params.chatId)); + const [chat, setChat] = useState(getChatItem(route.params.chatId)); console.log("ChatScreen - got chatItem ",chat) // const [hasPermission, setHasPermission] = useState(null); const [loading, setLoading] = useState(true); @@ -29,7 +34,7 @@ export default function ChatScreen({ route, navigation }) { useEffect(() => { let isCancelled = false; console.log("ChatScreen - useEffect",chat) - const chatSession = roots.startChatSession({ + const chatSession = startChatSession({ chat: chat, onReceivedMessage: (message) => { if (!isCancelled) { @@ -100,7 +105,7 @@ export default function ChatScreen({ route, navigation }) { useEffect(() => { console.log("ChatScreen - getting all messages") - const msgs = roots.getMessages(chat.id) + const msgs = getMessages(chat.id) console.log("ChatScreen - got",msgs.length,"msgs") msgs.forEach(msg => console.log("ChatScreen - got msg w/keys",Object.keys(msg))) //const msgs = {paginator: {items: }} @@ -155,53 +160,21 @@ export default function ChatScreen({ route, navigation }) { async function handleSend(pendingMsgs) { console.log("ChatScreen - handle send",pendingMsgs) - const result = await roots.sendMessages(chat, pendingMsgs, roots.TEXT_MSG_TYPE, getRelItem(chat.id)); + const result = await sendMessages(chat, pendingMsgs, TEXT_MSG_TYPE, getUserItem(chat.id)); // await setMessages((prevMessages) => GiftedChat.append(prevMessages, pendingMsgs)); } //getFakePromiseAsync(10000); //processQuickReply(chat,reply) - async function handleQuickReply(replies) { - console.log("ChatScreen - Processing Quick Reply w/ chat",chat.id,"w/ replies",replies.length) - if(replies) { - replies.forEach(async (reply) => - { - console.log("ChatScreen - processing quick reply",chat.id,reply) - if(reply.value.startsWith(roots.PROMPT_PUBLISH_MSG_TYPE)) { - console.log("ChatScreen - process quick reply to publish DID") - if(reply.value.endsWith(roots.PUBLISH_DID)) { - console.log("ChatScreen - publishing DID") - const pubChat = await roots.processPublishResponse(chat,reply) - setChat(pubChat) - } else { - console.log("ChatScreen - not publishing DID") - } - } else if(reply.value.startsWith(roots.PROMPT_ACCEPT_CREDENTIAL_MSG_TYPE)) { - console.log("ChatScreen - process quick reply for accepting credential") - const res = await roots.processCredentialResponse(chat,reply) - console.log("ChatScreen - credential accepted?",res) - } else if(reply.value.startsWith(roots.PROMPT_OWN_CREDENTIAL_MSG_TYPE)) { - console.log("ChatScreen - process quick reply for owned credential") - if (reply.value.endsWith(roots.CRED_VERIFY)) { - console.log("ChatScreen - quick reply verify credential",) - const verify = await roots.verifyCredential(chat, reply) - console.log("ChatScreen - credential verification result",verify) - } else if (reply.value.endsWith(roots.CRED_VIEW)) { - console.log("ChatScreen - quick reply view credential") - const cred = await roots.getCredentialByMsgId(reply.messageId) - const credJson = JSON.stringify(cred) - console.log("View credential",credJson); - showQR(JSON.stringify(credJson)) - } - } else { - console.log("ChatScreen - reply value not recognized, was",chat.id,reply.value) - return; - } - }); - } else { - console.log("ChatScreen - reply",replies,"or chat",chat,"were undefined") - return; + async function handleQuickReply(reply) { + console.log("ChatScreen - handle quick reply",reply) + const pubChat = await processQuickReply(chat,reply) + if(pubChat) { + setChat(pubChat) + console.log("ChatScreen - Quick Reply processing complete", pubChat) } +// await setMessages((prevMessages) => +// GiftedChat.append(prevMessages,resultMessages.map((resultMessage) => mapMessage(resultMessage)))); } //function renderActions(props: Readonly) { @@ -221,7 +194,7 @@ export default function ChatScreen({ route, navigation }) { //#fad58b function renderBubble(props) { - //console.log("render bubble with props",props.currentMessage) + console.log("render bubble with props",props.currentMessage) return ( b.createdAt - a.createdAt)} - onPress={ (context, message) => console.log("bubble pressed",context,message)} + onPress={ (context, message) => console.log("bubble pressed")} onQuickReply={reply => handleQuickReply(reply)} onSend={messages => handleSend(messages)} parsePatterns={(linkStyle) => [ @@ -387,8 +360,13 @@ export default function ChatScreen({ route, navigation }) { { pattern: /Show Chat QR code/, style: styles.qr, - onPress: (tag) => showQR(roots.getDid(chat.id).uriLongForm), + onPress: (tag) => showQR([getDid(chat.id).uriLongForm]), }, + { + pattern: /Show Cred QR codes/, + style: styles.qr, + onPress: (tag) => {showQR(getCredentials(chat.id).map(cred => cred.verifiedCredential))}, + } //{type: 'url', style: styles.url, onPress: onUrlPress}, ]} //placeholder={"Type your message"} @@ -399,7 +377,7 @@ export default function ChatScreen({ route, navigation }) { renderBubble={renderBubble} renderUsernameOnMessage={true} showAvatarForEveryMessage={true} - user={mapUser(getRelItem(chat.id))} + user={mapUser(getUserItem(chat.id))} /> ); @@ -415,7 +393,7 @@ export default function ChatScreen({ route, navigation }) { mappedMsg["_id"] = message.id mappedMsg["text"] = message.body mappedMsg["createdAt"] = new Date(message.createdTime) - mappedMsg["user"] = mapUser(getRelItem(message.rel)) + mappedMsg["user"] = mapUser(getUserItem(message.user)) if(message["image"]) { mappedMsg["image"] = message["image"] } @@ -445,12 +423,12 @@ export default function ChatScreen({ route, navigation }) { return mappedMsg; } - function mapUser(rel) { - console.log("ChatScreen - Map User for gifted",rel); + function mapUser(user) { + console.log("ChatScreen - Map User for gifted",user); return { - _id: rel.id, - name: rel.displayName, - avatar: rel.displayPictureUrl, + _id: user.id, + name: user.displayName, + avatar: user.displayPictureUrl, }; } diff --git a/src/screens/RelationshipsScreen.js b/src/screens/RelationshipsScreen.js index 5830cbe..7659bd3 100644 --- a/src/screens/RelationshipsScreen.js +++ b/src/screens/RelationshipsScreen.js @@ -1,7 +1,7 @@ import React, {useState} from 'react'; -import {FlatList, Image, SafeAreaView, StyleSheet, Text, View, TouchableOpacity} from 'react-native'; +import {FlatList, SafeAreaView, StyleSheet, Text, View, TouchableOpacity} from 'react-native'; import { Divider, List } from 'react-native-paper'; -import {getRelationships} from '../relationships' +import {getRelationships} from '../utils/relationshipsManager' import {getCredentials} from '../utils/credentialsRetriever' import Relationship from '../models/relationship' import styles from "../styles/styles"; @@ -11,7 +11,7 @@ const RelationshipsScreen = ({route,navigation}) => { const {walletName} = route.params console.log(`walletName: ${walletName}`) - const relationships = getRelationships(walletName).filter(rel => rel.displayName !== 'You') + const relationships = getRelationships(walletName) const goToRel = (key) => { console.log(`> RelationshipsScr.pressHandler( ${key})`) @@ -42,33 +42,17 @@ const RelationshipsScreen = ({route,navigation}) => { item.id} + keyExtractor={(item) => item.key} ItemSeparatorComponent={() => } renderItem={({ item }) => ( - - - - - - - goToRel(item)} - /> - - - + goToRel(item)} + /> )} /> diff --git a/src/screens/ScanQRCodeScreen.js b/src/screens/ScanQRCodeScreen.js deleted file mode 100644 index b30799f..0000000 --- a/src/screens/ScanQRCodeScreen.js +++ /dev/null @@ -1,74 +0,0 @@ -import { useEffect, useState } from 'react'; -import { - Animated, - View, - Text, - Pressable, - Button, - StyleSheet, -} from 'react-native'; -import { useTheme } from '@react-navigation/native'; -import { useCardAnimation } from '@react-navigation/stack'; -import { BarCodeScanner } from 'expo-barcode-scanner'; - -import {logger} from '../logging'; -import { prismLogo } from '../roots' -//import styles from "../styles/styles"; - -export default function ScanQRCodeScreen({ route, navigation }) { - logger("scan qr code - ") - const [hasPermission, setHasPermission] = useState(null); - const [scanned, setScanned] = useState(false); - const { colors } = useTheme(); - const { current } = useCardAnimation(); - - useEffect(() => { - (async () => { - const { status } = await BarCodeScanner.requestPermissionsAsync(); - setHasPermission(status === 'granted'); - })(); - }, []); - - const handleBarCodeScanned = ({ type, data }) => { - setScanned(true); - alert(`Bar code with type ${type} and data ${data} has been scanned!`); - }; - - if (hasPermission === null) { - return Requesting for camera permission; - } - if (hasPermission === false) { - return No access to camera; - } - - return ( - - - - - {scanned &&