From 530a0f8ce17017e548a4b7a056fe18fe04d2973a Mon Sep 17 00:00:00 2001 From: benya Date: Sun, 25 Jan 2026 02:35:15 +0300 Subject: [PATCH] =?UTF-8?q?feat(chat):=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BD=D0=B0=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=B0=D0=B4=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20=D0=AD=D1=82=D0=BE=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20=D0=BD=D0=BE=D0=B2=D1=83=D1=8E?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E,=20=D0=BA=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B0=D1=8F=20=D0=BF=D0=BE=D0=B7=D0=B2=D0=BE?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=20=D0=BD=D0=B0=D0=B7=D0=BD=D0=B0=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=82=D0=BE=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8=20=D0=B2=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D1=87=D0=B0=D1=82=D0=B0=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ключевые изменения: - В главное меню добавлен новый пункт "Назначить администратором". - Проведен рефакторинг для повышения надежности: для хранения пользователей теперь используется Map вместо двух отдельных списков, что исключает рассинхронизацию ID и имен. - Введен enum UserAction (ADD, REMOVE, SET_ADMIN) для более чистого управления действиями с пользователями. - В VkApiClient добавлен метод setMemberRole для взаимодействия с VK API. - Обновлены диалоги подтверждения и итоговые отчеты для поддержки новой функции. --- app/build.gradle | 4 +- .../anabasis/vkchatmanager/MainActivity.java | 99 ++++++++++++------- .../vkchatmanager/network/VkApiClient.java | 9 +- app/src/main/res/menu/main_menu.xml | 3 + app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 412b2ed..6a78b89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.anabasis.vkchatmanager" minSdk 26 targetSdk 36 - versionCode 10103 - versionName "1.1.3" + versionCode 10200 + versionName "1.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/anabasis/vkchatmanager/MainActivity.java b/app/src/main/java/com/anabasis/vkchatmanager/MainActivity.java index 0145790..ff3c50e 100644 --- a/app/src/main/java/com/anabasis/vkchatmanager/MainActivity.java +++ b/app/src/main/java/com/anabasis/vkchatmanager/MainActivity.java @@ -17,7 +17,6 @@ import android.widget.Toast; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; @@ -42,21 +41,23 @@ import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class MainActivity extends AppCompatActivity { + private enum UserAction { + ADD, REMOVE, SET_ADMIN + } private VkApiClient api; - private final List office = new ArrayList<>(); private final List retail = new ArrayList<>(); private final List warehouse = new ArrayList<>(); private final List coffee = new ArrayList<>(); private final List other = new ArrayList<>(); - private final List userIdsToProcess = new ArrayList<>(); - - private final List userNamesToProcess = new ArrayList<>(); + private final Map usersToProcess = new LinkedHashMap<>(); private LinearProgressIndicator progressBar; private androidx.swiperefreshlayout.widget.SwipeRefreshLayout swipeRefresh; @@ -74,13 +75,13 @@ public class MainActivity extends AppCompatActivity { result -> { if (result.getResultCode() == RESULT_OK) { recreate(); + } else { + finish(); } - } - ); - + }); @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { + protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowCompat.setDecorFitsSystemWindows(getWindow(), false); setContentView(R.layout.activity_main); @@ -154,8 +155,8 @@ public class MainActivity extends AppCompatActivity { } }); - addBtn.setOnClickListener(v -> processUsers(true)); - removeBtn.setOnClickListener(v -> processUsers(false)); + addBtn.setOnClickListener(v -> processUsers(UserAction.ADD)); + removeBtn.setOnClickListener(v -> processUsers(UserAction.REMOVE)); showUsersBtn.setOnClickListener(v -> showUsers()); } @@ -187,6 +188,11 @@ public class MainActivity extends AppCompatActivity { return true; } + if (id == R.id.action_set_admin) { + processUsers(UserAction.SET_ADMIN); + return true; + } + if (id == R.id.action_token_status) { showTokenStatus(); return true; @@ -383,8 +389,7 @@ public class MainActivity extends AppCompatActivity { /* ===================== LINKS ===================== */ private void processLinksList(List links) { - userIdsToProcess.clear(); - userNamesToProcess.clear(); + usersToProcess.clear(); setUiEnabled(false); @@ -394,8 +399,7 @@ public class MainActivity extends AppCompatActivity { String screen = extractScreenName(link); int uid = api.resolveUserId(screen); if (uid > 0) { - userIdsToProcess.add(uid); - userNamesToProcess.add(api.getUserName(uid)); + usersToProcess.put(uid, api.getUserName(uid)); } } catch (TokenExpiredException e) { runOnUiThread(this::handleTokenExpired); @@ -406,7 +410,7 @@ public class MainActivity extends AppCompatActivity { setUiEnabled(true); Toast.makeText( this, - getString(R.string.users_loaded_message, userIdsToProcess.size()), + getString(R.string.users_loaded_message, usersToProcess.size()), Toast.LENGTH_SHORT ).show(); }); @@ -431,16 +435,16 @@ public class MainActivity extends AppCompatActivity { return link; } - /* ===================== ADD / REMOVE ===================== */ + /* ===================== ADD / REMOVE / SET_ADMIN ===================== */ private void showUsers() { - if (userNamesToProcess.isEmpty()) { + if (usersToProcess.isEmpty()) { Toast.makeText(this, getString(R.string.user_list_empty), Toast.LENGTH_SHORT).show(); return; } StringBuilder msg = new StringBuilder(); - for (String name : userNamesToProcess) { + for (String name : usersToProcess.values()) { msg.append("• ").append(name).append("\n"); } @@ -451,10 +455,13 @@ public class MainActivity extends AppCompatActivity { .show(); } - private void processUsers(boolean add) { + private void processUsers(UserAction action) { - List chats = getCurrentFragment().getSelected(); - if (chats.isEmpty() || userIdsToProcess.isEmpty()) { + ChatListFragment currentFragment = getCurrentFragment(); + if (currentFragment == null) return; + + List chats = currentFragment.getSelected(); + if (chats.isEmpty() || usersToProcess.isEmpty()) { Toast.makeText(this, getString(R.string.no_chats_or_users_selected_message), Toast.LENGTH_SHORT).show(); @@ -462,10 +469,20 @@ public class MainActivity extends AppCompatActivity { } StringBuilder msg = new StringBuilder(); - msg.append(add ? getString(R.string.add_users_dialog_message) : getString(R.string.remove_users_dialog_message)); + switch (action) { + case ADD: + msg.append(getString(R.string.add_users_dialog_message)); + break; + case REMOVE: + msg.append(getString(R.string.remove_users_dialog_message)); + break; + case SET_ADMIN: + msg.append(getString(R.string.set_admin_dialog_message)); + break; + } msg.append("\n\n"); - for (String name : userNamesToProcess) { + for (String name : usersToProcess.values()) { msg.append("• ").append(name).append("\n"); } @@ -480,18 +497,18 @@ public class MainActivity extends AppCompatActivity { .setTitle(getString(R.string.confirmation_dialog_title)) .setMessage(msg.toString()) .setPositiveButton(getString(R.string.confirm_button), (d, w) -> - executeUsers(add, chats)) + executeUsers(action, chats)) .setNegativeButton(getString(R.string.cancel_button), null) .show(); } - private void executeUsers(boolean add, List chats) { + private void executeUsers(UserAction action, List chats) { setUiEnabled(false); progressBar.setVisibility(View.VISIBLE); progressBar.setIndeterminate(false); progressBar.setProgress(0, true); - int totalOps = chats.size() * userIdsToProcess.size(); + int totalOps = chats.size() * usersToProcess.size(); progressBar.setMax(totalOps); new Thread(() -> { @@ -499,19 +516,27 @@ public class MainActivity extends AppCompatActivity { int done = 0; for (VkChat c : chats) { - for (int i = 0; i < userIdsToProcess.size(); i++) { - int uid = userIdsToProcess.get(i); - String userName = userNamesToProcess.get(i); + for (Map.Entry user : usersToProcess.entrySet()) { + int uid = user.getKey(); + String userName = user.getValue(); String resultMessage; try { - if (add) { - api.addUser(c.id, uid, true); - resultMessage = getString(R.string.op_success_add_format, userName, c.title); - } else { - api.removeUser(c.id, uid); - resultMessage = getString(R.string.op_success_remove_format, userName, c.title); - } + resultMessage = switch (action) { + case ADD -> { + api.addUser(c.id, uid, true); + yield getString(R.string.op_success_add_format, userName, c.title); + } + case REMOVE -> { + api.removeUser(c.id, uid); + yield getString(R.string.op_success_remove_format, userName, c.title); + } + case SET_ADMIN -> { + api.setMemberRole(c.id, uid, "admin"); + yield getString(R.string.op_success_set_admin_format, userName, c.title); + } + }; + } catch (TokenExpiredException e) { runOnUiThread(this::handleTokenExpired); return; diff --git a/app/src/main/java/com/anabasis/vkchatmanager/network/VkApiClient.java b/app/src/main/java/com/anabasis/vkchatmanager/network/VkApiClient.java index 7e8b4da..8367738 100644 --- a/app/src/main/java/com/anabasis/vkchatmanager/network/VkApiClient.java +++ b/app/src/main/java/com/anabasis/vkchatmanager/network/VkApiClient.java @@ -59,6 +59,13 @@ public class VkApiClient { "&member_id=" + userId); } + public void setMemberRole(int chatId, int userId, String role) throws Exception { + call("messages.setMemberRole", + "peer_id=" + (2000000000 + chatId) + + "&member_id=" + userId + + "&role=" + role); + } + public int resolveUserId(String screenName) throws Exception { JSONObject resp = call( @@ -84,4 +91,4 @@ public class VkApiClient { return u.getString("first_name") + " " + u.getString("last_name"); } -} \ No newline at end of file +} diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index c2d2349..00403b1 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -12,6 +12,9 @@ + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 99ce4a8..fd4ea31 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -19,6 +19,7 @@ Не выбраны чаты или пользователи Добавить пользователей: Удалить пользователей: + Назначить администратором: В чаты: Подтверждение Подтвердить @@ -27,6 +28,7 @@ Обновить Выбрать все Снять выбор + Назначить администратором Статус токена Статус токена Токен бессрочный @@ -39,6 +41,7 @@ неизвестная ошибка ✅ %1$s в %2$s: Успешно ✅ %1$s из %2$s: Успешно + ✅ %1$s в %2$s: Назначен администратором ❌ %1$s в %2$s: %3$s Выйти Ошибка API: %s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2dbd8de..cfdc08d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ No chats or users selected Add users: Remove users: + Set as admin: In chats: Confirmation Confirm @@ -27,6 +28,7 @@ Refresh Select All Deselect All + Set as Admin Token Status Token Status Token is perpetual @@ -39,6 +41,7 @@ unknown error ✅ %1$s in %2$s: Success ✅ %1$s from %2$s: Success + ✅ %1$s in %2$s: Is now an admin ❌ %1$s in %2$s: %3$s Sign Out API error: %s