Добавлены родственные связи, расширен граф связей и улучшен локальный запуск

Что добавлено:\n- Новые типы CONNECTION для родственников: parent/child/sibling (50/51, 52/53, 54/55) в blockchain/db слоях.\n- Обновлены проверки ConnectionBody и DB-триггер connections_state для корректной записи/удаления новых связей.\n- В профиле добавлен блок "Близкие родственники" с модальным выбором типа связи и логина; добавление через AddBlock для parent/child/sibling.\n- Расширен API GetUserConnectionsGraph: out/in списки для родителей/детей/сиблингов, агрегированные списки родственников с полом, список allUsers с метками официальный/сияющий.\n- Полностью обновлен UI страницы "Связи": новое позиционирование родственников вокруг центра, отдельный цвет родственных связей, линия для взаимных связей и стрелка для односторонних, корректная геометрия линий при ресайзе.\n- Добавлена Gradle-задача startLocalWithBuild для запуска локального стека после build; сохранена отдельная startLocal без полного build.
This commit is contained in:
AidarKC
2026-04-17 21:01:53 +03:00
parent 9b188d56e9
commit 4a92a7fa22
13 changed files with 1061 additions and 73 deletions
@@ -48,6 +48,15 @@ public final class DatabaseInitializer {
public static final short CONNECTION_FOLLOW = 30;
public static final short CONNECTION_UNFOLLOW = 31;
public static final short CONNECTION_PARENT = 50;
public static final short CONNECTION_UNPARENT = 51;
public static final short CONNECTION_CHILD = 52;
public static final short CONNECTION_UNCHILD = 53;
public static final short CONNECTION_SIBLING = 54;
public static final short CONNECTION_UNSIBLING = 55;
public static void createNewDB(String[] args) {
AppConfig config = AppConfig.getInstance();
String dbPath = config.getParam("db.path");
@@ -194,17 +194,23 @@ public final class DatabaseTriggersInstaller {
int FRIEND = (int) DatabaseInitializer.CONNECTION_FRIEND;
int CONTACT = (int) DatabaseInitializer.CONNECTION_CONTACT;
int FOLLOW = (int) DatabaseInitializer.CONNECTION_FOLLOW;
int PARENT = (int) DatabaseInitializer.CONNECTION_PARENT;
int CHILD = (int) DatabaseInitializer.CONNECTION_CHILD;
int SIBLING = (int) DatabaseInitializer.CONNECTION_SIBLING;
int UNFRIEND = (int) DatabaseInitializer.CONNECTION_UNFRIEND;
int UNCONTACT = (int) DatabaseInitializer.CONNECTION_UNCONTACT;
int UNFOLLOW = (int) DatabaseInitializer.CONNECTION_UNFOLLOW;
int UNPARENT = (int) DatabaseInitializer.CONNECTION_UNPARENT;
int UNCHILD = (int) DatabaseInitializer.CONNECTION_UNCHILD;
int UNSIBLING = (int) DatabaseInitializer.CONNECTION_UNSIBLING;
st.executeUpdate("""
CREATE TRIGGER IF NOT EXISTS trg_blocks_connection_state_ai
AFTER INSERT ON blocks
WHEN NEW.msg_type = 3
BEGIN
-- FRIEND/CONTACT/FOLLOW:
-- FRIEND/CONTACT/FOLLOW/PARENT/CHILD/SIBLING:
-- 1) если записи нет — создаём
INSERT OR IGNORE INTO connections_state (
login, rel_type, to_login, to_bch_name, to_block_number, to_block_hash
@@ -225,7 +231,7 @@ public final class DatabaseTriggersInstaller {
NEW.to_bch_name,
NEW.to_block_number,
NEW.to_block_hash
WHERE NEW.msg_sub_type IN (%d, %d, %d)
WHERE NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d)
AND COALESCE(
NEW.to_login,
CASE
@@ -256,7 +262,7 @@ public final class DatabaseTriggersInstaller {
ELSE NULL
END
)
AND NEW.msg_sub_type IN (%d, %d)
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d)
AND COALESCE(
NEW.to_login,
CASE
@@ -269,7 +275,7 @@ public final class DatabaseTriggersInstaller {
) IS NOT NULL
AND NEW.to_bch_name IS NOT NULL;
-- UNFRIEND/UNCONTACT/UNFOLLOW:
-- UNFRIEND/UNCONTACT/UNFOLLOW/UNPARENT/UNCHILD/UNSIBLING:
-- удаляем соответствующее "позитивное" состояние
DELETE FROM connections_state
WHERE login = NEW.login
@@ -284,6 +290,9 @@ public final class DatabaseTriggersInstaller {
END
)
AND rel_type = CASE NEW.msg_sub_type
WHEN %d THEN %d
WHEN %d THEN %d
WHEN %d THEN %d
WHEN %d THEN %d
WHEN %d THEN %d
WHEN %d THEN %d
@@ -299,17 +308,20 @@ public final class DatabaseTriggersInstaller {
ELSE NULL
END
) IS NOT NULL
AND NEW.msg_sub_type IN (%d, %d, %d);
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d);
END;
""".formatted(
FRIEND, CONTACT, FOLLOW,
FRIEND, CONTACT,
FRIEND, CONTACT, FOLLOW, PARENT, CHILD, SIBLING,
FRIEND, CONTACT, PARENT, CHILD, SIBLING,
UNFRIEND, FRIEND,
UNCONTACT, CONTACT,
UNFOLLOW, FOLLOW,
UNPARENT, PARENT,
UNCHILD, CHILD,
UNSIBLING, SIBLING,
UNFRIEND, UNCONTACT, UNFOLLOW
UNFRIEND, UNCONTACT, UNFOLLOW, UNPARENT, UNCHILD, UNSIBLING
));
}
@@ -503,4 +515,3 @@ public final class DatabaseTriggersInstaller {
""".formatted(EDIT_POST, EDIT_REPLY));
}
}
@@ -40,8 +40,8 @@ public final class MsgSubType {
/* ===================== CONNECTION (msg_type=3) ===================== */
/**
* Совпадает с ConnectionBody:
* SET: FRIEND=10, CONTACT=20, FOLLOW=30
* UNSET: UNFRIEND=11, UNCONTACT=21, UNFOLLOW=31
* SET: FRIEND=10, CONTACT=20, FOLLOW=30, PARENT=50, CHILD=52, SIBLING=54
* UNSET: UNFRIEND=11, UNCONTACT=21, UNFOLLOW=31, UNPARENT=51, UNCHILD=53, UNSIBLING=55
*/
/** Добавить в друзья. */
@@ -62,6 +62,24 @@ public final class MsgSubType {
/** Отписаться (unfollow). */
public static final short CONNECTION_UNFOLLOW = 31;
/** Добавить связь "родитель". */
public static final short CONNECTION_PARENT = 50;
/** Удалить связь "родитель". */
public static final short CONNECTION_UNPARENT = 51;
/** Добавить связь "ребёнок". */
public static final short CONNECTION_CHILD = 52;
/** Удалить связь "ребёнок". */
public static final short CONNECTION_UNCHILD = 53;
/** Добавить связь "брат/сестра". */
public static final short CONNECTION_SIBLING = 54;
/** Удалить связь "брат/сестра". */
public static final short CONNECTION_UNSIBLING = 55;
/* ===================== USER_PARAM (msg_type=4) ===================== */
/** Параметр профиля key/value (обе строки). */