diff --git a/app/mobile/src/constants/Colors.js b/app/mobile/src/constants/Colors.js
index 4ea1cdc8..33e2bc65 100644
--- a/app/mobile/src/constants/Colors.js
+++ b/app/mobile/src/constants/Colors.js
@@ -21,7 +21,7 @@ export const Colors = {
itemDivider: '#eeeeee',
- connected: '#44cc44',
+ connected: '#4488FF',
connecting: '#dd88ff',
requested: '#4488ff',
pending: '#22aaaa',
diff --git a/app/mobile/src/context/useCardContext.hook.js b/app/mobile/src/context/useCardContext.hook.js
index bfda79d2..41c1a93b 100644
--- a/app/mobile/src/context/useCardContext.hook.js
+++ b/app/mobile/src/context/useCardContext.hook.js
@@ -84,6 +84,13 @@ export function useCardContext() {
cards.current.set(cardId, card);
}
}
+ const setCardBlocked = (cardId, blocked) => {
+ let card = cards.current.get(cardId);
+ if (card) {
+ card.blocked = blocked;
+ cards.current.set(cardId, card);
+ }
+ }
const clearCardChannels = (cardId) => {
let card = cards.current.get(cardId);
if (card) {
@@ -385,6 +392,18 @@ export function useCardContext() {
setCardCloseMessage: async (server, message) => {
return await setCardCloseMessage(server, message);
},
+ setCardBlocked: async (cardId) => {
+ const { guid } = session.current;
+ setCardBlocked(cardId, true);
+ await store.actions.setCardItemBlocked(guid, cardId);
+ updateState({ cards: cards.current });
+ },
+ clearCardBlocked: async (cardId) => {
+ const { guid } = session.current;
+ setCardBlocked(cardId, false);
+ await store.actions.clearCardItemBlocked(guid, cardId);
+ updateState({ cards: cards.current });
+ }
}
return { state, actions }
diff --git a/app/mobile/src/context/useStoreContext.hook.js b/app/mobile/src/context/useStoreContext.hook.js
index 56121205..e6e89a7b 100644
--- a/app/mobile/src/context/useStoreContext.hook.js
+++ b/app/mobile/src/context/useStoreContext.hook.js
@@ -1,7 +1,7 @@
import { useEffect, useState, useRef, useContext } from 'react';
import SQLite from "react-native-sqlite-storage";
-const DATABAG_DB = 'databag_v033.db';
+const DATABAG_DB = 'databag_v034.db';
export function useStoreContext() {
const [state, setState] = useState({});
@@ -14,8 +14,8 @@ export function useStoreContext() {
const initSession = async (guid) => {
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_${guid} (channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(channel_id))`);
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_topic_${guid} (channel_id text, topic_id text, revision integer, detail_revision integer, detail text, unique(channel_id, topic_id))`);
- await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_${guid} (card_id text, revision integer, detail_revision integer, profile_revision integer, detail text, profile text, notified_view integer, notified_article integer, notified_profile integer, notified_channel integer, offsync integer, unique(card_id))`);
- await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_${guid} (card_id text, channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(card_id, channel_id))`);
+ await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_${guid} (card_id text, revision integer, detail_revision integer, profile_revision integer, detail text, profile text, notified_view integer, notified_article integer, notified_profile integer, notified_channel integer, offsync integer, blocked integer, unique(card_id))`);
+ await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_${guid} (card_id text, channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, blocked integer, read_revision integer, unique(card_id, channel_id))`);
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_topic_${guid} (card_id text, channel_id text, topic_id text, revision integer, detail_revision integer, detail text, unique(card_id, channel_id, topic_id))`);
}
@@ -106,6 +106,12 @@ export function useStoreContext() {
clearCardItemOffsync: async (guid, cardId) => {
await db.current.executeSql(`UPDATE card_${guid} set offsync=? where card_id=?`, [0, cardId]);
},
+ setCardItemBlocked: async (guid, cardId) => {
+ await db.current.executeSql(`UPDATE card_${guid} set blocked=? where card_id=?`, [1, cardId]);
+ },
+ clearCardItemBlocked: async (guid, cardId) => {
+ await db.current.executeSql(`UPDATE card_${guid} set blocked=? where card_id=?`, [0, cardId]);
+ },
setCardItemDetail: async (guid, cardId, revision, detail) => {
await db.current.executeSql(`UPDATE card_${guid} set detail_revision=?, detail=? where card_id=?`, [revision, encodeObject(detail), cardId]);
},
@@ -127,6 +133,7 @@ export function useStoreContext() {
notifiedProfile: values[0].notified_profile,
notifiedChannel: values[0].notified_channel,
offsync: values[0].offsync,
+ blocked: values[0].blocked,
};
},
getCardItemView: async (guid, cardId) => {
@@ -141,7 +148,7 @@ export function useStoreContext() {
};
},
getCardItems: async (guid) => {
- const values = await getAppValues(db.current, `SELECT card_id, revision, detail_revision, profile_revision, detail, profile, notified_view, notified_profile, notified_article, notified_channel FROM card_${guid}`, []);
+ const values = await getAppValues(db.current, `SELECT card_id, revision, detail_revision, profile_revision, detail, profile, offsync, blocked, notified_view, notified_profile, notified_article, notified_channel FROM card_${guid}`, []);
return values.map(card => ({
cardId: card.card_id,
revision: card.revision,
@@ -153,6 +160,8 @@ export function useStoreContext() {
notifiedProfile: card.notified_profile,
notifiedArticle: card.notified_article,
notifiedChannel: card.notified_channel,
+ offsync: card.offsync,
+ blocked: card.blocked,
}));
},
@@ -238,7 +247,7 @@ export function useStoreContext() {
};
},
getCardChannelItems: async (guid) => {
- const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, revision, detail_revision, topic_revision, detail, summary FROM card_channel_${guid}`, []);
+ const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, revision, blocked, detail_revision, topic_revision, detail, summary FROM card_channel_${guid}`, []);
return values.map(channel => ({
cardId: channel.card_id,
channelId: channel.channel_id,
@@ -248,6 +257,7 @@ export function useStoreContext() {
topicRevision: channel.topic_revision,
detail: decodeObject(channel.detail),
summary: decodeObject(channel.summary),
+ blocked: channel.blocked,
}));
},
clearCardChannelItems: async (guid, cardId) => {
diff --git a/app/mobile/src/session/cards/cardItem/CardItem.jsx b/app/mobile/src/session/cards/cardItem/CardItem.jsx
index 62518e89..04efed97 100644
--- a/app/mobile/src/session/cards/cardItem/CardItem.jsx
+++ b/app/mobile/src/session/cards/cardItem/CardItem.jsx
@@ -21,7 +21,7 @@ export function CardItem({ item, openContact }) {
{ item.handle }
{ item.status === 'connected' && (
-
+
)}
{ item.status === 'requested' && (
diff --git a/app/mobile/src/session/cards/useCards.hook.js b/app/mobile/src/session/cards/useCards.hook.js
index 167e98b8..428ab80b 100644
--- a/app/mobile/src/session/cards/useCards.hook.js
+++ b/app/mobile/src/session/cards/useCards.hook.js
@@ -37,6 +37,8 @@ export function useCards() {
name: profile.name,
handle: `${profile.handle}@${profile.node}`,
status: detail.status,
+ offsync: item.offsync,
+ blocked: item.blocked,
updated: detail.statusUpdated,
logo: profile.imageSet ? card.actions.getCardLogo(item.cardId, profile.revision) : 'avatar',
}
@@ -47,7 +49,7 @@ export function useCards() {
const items = cards.map(setCardItem);
const filtered = items.filter(item => {
if (!state.filter) {
- return true;
+ return !item.blocked;
}
const lower = state.filter.toLowerCase();
if (item.name) {
diff --git a/app/mobile/src/session/channels/useChannels.hook.js b/app/mobile/src/session/channels/useChannels.hook.js
index bca44a31..95f79bc4 100644
--- a/app/mobile/src/session/channels/useChannels.hook.js
+++ b/app/mobile/src/session/channels/useChannels.hook.js
@@ -130,7 +130,9 @@ export function useChannels() {
useEffect(() => {
let merged = [];
card.state.cards.forEach((card, cardId, map) => {
- merged.push(...Array.from(card.channels.values()));
+ if (!card.blocked) {
+ merged.push(...Array.from(card.channels.values()));
+ }
});
merged.push(...Array.from(channel.state.channels.values()));
diff --git a/app/mobile/src/session/contact/Contact.jsx b/app/mobile/src/session/contact/Contact.jsx
index 23fd9b17..3231593a 100644
--- a/app/mobile/src/session/contact/Contact.jsx
+++ b/app/mobile/src/session/contact/Contact.jsx
@@ -232,9 +232,6 @@ export function Contact({ contact, closeContact }) {
Save Contact
-
- Block Contact
-
>
)}
diff --git a/app/mobile/src/session/contact/useContact.hook.js b/app/mobile/src/session/contact/useContact.hook.js
index 12c01247..44a4342f 100644
--- a/app/mobile/src/session/contact/useContact.hook.js
+++ b/app/mobile/src/session/contact/useContact.hook.js
@@ -154,7 +154,12 @@ export function useContact(contact, close) {
}
});
},
- blockContact: async () => {},
+ blockContact: async () => {
+ await applyAction(async () => {
+ await card.actions.setCardBlocked(state.cardId);
+ close();
+ });
+ },
};
return { state, actions };
diff --git a/app/mobile/src/session/profile/Profile.jsx b/app/mobile/src/session/profile/Profile.jsx
index bb52aab5..985bf340 100644
--- a/app/mobile/src/session/profile/Profile.jsx
+++ b/app/mobile/src/session/profile/Profile.jsx
@@ -7,6 +7,8 @@ import Ionicons from '@expo/vector-icons/AntDesign';
import Colors from 'constants/Colors';
import ImagePicker from 'react-native-image-crop-picker'
import { SafeAreaView } from 'react-native-safe-area-context';
+import { BlockedTopics } from './blockedTopics/BlockedTopics';
+import { BlockedContacts } from './blockedContacts/BlockedContacts';
export function Profile() {
@@ -127,11 +129,59 @@ export function Profile() {
+
+ Manage Blocked Contacts
+
+
+ Manager Blocked Topics
+
Logout
+
+
+
+ Blocked Contacts:
+
+
+
+
+
+ Close
+
+
+
+
+
+
+
+
+ Blocked Topics:
+
+
+
+
+
+ Close
+
+
+
+
+
{
+ Alert.alert(
+ 'Unblocking Contact',
+ 'Confirm?',
+ [
+ { text: "Cancel", onPress: () => {}, },
+ { text: "Unblock", onPress: () => actions.unblock(cardId) },
+ ],
+ );
+ };
+
+ const BlockedItem = ({ item }) => {
+ return (
+ unblock(item.cardId)}>
+
+
+ { item.name }
+ { item.handle }
+
+
+ )
+ }
+
+ return (
+
+ { state.cards.length === 0 && (
+ No Blocked Contacts
+ )}
+ { state.cards.length !== 0 && (
+ }
+ keyExtractor={item => item.cardId}
+ />
+ )}
+
+ );
+}
+
diff --git a/app/mobile/src/session/profile/blockedContacts/BlockedContacts.styled.js b/app/mobile/src/session/profile/blockedContacts/BlockedContacts.styled.js
new file mode 100644
index 00000000..18a5c33d
--- /dev/null
+++ b/app/mobile/src/session/profile/blockedContacts/BlockedContacts.styled.js
@@ -0,0 +1,43 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'constants/Colors';
+
+export const styles = StyleSheet.create({
+ container: {
+ backgroundColor: Colors.white,
+ display: 'flex',
+ width: '100%',
+ justifyContent: 'center',
+ fontSize: 14,
+ height: 200,
+ },
+ default: {
+ textAlign: 'center',
+ color: Colors.grey,
+ },
+ item: {
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'row',
+ height: 48,
+ paddingLeft: 16,
+ alignItems: 'center',
+ borderBottomWidth: 1,
+ borderColor: Colors.itemDivider,
+ },
+ detail: {
+ paddingLeft: 12,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ flexGrow: 1,
+ flexShrink: 1,
+ },
+ name: {
+ color: Colors.text,
+ fontSize: 14,
+ },
+ handle: {
+ color: Colors.text,
+ fontSize: 12,
+ },
+});
diff --git a/app/mobile/src/session/profile/blockedContacts/useBlockedContacts.hook.js b/app/mobile/src/session/profile/blockedContacts/useBlockedContacts.hook.js
new file mode 100644
index 00000000..6fe77f4e
--- /dev/null
+++ b/app/mobile/src/session/profile/blockedContacts/useBlockedContacts.hook.js
@@ -0,0 +1,53 @@
+import { useState, useEffect, useContext } from 'react';
+import { CardContext } from 'context/CardContext';
+
+export function useBlockedContacts() {
+
+ const [state, setState] = useState({
+ cards: [],
+ });
+
+ const card = useContext(CardContext);
+
+ const updateState = (value) => {
+ setState((s) => ({ ...s, ...value }));
+ }
+
+ const setCardItem = (item) => {
+ const { profile } = item;
+ return {
+ cardId: item.cardId,
+ name: profile.name,
+ handle: `${profile.handle}@${profile.node}`,
+ blocked: item.blocked,
+ logo: profile.imageSet ? card.actions.getCardLogo(item.cardId, item.revision) : 'avatar',
+ }
+ };
+
+ useEffect(() => {
+ const cards = Array.from(card.state.cards.values());
+ const items = cards.map(setCardItem);
+ const filtered = items.filter(item => {
+ return item.blocked;
+ });
+ filtered.sort((a, b) => {
+ if (a.name === b.name) {
+ return 0;
+ }
+ if (!a.name || (a.name < b.name)) {
+ return -1;
+ }
+ return 1;
+ });
+ updateState({ cards: filtered });
+ }, [card]);
+
+ const actions = {
+ unblock: async (cardId) => {
+ await card.actions.clearCardBlocked(cardId);
+ }
+ };
+
+ return { state, actions };
+}
+
diff --git a/app/mobile/src/session/profile/blockedTopics/BlockedTopics.jsx b/app/mobile/src/session/profile/blockedTopics/BlockedTopics.jsx
new file mode 100644
index 00000000..b28b34ab
--- /dev/null
+++ b/app/mobile/src/session/profile/blockedTopics/BlockedTopics.jsx
@@ -0,0 +1,6 @@
+import { Text } from 'react-native';
+
+export function BlockedTopics() {
+ return TOPICS
+}
+
diff --git a/app/mobile/src/session/profile/useProfile.hook.js b/app/mobile/src/session/profile/useProfile.hook.js
index 51842bd1..337364a0 100644
--- a/app/mobile/src/session/profile/useProfile.hook.js
+++ b/app/mobile/src/session/profile/useProfile.hook.js
@@ -26,6 +26,8 @@ export function useProfile() {
available: true,
showPassword: false,
showConfirm: false,
+ blockedChannels: false,
+ blockedCards: false,
});
const app = useContext(AppContext);
@@ -60,6 +62,18 @@ export function useProfile() {
setProfileImage: async (data) => {
await profile.actions.setProfileImage(data);
},
+ showBlockedChannels: () => {
+ updateState({ blockedChannels: true });
+ },
+ hideBlockedChannels: () => {
+ updateState({ blockedChannels: false });
+ },
+ showBlockedCards: () => {
+ updateState({ blockedCards: true });
+ },
+ hideBlockedCards: () => {
+ updateState({ blockedCards: false });
+ },
showLoginEdit: () => {
updateState({ showLoginEdit: true });
},