├── APKs └── iHA bot 6.0 alpha 8 │ ├── iHA bot 6.0 alpha 8.apk │ └── output-metadata.json ├── Android-app ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .name │ ├── compiler.xml │ ├── gradle.xml │ ├── misc.xml │ ├── other.xml │ ├── render.experimental.xml │ └── vcs.xml ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── fsoft │ │ │ └── ihabot │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher-playstore.png │ │ ├── java │ │ │ └── com │ │ │ │ └── fsoft │ │ │ │ └── ihabot │ │ │ │ ├── ApplicationManager.java │ │ │ │ ├── BotActivity.java │ │ │ │ ├── BotService.java │ │ │ │ ├── Utils │ │ │ │ ├── Attachment.java │ │ │ │ ├── Command.java │ │ │ │ ├── CommandDesc.java │ │ │ │ ├── CommandModule.java │ │ │ │ ├── CommandParser.java │ │ │ │ ├── F.java │ │ │ │ ├── FileStorage.java │ │ │ │ └── Triplet.java │ │ │ │ ├── answer │ │ │ │ ├── AnswerDatabase.java │ │ │ │ ├── AnswerElement.java │ │ │ │ ├── Attachment.java │ │ │ │ ├── Message.java │ │ │ │ └── Synonyme.java │ │ │ │ ├── communucation │ │ │ │ ├── Account.java │ │ │ │ ├── AccountBase.java │ │ │ │ ├── Communicator.java │ │ │ │ ├── VolleyMultipartRequest.java │ │ │ │ └── tg │ │ │ │ │ ├── Chat.java │ │ │ │ │ ├── Document.java │ │ │ │ │ ├── File.java │ │ │ │ │ ├── Message.java │ │ │ │ │ ├── MessageEntity.java │ │ │ │ │ ├── MessageProcessor.java │ │ │ │ │ ├── PhotoSize.java │ │ │ │ │ ├── Sticker.java │ │ │ │ │ ├── TgAccount.java │ │ │ │ │ ├── TgAccountCore.java │ │ │ │ │ ├── Update.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── UserProfilePhotos.java │ │ │ │ ├── configuration │ │ │ │ ├── AdminList.java │ │ │ │ └── MessageHistory.java │ │ │ │ └── ui │ │ │ │ ├── TgLoginWindow.java │ │ │ │ ├── accounts │ │ │ │ ├── AccountsAdapter.java │ │ │ │ └── AccountsFragment.java │ │ │ │ ├── admins │ │ │ │ ├── AddAdminUsersAdapter.java │ │ │ │ ├── AdminsAdapter.java │ │ │ │ └── AdminsFragment.java │ │ │ │ ├── gallery │ │ │ │ ├── GalleryFragment.java │ │ │ │ └── GalleryViewModel.java │ │ │ │ ├── home │ │ │ │ ├── HomeFragment.java │ │ │ │ └── HomeViewModel.java │ │ │ │ └── slideshow │ │ │ │ ├── SlideshowFragment.java │ │ │ │ └── SlideshowViewModel.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ ├── bot_noti.png │ │ │ ├── ic_add_user.xml │ │ │ ├── ic_cross.xml │ │ │ ├── ic_exclamation.xml │ │ │ ├── ic_launcher_foreground.xml │ │ │ ├── ic_tg_logo.png │ │ │ ├── iha_bot.png │ │ │ └── tg_account_placeholder.png │ │ │ ├── drawable │ │ │ ├── background_warning.xml │ │ │ ├── ic_add_tg_account.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ic_menu_camera.xml │ │ │ ├── ic_menu_gallery.xml │ │ │ ├── ic_menu_message.xml │ │ │ ├── ic_menu_settings.xml │ │ │ ├── ic_menu_slideshow.xml │ │ │ ├── ic_menu_user.xml │ │ │ ├── ic_pause.xml │ │ │ └── side_nav_bar.xml │ │ │ ├── layout │ │ │ ├── activity_bot.xml │ │ │ ├── app_bar_bot.xml │ │ │ ├── content_bot.xml │ │ │ ├── dialog_add_admin.xml │ │ │ ├── dialog_add_admin_list_item.xml │ │ │ ├── dialog_add_telegram_account.xml │ │ │ ├── fragment_accounts_layout.xml │ │ │ ├── fragment_accounts_list_item.xml │ │ │ ├── fragment_admins_layout.xml │ │ │ ├── fragment_admins_list_item.xml │ │ │ ├── fragment_gallery.xml │ │ │ ├── fragment_home.xml │ │ │ ├── fragment_slideshow.xml │ │ │ └── nav_header_bot.xml │ │ │ ├── menu │ │ │ ├── account_popup_menu.xml │ │ │ ├── activity_main_drawer.xml │ │ │ ├── admin_popup_menu.xml │ │ │ └── bot.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── navigation │ │ │ └── mobile_navigation.xml │ │ │ ├── raw │ │ │ ├── answer_database.zip │ │ │ └── synonyme.txt │ │ │ ├── values-land │ │ │ └── dimens.xml │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ ├── values-w1240dp │ │ │ └── dimens.xml │ │ │ ├── values-w600dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── fsoft │ │ └── ihabot │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── Others └── 2022 Самые популярные слова (парсинг старой базы) │ ├── Database_frequent_words │ ├── Database_frequent_words.pde │ └── data │ │ ├── answer_database_old_full.txt │ │ ├── words_frequency.txt │ │ └── Синонимы (мной вручную дописанные к words_frequency).txt │ └── Пояснительная бригада.txt ├── Photos └── Screenshot_20220324_180909.png ├── README.md └── iHA bot INFO.md /APKs/iHA bot 6.0 alpha 8/iHA bot 6.0 alpha 8.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/APKs/iHA bot 6.0 alpha 8/iHA bot 6.0 alpha 8.apk -------------------------------------------------------------------------------- /APKs/iHA bot 6.0 alpha 8/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.fsoft.ihabot", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "1.0", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File" 20 | } -------------------------------------------------------------------------------- /Android-app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /Android-app/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /Android-app/.idea/.name: -------------------------------------------------------------------------------- 1 | FP iHA bot -------------------------------------------------------------------------------- /Android-app/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Android-app/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /Android-app/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | -------------------------------------------------------------------------------- /Android-app/.idea/other.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Android-app/.idea/render.experimental.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Android-app/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Android-app/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /Android-app/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdk 33 7 | 8 | defaultConfig { 9 | applicationId "com.fsoft.ihabot" 10 | minSdk 29 11 | targetSdk 33 12 | versionCode 3 13 | versionName "6.1" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_1_8 26 | targetCompatibility JavaVersion.VERSION_1_8 27 | } 28 | buildFeatures { 29 | viewBinding true 30 | } 31 | namespace 'com.fsoft.ihabot' 32 | } 33 | 34 | dependencies { 35 | 36 | implementation 'androidx.appcompat:appcompat:1.4.1' 37 | implementation 'com.google.android.material:material:1.5.0' 38 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 39 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" 40 | implementation 'com.squareup.picasso:picasso:2.71828' 41 | implementation 'jp.wasabeef:picasso-transformations:2.4.0' 42 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1' 43 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' 44 | implementation 'androidx.navigation:navigation-fragment:2.4.2' 45 | implementation 'androidx.navigation:navigation-ui:2.4.2' 46 | testImplementation 'junit:junit:4.13.2' 47 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 48 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 49 | implementation 'com.android.volley:volley:1.2.1' 50 | // https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j 51 | implementation 'net.lingala.zip4j:zip4j:2.10.0' 52 | 53 | } -------------------------------------------------------------------------------- /Android-app/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /Android-app/app/src/androidTest/java/com/fsoft/ihabot/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.fsoft.ihabot", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Android-app/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/BotService.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationChannel; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.app.Service; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.graphics.Color; 11 | import android.os.IBinder; 12 | import android.util.Log; 13 | 14 | import com.fsoft.ihabot.Utils.F; 15 | 16 | public class BotService extends Service { 17 | static public ApplicationManager applicationManager = null; 18 | 19 | @Override 20 | public IBinder onBind(Intent intent) { 21 | return null; 22 | } 23 | 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | try { 28 | Intent notificationIntent = new Intent(this, BotActivity.class); 29 | 30 | PendingIntent pendingIntent = PendingIntent.getActivity( 31 | this.getApplicationContext(), 32 | 0, 33 | notificationIntent, 34 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT // setting the mutability flag 35 | ); 36 | 37 | String channelId = "BotRunning"; 38 | 39 | NotificationChannel chan = new NotificationChannel(channelId, getText(R.string.notification_channel_name), NotificationManager.IMPORTANCE_NONE); 40 | chan.setLightColor(Color.BLUE); 41 | chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); 42 | NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 43 | manager.createNotificationChannel(chan); 44 | 45 | Notification notification = new Notification.Builder(this, channelId) 46 | .setContentTitle(getText(R.string.notification_title)) 47 | .setContentText(getText(R.string.notification_content)) 48 | .setSmallIcon(R.drawable.bot_noti) 49 | .setContentIntent(pendingIntent) 50 | .setTicker(getText(R.string.notification_content)) 51 | .build(); 52 | 53 | 54 | // Notification ID cannot be 0. 55 | int ONGOING_NOTIFICATION_ID = 1; 56 | startForeground(ONGOING_NOTIFICATION_ID, notification); 57 | } catch (Exception e) { 58 | Log.d(F.TAG, "Error starting service: " + e.getMessage()); 59 | e.printStackTrace(); 60 | } 61 | new Thread(new Runnable() { 62 | @Override 63 | public void run() { 64 | try { 65 | Log.d(F.TAG, "BotService ApplicationManager starting..."); 66 | applicationManager = new ApplicationManager(BotService.this); 67 | Log.d(F.TAG, "BotService started"); 68 | } 69 | catch (Exception e){ 70 | Log.d(F.TAG, "Error starting ApplicationManager: " + e.getMessage()); 71 | e.printStackTrace(); 72 | } 73 | } 74 | }).start(); 75 | } 76 | 77 | 78 | @Override 79 | public void onDestroy() { 80 | Log.d(F.TAG, "BotService stopped"); 81 | if (applicationManager != null) { 82 | applicationManager.stop(); 83 | } 84 | super.onDestroy(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/Utils/Attachment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.Utils; 2 | 3 | public class Attachment { 4 | } 5 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/Utils/Command.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.Utils; 2 | 3 | import com.fsoft.ihabot.answer.Message; 4 | import com.fsoft.ihabot.communucation.tg.TgAccount; 5 | import com.fsoft.ihabot.configuration.AdminList; 6 | 7 | import java.util.ArrayList; 8 | 9 | /** 10 | * Базовый класс для всех обработчиков команд, общий для всех модулей. Это наследование нужно чтобы хранить их все одном массиве 11 | * 12 | * Формат справки: 13 | * [ описание команды ] (до 50 символов) 14 | * ---| botcmmd hui push 15 | * Created by Dr. Failov on 28.11.2014. 16 | */ 17 | public interface Command { 18 | 19 | /** 20 | * На входе и на выходе обьект com.fsoft.ihabot.answer.Message 21 | * Обработка команд происзодит раньше чем обработка базой ответов 22 | * Если по итогу модули прислали ответы на команду - Будут отправлены только сообщения с ответами на команду 23 | * Если модули прислали пустые ответы на команду - ничего не будет отправлено. Базой ответов это сообщение не будет обработано. 24 | * Если модули не прислали ни одного ответа на команду - будет выполнена обработка сообщения как обычного ответа 25 | * @param message сообщение на входе от администратора в неизменном виде 26 | * @param tgAccount Аккаунт телеграм бота, который получил команду. Нужен для обращения в сеть и деланья всякого важного разного командами 27 | * @param admin Какой из админов прислал команду. Мы тут можем проверить есть ли у него права, и т.д. 28 | * @return Список сообщений ответов на команду. 29 | * @throws Exception Мало ли что может случиться при обработке. Команды многое могут делать. 30 | * */ 31 | ArrayList processCommand(Message message, TgAccount tgAccount, AdminList.AdminListItem admin) throws Exception; //На вход принимается текст без botcmd 32 | 33 | /** 34 | * Эта команда участвует в формировании справки для админа со списком доступных команд 35 | * @param requester Какой админ запрашивает справку. Не будем выводить ему в справку команд, к которым у него нет доступа. 36 | * @return Список обьектов CommandDesc, где каждый содердит достаточно информации о команде 37 | */ 38 | ArrayList getHelp(AdminList.AdminListItem requester); 39 | } 40 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/Utils/CommandDesc.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.Utils; 2 | /** 3 | * Этот класс представляет собой элемент справки 4 | * Created by Dr. Failov on 13.07.2017. 5 | */ 6 | 7 | public class CommandDesc { 8 | private String helpText = ""; 9 | private String example = ""; 10 | 11 | public CommandDesc(String example, String helpText) { 12 | this.helpText = helpText; 13 | this.example = example; 14 | } 15 | 16 | public String getHelpText() { 17 | return helpText; 18 | } 19 | 20 | public void setHelpText(String helpText) { 21 | this.helpText = helpText; 22 | } 23 | 24 | public String getExample() { 25 | return example; 26 | } 27 | 28 | public void setExample(String example) { 29 | this.example = example; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/Utils/CommandModule.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.Utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.fsoft.ihabot.answer.Message; 6 | import com.fsoft.ihabot.communucation.tg.TgAccount; 7 | import com.fsoft.ihabot.configuration.AdminList; 8 | 9 | import java.text.SimpleDateFormat; 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * этот класс будет собирать в себе весь общий функционал необходимый для работы модулей внутри самой программы 14 | * Created by Dr. Failov on 12.02.2017. 15 | */ 16 | public class CommandModule implements Command { 17 | protected ArrayList childCommands = new ArrayList<>(); 18 | 19 | 20 | public CommandModule() { 21 | } 22 | 23 | protected static String log(String string){ 24 | Log.d(F.TAG, string); 25 | return string; 26 | } 27 | 28 | @Override 29 | public ArrayList processCommand(Message message, TgAccount tgAccount, AdminList.AdminListItem admin) throws Exception { 30 | ArrayList results = new ArrayList<>(); 31 | for (CommandModule child : childCommands) { 32 | results.addAll(child.processCommand(message, tgAccount, admin)); 33 | } 34 | return results; 35 | } 36 | @Override 37 | public ArrayList getHelp(AdminList.AdminListItem requester) { 38 | ArrayList result=new ArrayList<>(); 39 | for (CommandModule child : childCommands) 40 | result.addAll(child.getHelp(requester)); 41 | return result; 42 | } 43 | public void stop() { 44 | //при закрытии программы останавливает процессы 45 | //НЕ ИСПОЛЬЗОВАТЬ ДЛЯ СОХРАНЕНИЯ!!!!!!!!!!!!!!! Сохранять всё на лету, так надежнее 46 | for (CommandModule child : childCommands) 47 | child.stop(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/Utils/CommandParser.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.Utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.fsoft.ihabot.ApplicationManager; 6 | 7 | /** 8 | * Мегаохуительный класс для разбора команд без регистрации и СМС. 9 | * Created by Dr. Failov on 01.01.2015. 10 | */ 11 | 12 | public class CommandParser { 13 | /* 14 | * класс для разбора команд. 15 | * */ 16 | public static ApplicationManager applicationManager = null; 17 | private String command = "(empty)"; 18 | private String[] words; 19 | private int currentWordCounter = 0; 20 | 21 | public CommandParser(String command){ 22 | command = deleteCrap(command); 23 | this.command = command; 24 | words = command.split("\\ "); 25 | if(words.length == 1) 26 | words = command.split("_"); 27 | } 28 | private void log(String text){ 29 | Log.d(F.TAG, text); 30 | } 31 | private String deleteCrap(String in){ 32 | String out = in.replace("botcmd", ""); 33 | out = out.replace("/", " "); 34 | out = out.replaceAll(" +", " "); 35 | out = out.trim(); 36 | return out; 37 | } 38 | public String tryWord(){ 39 | //получить СЛЕДУЮЩЕЕ ПО ПОРЯДКУ НО НЕ МЕНЯТЬ СЧЁТЧИК. Т.е. вызов tryWord не повлияет на результат вызова getWord 40 | int index = currentWordCounter; 41 | return getWord(index); 42 | } 43 | public String getWord(){ 44 | //получить СЛЕДУЮЩЕЕ ПО ПОРЯДКУ 45 | int index = currentWordCounter; 46 | currentWordCounter ++; 47 | return getWord(index); 48 | } 49 | public String getWord(int wordNumber){ 50 | if(wordNumber >= 0 && wordNumber { 4 | 5 | private final T first; 6 | private final U second; 7 | private final V third; 8 | 9 | public Triplet(T first, U second, V third) { 10 | this.first = first; 11 | this.second = second; 12 | this.third = third; 13 | } 14 | 15 | public T getFirst() { return first; } 16 | public U getSecond() { return second; } 17 | public V getThird() { return third; } 18 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/answer/AnswerElement.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.answer; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.fsoft.ihabot.communucation.tg.User; 6 | 7 | import org.json.JSONArray; 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | 11 | import java.text.ParseException; 12 | import java.util.Locale; 13 | 14 | /* * Какая инфа про ответ должна хранится: 15 | * - ID ответа (id, long. В случае коллизий генерировать новые) 16 | * - Message вопроса (текст вопроса, автор вопроса, дата вопроса) 17 | * - Message ответа (текст ответа, автор ответа, дата ответа) 18 | * */ 19 | public class AnswerElement { 20 | private long id = 0; //В случае коллизий генерировать новые) 21 | private Message questionMessage = null; 22 | private Message answerMessage = null; 23 | private int timesUsed = 0; //Количество раз, сколько раз бот использовал этот ответ 24 | 25 | public AnswerElement() { 26 | } 27 | public AnswerElement(JSONObject jsonObject)throws JSONException, ParseException { 28 | fromJson(jsonObject); 29 | } 30 | 31 | public long getId() { 32 | return id; 33 | } 34 | 35 | public Message getQuestionMessage() { 36 | return questionMessage; 37 | } 38 | 39 | public Message getAnswerMessage() { 40 | return answerMessage; 41 | } 42 | 43 | public boolean hasAnswer(){ 44 | return answerMessage != null; 45 | } 46 | 47 | public void setId(long id) { 48 | this.id = id; 49 | } 50 | 51 | /** 52 | * Используется для быстрого подбора унимального максимального ID. 53 | * Эта функция задаёт ID на единицу больше того что принят, при условии, 54 | * что принятый ID больше или такой же как текущий. 55 | * @param id ID, больше которого надо сделать ID этого ответа 56 | */ 57 | public void setIdBiggerThan(long id) { 58 | if(id >= this.id) 59 | this.id = id+1; 60 | } 61 | 62 | public void setQuestionMessage(Message questionMessage) { 63 | this.questionMessage = questionMessage; 64 | } 65 | 66 | public void setAnswerMessage(Message answerMessage) { 67 | this.answerMessage = answerMessage; 68 | } 69 | 70 | public int getTimesUsed() { 71 | return timesUsed; 72 | } 73 | 74 | public void incrementTimesUsed() { 75 | this.timesUsed++; 76 | } 77 | 78 | public JSONObject toJson() throws JSONException { 79 | JSONObject jsonObject = new JSONObject(); 80 | jsonObject.put("id", id); 81 | jsonObject.put("timesUsed", timesUsed); 82 | if(questionMessage != null) 83 | jsonObject.put("questionMessage", questionMessage.toJson()); 84 | if(answerMessage != null) 85 | jsonObject.put("answerMessage", answerMessage.toJson()); 86 | return jsonObject; 87 | } 88 | 89 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 90 | if(jsonObject.has("id")) 91 | id = jsonObject.getLong("id"); 92 | if(jsonObject.has("timesUsed")) 93 | timesUsed = jsonObject.getInt("timesUsed"); 94 | 95 | if(jsonObject.has("questionMessage")) 96 | questionMessage = new Message(jsonObject.getJSONObject("questionMessage")); 97 | 98 | if(jsonObject.has("answerMessage")) 99 | answerMessage = new Message(jsonObject.getJSONObject("answerMessage")); 100 | } 101 | 102 | public String toStringWithID() { 103 | if(getQuestionMessage() == null && getAnswerMessage() == null){ 104 | return String.format(Locale.US, "ID%d NULL -> NULL", getId()); 105 | } 106 | if(getQuestionMessage() == null){ 107 | return String.format(Locale.US, "ID%d NULL -> %s", 108 | getId(), 109 | getAnswerMessage().toString().replace("\n", "")); 110 | } 111 | if(getAnswerMessage() == null){ 112 | return String.format(Locale.US, "ID%d %s -> NULL", 113 | getId(), 114 | getQuestionMessage().toString().replace("\n", "")); 115 | } 116 | return String.format(Locale.US, "ID%d %s -> %s", 117 | getId(), 118 | getQuestionMessage().toString().replace("\n", ""), 119 | getAnswerMessage().toString().replace("\n", "")); 120 | 121 | } 122 | @NonNull 123 | @Override 124 | public String toString() { 125 | if(getQuestionMessage() == null && getAnswerMessage() == null){ 126 | return "NULL -> NULL"; 127 | } 128 | if(getQuestionMessage() == null){ 129 | return String.format(Locale.US, "NULL -> %s", 130 | getAnswerMessage().toString().replace("\n", "")); 131 | } 132 | if(getAnswerMessage() == null){ 133 | return String.format(Locale.US, "%s -> NULL", 134 | getQuestionMessage().toString().replace("\n", "")); 135 | } 136 | return String.format(Locale.US, "%s -> %s", 137 | getQuestionMessage().toString().replace("\n", ""), 138 | getAnswerMessage().toString().replace("\n", "")); 139 | 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/answer/Synonyme.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.answer; 2 | 3 | import android.content.res.Resources; 4 | 5 | import com.fsoft.ihabot.R; 6 | import com.fsoft.ihabot.ApplicationManager; 7 | import com.fsoft.ihabot.Utils.CommandModule; 8 | import com.fsoft.ihabot.Utils.F; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.File; 12 | import java.io.FileReader; 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | 16 | /** 17 | * 18 | * Synonyme database replaces all words to its base synonym 19 | * 20 | * @author Dr. Failov 21 | * date 2022-03-28 22 | */ 23 | public class Synonyme extends CommandModule { 24 | private final ApplicationManager applicationManager; 25 | private static final int defaultDatabaseResource = R.raw.synonyme; 26 | private File fileSynonyme = null; 27 | private final ArrayList> synonymeRows = new ArrayList<>(); 28 | 29 | public Synonyme(AnswerDatabase answerDatabase) throws Exception { 30 | this.applicationManager = answerDatabase.getApplicationManager(); 31 | if(applicationManager == null) 32 | return; 33 | fileSynonyme = new File(answerDatabase.getFolderAnswerDatabase(), "synonyme.txt"); 34 | if(!fileSynonyme.isFile()){ 35 | log(". Файла синонимов нет. Загрузка файла synonyme.zip из ресурсов..."); 36 | loadDefaultDatabase(); 37 | } 38 | loadDefaultDatabase(); //todo это для отладки! 39 | 40 | BufferedReader bufferedReader = new BufferedReader(new FileReader(fileSynonyme)); 41 | String line; 42 | int lineNumber = 0; 43 | 44 | while ((line = bufferedReader.readLine()) != null) { 45 | lineNumber++; 46 | //- Заменить символы которые часто забивают писать (ё ъ щ) 47 | line = AnswerDatabase.replacePhoneticallySimilarLetters(line); 48 | // - устранить любые символы повторяющиеся несколько раз 49 | line = AnswerDatabase.removeRepeatingSymbols(line); 50 | if (lineNumber % 18 == 0) 51 | log(". Загрузка синонимов (" + lineNumber + " рядов загружено) ..."); 52 | try { 53 | ArrayList row = new ArrayList<>(Arrays.asList(line.split(","))); 54 | if(row.size() > 1){ 55 | synonymeRows.add(row); 56 | } 57 | else { 58 | log("! Строка " + lineNumber + " в базе синонимов содержит слишком мало синонимов"); 59 | } 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | log("! Ошибка разбора строки " + lineNumber + " как ряда синонимов.\n" + e.getMessage()); 63 | } 64 | } 65 | //завешить сессию 66 | bufferedReader.close(); 67 | System.gc(); 68 | log(". Загрузка синонимов из synonyme.txt прошла без ошибок. Загружено " + synonymeRows.size() + " рядов."); 69 | } 70 | 71 | /*текст на входе: 72 | - привести текст входящего сообшения к нижнему регистру 73 | - убрать обращение бот 74 | - Убрать все символы и знаки, оставить только текст 75 | - Заменить символы которые часто забивают писать (ё ъ щ) 76 | - устранить любые символы повторяющиеся несколько раз 77 | */ 78 | 79 | public String replaceSynonyms(String in){ 80 | in = " " + in + " "; 81 | for (ArrayList row:synonymeRows){ 82 | if(row.size() < 2) 83 | continue; 84 | String baseSynonyme = " " + row.get(0) + " "; 85 | for(int i=1;i login() -> startAccount() 19 | * constructor() -> startAccount() 20 | * Created by Dr. Failov on 22.02.2017. 21 | */ 22 | public class Account extends CommandModule implements AccountBase { 23 | private long id = 0L; 24 | private String token = null; 25 | //место для хранения данных этого аккаунта и любого наследованного аккаунта 26 | private FileStorage fileStorage = null; 27 | private String fileName = null; 28 | //это настройка для пользователя чтобы выключить аккаунт 29 | private boolean enabled = true; 30 | //устанавливается true во время запуска аккаунта 31 | private boolean running = false; 32 | //это - что-то наподобие временного комментария описывающего, что с этим аккаунтом происходит. 33 | private String state = ""; 34 | //Имя под которым можно отображать этот аккаунт в программе 35 | private String screenName = null; 36 | private Runnable onStateChangedListener = null; 37 | 38 | 39 | public Account(ApplicationManager applicationManager, String fileName) { 40 | super(); 41 | this.fileName = fileName; 42 | fileStorage = new FileStorage(fileName, applicationManager); 43 | log(". Создан аккаунт: " + fileName); 44 | 45 | enabled = getFileStorage().getBoolean("enabled", enabled); 46 | id = getFileStorage().getLong("id", id); 47 | token = getFileStorage().getString("token", token); 48 | screenName = getFileStorage().getString("screenName", screenName); 49 | 50 | } 51 | public boolean remove(){ 52 | //удалить файл аккаунта 53 | return new File(fileStorage.getFilePath()).delete(); 54 | } 55 | public void login(){ 56 | //открывает процедуру (пере)логина. 57 | // По итогу задает значение для token 58 | } 59 | public void startAccount(){ 60 | //если токен есть, эта функция его проверяет. Если токен валидный, 61 | //эта функция запускает работу во всех службах аккаунта, если isEnabled. 62 | running = true; 63 | log(". Аккаунт " + toString() + " запускается..."); 64 | setState("Запускается..."); 65 | //token_ok = true; //кажется, это не всегда связано 66 | } 67 | public void stopAccount(){ 68 | //эта функция останавливает работу во всех службах аккаунта 69 | running = false; 70 | log(". Аккаунт " + toString() + " остановлен."); 71 | setState("Остановлен."); 72 | // token_ok = false; ////кажется, это не всегда связано 73 | } 74 | protected interface OnTokenValidityCheckedListener{ 75 | void onTokenPass(); 76 | void onTokenFail(); 77 | } 78 | protected void checkTokenValidity(OnTokenValidityCheckedListener listener){ 79 | //запускать проверку и вызывать лисенер... 80 | log(". Аккаунт " + toString() + " проверяется..."); 81 | setState("Проверяется..."); 82 | } 83 | public boolean isMine(String commandTreatment){ 84 | //Эта функция должна отвечать за то, чтобы при обращении в команде 85 | // можно было понять что обращение именно к этому аккаунту 86 | //например bcd acc 098309832 enable 87 | try{ 88 | return Long.parseLong(commandTreatment.trim()) == id; 89 | }catch (Exception e){ 90 | return false; 91 | } 92 | } 93 | 94 | public boolean isEnabled() { 95 | return enabled; 96 | } 97 | public boolean isRunning() { 98 | return running; 99 | } 100 | public String getState() { 101 | return state; 102 | } 103 | public FileStorage getFileStorage() { 104 | return fileStorage; 105 | } 106 | public long getId() { 107 | return id; 108 | } 109 | public String getToken() { 110 | return token; 111 | } 112 | public String getFileName() { 113 | //именно это имя аккаунт получает при создании 114 | //эта функция нужна для того чтобы список аккаунтов можно было сохранить, не только загрузить 115 | return fileName; 116 | } 117 | public String getScreenName() { 118 | return screenName; 119 | } 120 | public void setScreenName(String screenName) { 121 | this.screenName = screenName; 122 | getFileStorage().put("screenName", screenName).commit(); 123 | } 124 | 125 | //------------ 126 | public void setEnabled(boolean enabled) { 127 | this.enabled = enabled; 128 | getFileStorage().put("enabled", enabled).commit(); 129 | if(isRunning() && !isEnabled()) 130 | stopAccount(); 131 | if(!isRunning() && isEnabled()) 132 | startAccount(); 133 | } 134 | public String state(String state) { 135 | setState(state); 136 | return state; 137 | } 138 | public void setState(String state) { 139 | String time = new SimpleDateFormat("HH:mm").format(new Date()); 140 | this.state = time + " " + state; 141 | if(onStateChangedListener != null) { 142 | try { 143 | onStateChangedListener.run(); 144 | } 145 | catch (Exception e){ 146 | e.printStackTrace(); 147 | } 148 | } 149 | } 150 | public void setId(long id) { 151 | this.id = id; 152 | getFileStorage().put("id", id).commit(); 153 | } 154 | public void setToken(String token) { 155 | this.token = token; 156 | getFileStorage().put("token", token).commit(); 157 | } 158 | public void setOnStateChangedListener(Runnable onStateChangedListener) { 159 | this.onStateChangedListener = onStateChangedListener; 160 | } 161 | 162 | @NonNull 163 | @Override public String toString() { 164 | return "Аккаунт " + id; 165 | } 166 | @Override public boolean equals(Object o) { 167 | if (this == o) return true; 168 | if (o == null || getClass() != o.getClass()) return false; 169 | 170 | Account account = (Account) o; 171 | 172 | if (getId() != account.getId()) return false; 173 | 174 | return true; 175 | } 176 | @Override public int hashCode() { 177 | return (int) (getId() ^ (getId() >>> 32)); 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/AccountBase.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation; 2 | 3 | import com.fsoft.ihabot.Utils.FileStorage; 4 | 5 | public interface AccountBase 6 | { 7 | public boolean remove(); 8 | public void startAccount(); 9 | public void stopAccount(); 10 | public boolean isEnabled(); 11 | public boolean isRunning(); 12 | public String getState(); 13 | public FileStorage getFileStorage(); 14 | public long getId(); 15 | public String getToken(); 16 | public String getFileName(); 17 | public void setEnabled(boolean enabled); 18 | public String state(String state); 19 | public void setState(String state); 20 | public void setId(long id); 21 | public void setToken(String token); 22 | public String getScreenName(); 23 | public void setScreenName(String screenName); 24 | } 25 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/Communicator.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation; 2 | 3 | import com.fsoft.ihabot.ApplicationManager; 4 | import com.fsoft.ihabot.Utils.CommandModule; 5 | import com.fsoft.ihabot.Utils.FileStorage; 6 | import com.fsoft.ihabot.communucation.tg.TgAccount; 7 | 8 | import java.util.ArrayList; 9 | 10 | /** 11 | * class for communication with VK 12 | * Created by Dr. Failov on 05.08.2014. 13 | */ 14 | public class Communicator extends CommandModule{ 15 | ApplicationManager applicationManager = null; 16 | private final ArrayList tgAccounts = new ArrayList<>(); 17 | private FileStorage file = null; 18 | private boolean running = false; 19 | 20 | public Communicator(ApplicationManager applicationManager) { 21 | this.applicationManager = applicationManager; 22 | file = new FileStorage("communicator",applicationManager); 23 | 24 | String[] accountList = file.getStringArray("TGaccounts", new String[0]); 25 | for (String acc:accountList) 26 | tgAccounts.add(new TgAccount(applicationManager, acc)); 27 | } 28 | public void startCommunicator(){ 29 | log("Запуск коммуникатора..."); 30 | running = true; 31 | for(TgAccount tgAccount:tgAccounts) { 32 | if(tgAccount.isEnabled()) 33 | tgAccount.startAccount(); 34 | } 35 | } 36 | public void stopCommunicator(){ 37 | running = false; 38 | for(TgAccount tgAccount:tgAccounts) { 39 | tgAccount.stopAccount(); 40 | } 41 | } 42 | public TgAccount getTgAccount(long id){ 43 | for (TgAccount account : tgAccounts) 44 | if (account.getId() == id) 45 | return account; 46 | return null; 47 | } 48 | public TgAccount getWorkingTgAccount(){ 49 | for (TgAccount account : tgAccounts) { 50 | if (account.isRunning() && account.isEnabled()) 51 | return account; 52 | } 53 | return null; 54 | } 55 | public ArrayList getTgAccounts() { 56 | return tgAccounts; 57 | } 58 | 59 | public boolean containsTgAccount(long id){ 60 | return getTgAccount(id) != null; 61 | } 62 | public void addAccount(TgAccount tgAccount) throws Exception{ 63 | if(tgAccount == null) 64 | throw new Exception("Аккаунт не получен"); 65 | if(containsTgAccount(tgAccount.getId())) { 66 | tgAccount.stopAccount(); 67 | throw new Exception("Такой аккаунт уже есть"); 68 | } 69 | tgAccounts.add(tgAccount); 70 | 71 | String[] accountList = new String[tgAccounts.size()]; 72 | for (int i = 0; i < tgAccounts.size(); i++) 73 | accountList[i] = tgAccounts.get(i).getFileName(); 74 | file.put("TGaccounts", accountList).commit(); 75 | log("Аккаунт " + tgAccount.getId() + " добавлен. Список аккаунтов сохранён."); 76 | } 77 | public void remAccount(TgAccount accountToRemove) throws Exception{ 78 | if(accountToRemove == null) 79 | throw new Exception("Функция удаления TG аккаунта вызвана с аргументом null"); 80 | if(running) 81 | accountToRemove.stopAccount(); 82 | tgAccounts.remove(accountToRemove); 83 | 84 | String[] accountList = new String[tgAccounts.size()]; 85 | for (int i = 0; i < tgAccounts.size(); i++) 86 | accountList[i] = tgAccounts.get(i).getFileName(); 87 | file.put("TGaccounts", accountList).commit(); 88 | 89 | if(accountToRemove.remove()) 90 | log("Аккаунт TG " + accountToRemove + " успешно удалён."); 91 | else 92 | throw new Exception("Аккаунт TG " + accountToRemove + " удалён из списка, но его файл удалить не получается."); 93 | } 94 | 95 | @Override 96 | public void stop() { 97 | stopCommunicator(); 98 | super.stop(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/Chat.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.text.ParseException; 7 | 8 | public class Chat { 9 | private long id = 0; 10 | private String type = ""; 11 | private String title = ""; 12 | private String username = ""; 13 | private String first_name = ""; 14 | private String last_name = ""; 15 | private String description = ""; 16 | private boolean all_members_are_administrators = false; 17 | 18 | public Chat() { 19 | } 20 | 21 | public Chat(JSONObject jsonObject) throws JSONException, ParseException { 22 | fromJson(jsonObject); 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | if(title == null || title.isEmpty()) 28 | return first_name + " " + last_name; 29 | else 30 | return title; 31 | } 32 | public JSONObject toJson() throws JSONException { 33 | JSONObject jsonObject = new JSONObject(); 34 | jsonObject.put("id", id); 35 | jsonObject.put("all_members_are_administrators", all_members_are_administrators); 36 | if(type != null) 37 | jsonObject.put("type", type); 38 | if(title != null) 39 | jsonObject.put("title", title); 40 | if(description != null) 41 | jsonObject.put("description", description); 42 | if(first_name != null) 43 | jsonObject.put("first_name", first_name); 44 | if(last_name != null) 45 | jsonObject.put("last_name", last_name); 46 | if(username != null) 47 | jsonObject.put("username", username); 48 | return jsonObject; 49 | } 50 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 51 | id = jsonObject.getLong("id"); 52 | if(jsonObject.has("all_members_are_administrators")) 53 | all_members_are_administrators = jsonObject.getBoolean("all_members_are_administrators"); 54 | if(jsonObject.has("first_name")) 55 | first_name = jsonObject.getString("first_name"); 56 | if(jsonObject.has("last_name")) 57 | last_name = jsonObject.getString("last_name"); 58 | if(jsonObject.has("username")) 59 | username = jsonObject.getString("username"); 60 | if(jsonObject.has("description")) 61 | description = jsonObject.getString("description"); 62 | if(jsonObject.has("title")) 63 | title = jsonObject.getString("title"); 64 | if(jsonObject.has("type")) 65 | type = jsonObject.getString("type"); 66 | } 67 | 68 | public long getId() { 69 | return id; 70 | } 71 | 72 | public void setId(long id) { 73 | this.id = id; 74 | } 75 | 76 | public String getType() { 77 | return type; 78 | } 79 | 80 | public void setType(String type) { 81 | this.type = type; 82 | } 83 | 84 | public String getTitle() { 85 | return title; 86 | } 87 | 88 | public void setTitle(String title) { 89 | this.title = title; 90 | } 91 | 92 | public String getUsername() { 93 | return username; 94 | } 95 | 96 | public void setUsername(String username) { 97 | this.username = username; 98 | } 99 | 100 | public String getFirst_name() { 101 | return first_name; 102 | } 103 | 104 | public void setFirst_name(String first_name) { 105 | this.first_name = first_name; 106 | } 107 | 108 | public String getLast_name() { 109 | return last_name; 110 | } 111 | 112 | public void setLast_name(String last_name) { 113 | this.last_name = last_name; 114 | } 115 | 116 | public String getDescription() { 117 | return description; 118 | } 119 | 120 | public void setDescription(String description) { 121 | this.description = description; 122 | } 123 | 124 | public boolean isAll_members_are_administrators() { 125 | return all_members_are_administrators; 126 | } 127 | 128 | public void setAll_members_are_administrators(boolean all_members_are_administrators) { 129 | this.all_members_are_administrators = all_members_are_administrators; 130 | } 131 | } 132 | 133 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/Document.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import com.fsoft.ihabot.communucation.Account; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.text.ParseException; 9 | 10 | public class Document { 11 | private String file_id = ""; 12 | private long file_size = 0; 13 | private String file_name = ""; 14 | 15 | public Document() { 16 | } 17 | public Document(String file_id, long file_size, String file_name) { 18 | this.file_id = file_id; 19 | this.file_size = file_size; 20 | this.file_name = file_name; 21 | } 22 | public Document(JSONObject jsonObject) throws JSONException, ParseException { 23 | fromJson(jsonObject); 24 | } 25 | 26 | public JSONObject toJson() throws JSONException { 27 | JSONObject jsonObject = new JSONObject(); 28 | if(file_id != null) 29 | jsonObject.put("file_id", file_id); 30 | jsonObject.put("file_size", file_size); 31 | if(file_name != null) 32 | jsonObject.put("file_name", file_name); 33 | return jsonObject; 34 | } 35 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 36 | if(jsonObject.has("file_id")) 37 | file_id = jsonObject.getString("file_id"); 38 | if(jsonObject.has("file_size")) 39 | file_size = jsonObject.getLong("file_size"); 40 | if(jsonObject.has("file_name")) 41 | file_name = jsonObject.getString("file_name"); 42 | } 43 | 44 | public String getFile_id() { 45 | return file_id; 46 | } 47 | 48 | public void setFile_id(String file_id) { 49 | this.file_id = file_id; 50 | } 51 | 52 | public long getFile_size() { 53 | return file_size; 54 | } 55 | 56 | public void setFile_size(long file_size) { 57 | this.file_size = file_size; 58 | } 59 | 60 | public String getFile_name() { 61 | return file_name; 62 | } 63 | 64 | public void setFile_name(String file_name) { 65 | this.file_name = file_name; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/File.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import com.fsoft.ihabot.communucation.Account; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.text.ParseException; 9 | 10 | public class File { 11 | private String file_id = ""; 12 | private long file_size = 0; 13 | private String file_path = ""; 14 | 15 | public File() { 16 | } 17 | public File(String file_id, long file_size, String file_path) { 18 | this.file_id = file_id; 19 | this.file_size = file_size; 20 | this.file_path = file_path; 21 | } 22 | public File(JSONObject jsonObject) throws JSONException, ParseException { 23 | fromJson(jsonObject); 24 | } 25 | 26 | public JSONObject toJson() throws JSONException { 27 | JSONObject jsonObject = new JSONObject(); 28 | if(file_id != null) 29 | jsonObject.put("file_id", file_id); 30 | jsonObject.put("file_size", file_size); 31 | if(file_path != null) 32 | jsonObject.put("file_path", file_path); 33 | return jsonObject; 34 | } 35 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 36 | if(jsonObject.has("file_id")) 37 | file_id = jsonObject.getString("file_id"); 38 | if(jsonObject.has("file_size")) 39 | file_size = jsonObject.getLong("file_size"); 40 | if(jsonObject.has("file_path")) 41 | file_path = jsonObject.getString("file_path"); 42 | } 43 | 44 | public String getUrl(Account tgAccount){ 45 | //https://api.telegram.org/file/bot/ 46 | return "https://api.telegram.org/file/bot" + tgAccount.getId() + ":"+tgAccount.getToken()+"/"+file_path; 47 | } 48 | 49 | 50 | public String getFile_id() { 51 | return file_id; 52 | } 53 | 54 | public void setFile_id(String file_id) { 55 | this.file_id = file_id; 56 | } 57 | 58 | public long getFile_size() { 59 | return file_size; 60 | } 61 | 62 | public void setFile_size(long file_size) { 63 | this.file_size = file_size; 64 | } 65 | 66 | public String getFile_path() { 67 | return file_path; 68 | } 69 | 70 | public void setFile_path(String file_path) { 71 | this.file_path = file_path; 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/MessageEntity.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.text.ParseException; 7 | 8 | /* 9 | https://core.telegram.org/bots/api#messageentity 10 | 11 | drfailov 2018-08-19 12 | * */ 13 | public class MessageEntity { 14 | private String type = ""; 15 | private int offset = 0; 16 | private int length = 0; 17 | private String url = ""; 18 | private User user = null; 19 | 20 | public MessageEntity() { 21 | } 22 | public MessageEntity(String type, int offset, int length, String url, User user) { 23 | this.type = type; 24 | this.offset = offset; 25 | this.length = length; 26 | this.url = url; 27 | this.user = user; 28 | } 29 | public MessageEntity(String type, int offset, int length) { 30 | this.type = type; 31 | this.offset = offset; 32 | this.length = length; 33 | } 34 | public MessageEntity(String type, int offset, int length, User user) { 35 | this.type = type; 36 | this.offset = offset; 37 | this.length = length; 38 | this.user = user; 39 | } 40 | public MessageEntity(JSONObject jsonObject) throws JSONException, ParseException { 41 | fromJson(jsonObject); 42 | } 43 | 44 | 45 | public JSONObject toJson() throws JSONException { 46 | JSONObject jsonObject = new JSONObject(); 47 | if(type != null) 48 | jsonObject.put("type", type); 49 | if(offset != 0) 50 | jsonObject.put("offset", offset); 51 | if(length != 0) 52 | jsonObject.put("length", length); 53 | if(url != null) 54 | jsonObject.put("url", url); 55 | if(user != null) 56 | jsonObject.put("user", user.toJson()); 57 | return jsonObject; 58 | } 59 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 60 | if(jsonObject.has("type")) 61 | type = jsonObject.getString("type"); 62 | if(jsonObject.has("offset")) 63 | offset = jsonObject.getInt("offset"); 64 | if(jsonObject.has("length")) 65 | length = jsonObject.getInt("length"); 66 | if(jsonObject.has("url")) 67 | url = jsonObject.getString("url"); 68 | if(jsonObject.has("user")) 69 | user = new User(jsonObject.getJSONObject("user")); 70 | } 71 | 72 | public String getType() { 73 | return type; 74 | } 75 | public void setType(String type) { 76 | this.type = type; 77 | } 78 | public int getOffset() { 79 | return offset; 80 | } 81 | public void setOffset(int offset) { 82 | this.offset = offset; 83 | } 84 | public int getLength() { 85 | return length; 86 | } 87 | public void setLength(int length) { 88 | this.length = length; 89 | } 90 | public String getUrl() { 91 | return url; 92 | } 93 | public void setUrl(String url) { 94 | this.url = url; 95 | } 96 | public User getUser() { 97 | return user; 98 | } 99 | public void setUser(User user) { 100 | this.user = user; 101 | } 102 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/PhotoSize.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | import org.json.JSONException; 3 | import org.json.JSONObject; 4 | 5 | import java.text.ParseException; 6 | 7 | public class PhotoSize { 8 | private String file_id = ""; 9 | private long file_size = 0; 10 | private int height = 0; 11 | private int width = 0; 12 | 13 | public PhotoSize() { 14 | } 15 | 16 | public PhotoSize(String file_id, long file_size, int height, int width) { 17 | this.file_id = file_id; 18 | this.file_size = file_size; 19 | this.height = height; 20 | this.width = width; 21 | } 22 | 23 | public PhotoSize(JSONObject jsonObject) throws JSONException, ParseException { 24 | fromJson(jsonObject); 25 | } 26 | 27 | public JSONObject toJson() throws JSONException { 28 | JSONObject jsonObject = new JSONObject(); 29 | if(file_id != null) 30 | jsonObject.put("file_id", file_id); 31 | jsonObject.put("file_size", file_size); 32 | jsonObject.put("height", height); 33 | jsonObject.put("width", width); 34 | return jsonObject; 35 | } 36 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 37 | if(jsonObject.has("file_id")) 38 | file_id = jsonObject.getString("file_id"); 39 | if(jsonObject.has("file_size")) 40 | file_size = jsonObject.getLong("file_size"); 41 | if(jsonObject.has("height")) 42 | height = jsonObject.getInt("height"); 43 | if(jsonObject.has("width")) 44 | width = jsonObject.getInt("width"); 45 | } 46 | 47 | public String getFile_id() { 48 | return file_id; 49 | } 50 | 51 | public void setFile_id(String file_id) { 52 | this.file_id = file_id; 53 | } 54 | 55 | public long getFile_size() { 56 | return file_size; 57 | } 58 | 59 | public void setFile_size(long file_size) { 60 | this.file_size = file_size; 61 | } 62 | 63 | public int getHeight() { 64 | return height; 65 | } 66 | 67 | public void setHeight(int height) { 68 | this.height = height; 69 | } 70 | 71 | public int getWidth() { 72 | return width; 73 | } 74 | 75 | public void setWidth(int width) { 76 | this.width = width; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/Sticker.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.text.ParseException; 7 | 8 | /** 9 | * https://core.telegram.org/bots/api#sticker 10 | * @author Dr. Failov 11 | */ 12 | public class Sticker { 13 | private String file_id = ""; 14 | private int height = 0; 15 | private int width = 0; 16 | private long file_size = 0; 17 | private boolean is_animated = false; 18 | private boolean is_video = false; 19 | 20 | 21 | public Sticker(String file_id, int height, int width, boolean is_animated, boolean is_video) { 22 | this.file_id = file_id; 23 | this.height = height; 24 | this.width = width; 25 | this.is_animated = is_animated; 26 | this.is_video = is_video; 27 | } 28 | public Sticker(JSONObject jsonObject) throws JSONException, ParseException { 29 | fromJson(jsonObject); 30 | } 31 | 32 | public JSONObject toJson() throws JSONException { 33 | JSONObject jsonObject = new JSONObject(); 34 | if(file_id != null) 35 | jsonObject.put("file_id", file_id); 36 | jsonObject.put("height", height); 37 | jsonObject.put("width", width); 38 | jsonObject.put("file_size", file_size); 39 | jsonObject.put("is_animated", is_animated); 40 | jsonObject.put("is_video", is_video); 41 | return jsonObject; 42 | } 43 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 44 | if(jsonObject.has("file_id")) 45 | file_id = jsonObject.getString("file_id"); 46 | if(jsonObject.has("height")) 47 | height = jsonObject.getInt("height"); 48 | if(jsonObject.has("width")) 49 | width = jsonObject.getInt("width"); 50 | if(jsonObject.has("file_size")) 51 | file_size = jsonObject.getLong("file_size"); 52 | if(jsonObject.has("is_animated")) 53 | is_animated = jsonObject.getBoolean("is_animated"); 54 | if(jsonObject.has("is_video")) 55 | is_video = jsonObject.getBoolean("is_video"); 56 | } 57 | 58 | public String getFile_id() { 59 | return file_id; 60 | } 61 | 62 | public void setFile_id(String file_id) { 63 | this.file_id = file_id; 64 | } 65 | 66 | public int getHeight() { 67 | return height; 68 | } 69 | 70 | public void setHeight(int height) { 71 | this.height = height; 72 | } 73 | 74 | public int getWidth() { 75 | return width; 76 | } 77 | 78 | public void setWidth(int width) { 79 | this.width = width; 80 | } 81 | 82 | public boolean isIs_animated() { 83 | return is_animated; 84 | } 85 | 86 | public void setIs_animated(boolean is_animated) { 87 | this.is_animated = is_animated; 88 | } 89 | 90 | public boolean isIs_video() { 91 | return is_video; 92 | } 93 | 94 | public void setIs_video(boolean is_video) { 95 | this.is_video = is_video; 96 | } 97 | 98 | public long getFile_size() { 99 | return file_size; 100 | } 101 | 102 | public void setFile_size(long file_size) { 103 | this.file_size = file_size; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/TgAccount.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import com.fsoft.ihabot.ApplicationManager; 4 | import com.fsoft.ihabot.Utils.F; 5 | 6 | import java.io.DataInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.MalformedURLException; 11 | import java.net.URL; 12 | import java.text.SimpleDateFormat; 13 | import java.util.ArrayList; 14 | import java.util.Calendar; 15 | import java.util.Date; 16 | import java.util.Locale; 17 | import java.util.concurrent.TimeoutException; 18 | 19 | public class TgAccount extends TgAccountCore { 20 | private MessageProcessor messageProcessor = null; 21 | 22 | public TgAccount(ApplicationManager applicationManager, String fileName) { 23 | super(applicationManager, fileName); 24 | messageProcessor = new MessageProcessor(applicationManager, this); 25 | } 26 | 27 | @Override 28 | public void startAccount() { 29 | super.startAccount(); 30 | checkTokenValidity(new OnTokenValidityCheckedListener() { 31 | @Override 32 | public void onTokenPass() { 33 | messageProcessor.startModule(); 34 | } 35 | 36 | @Override 37 | public void onTokenFail() { 38 | 39 | } 40 | }); 41 | } 42 | 43 | @Override 44 | public void stopAccount() { 45 | super.stopAccount(); 46 | messageProcessor.stopModule(); 47 | } 48 | 49 | 50 | public MessageProcessor getMessageProcessor() { 51 | return messageProcessor; 52 | } 53 | public void sendMessage(long chatId, com.fsoft.ihabot.answer.Message message){ 54 | messageProcessor.sendAnswer(chatId, message); 55 | } 56 | /** 57 | * Блокирующая(!) версия функции для скачивания файла из телеграма в локальное хранилище. 58 | * Файл будет сохранен под автоматически выбранным именем во временной папке. 59 | * @param fileId FileID с серверов телеграма 60 | * @return Файл который скачан во временную папку 61 | * @throws Exception работаем с фалами и сетью. Может случиться что угодно. 62 | */ 63 | public java.io.File downloadPhotoAttachment(String fileId) throws Exception{ 64 | log("Попытка получить ссылку для скачивания файла вложения..."); 65 | final ArrayList files = new ArrayList<>(); 66 | final ArrayList exceptions = new ArrayList<>(); 67 | getFile(new GetFileListener() { 68 | @Override 69 | public void gotFile(File file) { 70 | if(file.getFile_path() == null || file.getFile_path().isEmpty()){ 71 | exceptions.add(new Exception("Телеграм не прислал ссылку на файл для скачивания.")); 72 | return; 73 | } 74 | String directLink = "https://api.telegram.org/file/bot"+getId()+":"+getToken() + "/" + file.getFile_path(); 75 | log("Ссылка на файл получена. Попытка скачать файл: " +directLink); 76 | String fileRes = F.getFileExtension(file.getFile_path()); 77 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSS", Locale.US); 78 | String filename = simpleDateFormat.format(new Date()); 79 | if(!fileRes.isEmpty()) 80 | filename += fileRes; 81 | java.io.File placeToSave = new java.io.File(ApplicationManager.getInstance().getTempFolder(), filename); 82 | log("Скачивать файл будем сюда: " + placeToSave.getAbsolutePath()); 83 | 84 | try { 85 | URL u = new URL(directLink); 86 | try(InputStream is = u.openStream()) { 87 | DataInputStream dis = new DataInputStream(is); 88 | byte[] buffer = new byte[1024]; 89 | int length; 90 | try(FileOutputStream fos = new FileOutputStream(placeToSave)) { 91 | while ((length = dis.read(buffer)) > 0) { 92 | fos.write(buffer, 0, length); 93 | } 94 | } 95 | } 96 | log("Загрузка файла прошла без ошибок. Загружено " + placeToSave.length() + " байт."); 97 | } catch (MalformedURLException mue) { 98 | exceptions.add(new Exception(log("Ошибка MalformedURLException скачивания файла фото: " + mue))); 99 | mue.printStackTrace(); 100 | return; 101 | } catch (IOException ioe) { 102 | exceptions.add(new Exception(log("Ошибка IOException скачивания файла: " + ioe.getLocalizedMessage()))); 103 | ioe.printStackTrace(); 104 | return; 105 | } catch (SecurityException se) { 106 | exceptions.add(new Exception(log("Ошибка SecurityException скачивания файла: " + se.getLocalizedMessage()))); 107 | se.printStackTrace(); 108 | return; 109 | } 110 | if(placeToSave.isFile()) 111 | files.add(placeToSave); 112 | else 113 | exceptions.add(new Exception(log("Всё вроде прошло норм, но фото не был скачан."))); 114 | } 115 | 116 | @Override 117 | public void error(Throwable error) { 118 | 119 | } 120 | }, fileId); 121 | 122 | 123 | Date started = new Date(); 124 | //ждать пока что-то появится либо пока не будет какая-то ошибка, либо таймаут 30 секунд 125 | while (files.isEmpty() && exceptions.isEmpty()){ 126 | if(Calendar.getInstance().getTime().getTime() - started.getTime() > 60000) { 127 | throw new TimeoutException("Таймаут, файл не получилось скачать."); 128 | } 129 | } 130 | if(!files.isEmpty()){ 131 | log("Был получен файл: " + files.get(0).getName()); 132 | return files.get(0); 133 | } 134 | if(!exceptions.isEmpty()) { 135 | log("Была получена ошибка: " + exceptions.get(0)); 136 | throw exceptions.get(0); 137 | } 138 | throw new Exception("Во время скачивания файла фотографии ни файл ни ошибка не получены. Это странная ситуация."); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/Update.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.text.ParseException; 7 | 8 | /* 9 | * 10 | * https://core.telegram.org/bots/api#update 11 | * 12 | * Created by Dr. Failov 2018-07-24 13 | * */ 14 | public class Update { 15 | private long update_id = 0; 16 | private Message message = null; 17 | private Message edited_message = null; 18 | 19 | public Update(JSONObject jsonObject) throws JSONException, ParseException { 20 | fromJson(jsonObject); 21 | } 22 | 23 | public JSONObject toJson() throws JSONException { 24 | JSONObject jsonObject = new JSONObject(); 25 | jsonObject.put("update_id", update_id); 26 | if(message != null) 27 | jsonObject.put("message", message.toJson()); 28 | if(edited_message != null) 29 | jsonObject.put("edited_message", edited_message.toJson()); 30 | return jsonObject; 31 | } 32 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 33 | update_id = jsonObject.getLong("update_id"); 34 | if(jsonObject.has("message")) 35 | message = new Message(jsonObject.getJSONObject("message")); 36 | if(jsonObject.has("edited_message")) 37 | edited_message = new Message(jsonObject.getJSONObject("edited_message")); 38 | } 39 | 40 | public long getUpdate_id() { 41 | return update_id; 42 | } 43 | 44 | public void setUpdate_id(long update_id) { 45 | this.update_id = update_id; 46 | } 47 | 48 | public Message getMessage() { 49 | return message; 50 | } 51 | 52 | public void setMessage(Message message) { 53 | this.message = message; 54 | } 55 | 56 | public Message getEdited_message() { 57 | return edited_message; 58 | } 59 | 60 | public void setEdited_message(Message edited_message) { 61 | this.edited_message = edited_message; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/User.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.fsoft.ihabot.Utils.F; 8 | 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.text.ParseException; 13 | import java.util.Locale; 14 | import java.util.Objects; 15 | 16 | /*Telegram user according to telegram API*/ 17 | public class User { 18 | private long id = 0; 19 | private boolean is_bot = false; 20 | private String first_name = ""; 21 | private String last_name = ""; 22 | private String username = ""; 23 | private String language_code = ""; 24 | 25 | public User() { 26 | } 27 | 28 | public User(long id, String username, String first_name, String last_name) { 29 | this.id = id; 30 | this.first_name = first_name; 31 | this.last_name = last_name; 32 | this.username = username; 33 | } 34 | 35 | public User(JSONObject jsonObject) throws JSONException, ParseException { 36 | fromJson(jsonObject); 37 | } 38 | 39 | public User(long id, String username) { 40 | this.id = id; 41 | this.username = username; 42 | } 43 | 44 | public User(long id, boolean is_bot, String first_name, String last_name, String username, String language_code) { 45 | this.id = id; 46 | this.is_bot = is_bot; 47 | this.first_name = first_name; 48 | this.last_name = last_name; 49 | this.username = username; 50 | this.language_code = language_code; 51 | } 52 | 53 | public JSONObject toJson() throws JSONException { 54 | JSONObject jsonObject = new JSONObject(); 55 | jsonObject.put("id", id); 56 | jsonObject.put("is_bot", is_bot); 57 | if(first_name != null) 58 | jsonObject.put("first_name", first_name); 59 | if(last_name != null) 60 | jsonObject.put("last_name", last_name); 61 | if(username != null) 62 | jsonObject.put("username", username); 63 | if(language_code != null) 64 | jsonObject.put("language_code", language_code); 65 | return jsonObject; 66 | } 67 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 68 | try { 69 | id = jsonObject.getLong("id"); 70 | if (jsonObject.has("username")) 71 | username = jsonObject.getString("username"); 72 | if (jsonObject.has("is_bot")) 73 | is_bot = jsonObject.getBoolean("is_bot"); 74 | if (jsonObject.has("name")) //for backward compatibiluty with old format of users (before 2022-04) 75 | first_name = jsonObject.getString("name"); 76 | if (jsonObject.has("first_name")) 77 | first_name = jsonObject.getString("first_name"); 78 | if (jsonObject.has("last_name")) 79 | last_name = jsonObject.getString("last_name"); 80 | if (jsonObject.has("language_code")) 81 | language_code = jsonObject.getString("language_code"); 82 | } 83 | catch (Exception e){ 84 | Log.d("USER ERROR " + e.getMessage(), jsonObject.toString()); 85 | throw e; 86 | } 87 | } 88 | public String getName(){ 89 | if(last_name.isEmpty() || first_name.isEmpty()) 90 | return username; 91 | else 92 | return first_name + " " + last_name; 93 | } 94 | 95 | /** 96 | * вовзарает является ли текстовое описание пользователя его однознозначным представлением базируясь на Username или ID 97 | * @param usernameOrId текст его ID, либо username. Можно с собакой можно без. 98 | * @return да, если описание полностью соотвествует текущему юзеру 99 | */ 100 | public boolean isIt(String usernameOrId){ 101 | if(usernameOrId == null) 102 | return false; 103 | if(usernameOrId.trim().isEmpty()) 104 | return false; 105 | if (F.isDigitsOnly(usernameOrId) && id != 0){ 106 | try { 107 | long result = Long.parseLong(usernameOrId); 108 | if(result == 0) 109 | return false; 110 | return id == result; 111 | } 112 | catch (Exception e){ 113 | //похуй 114 | } 115 | } 116 | usernameOrId = usernameOrId.replace("@", "").toLowerCase(Locale.ROOT).trim(); 117 | if(getUsername() != null) 118 | return getUsername().replace("@", "").toLowerCase(Locale.ROOT).trim().equals(usernameOrId); 119 | return false; 120 | } 121 | 122 | public long getId() { 123 | return id; 124 | } 125 | 126 | public void setId(long id) { 127 | this.id = id; 128 | } 129 | 130 | public boolean isIs_bot() { 131 | return is_bot; 132 | } 133 | 134 | public void setIs_bot(boolean is_bot) { 135 | this.is_bot = is_bot; 136 | } 137 | 138 | public String getFirst_name() { 139 | return first_name; 140 | } 141 | 142 | public void setFirst_name(String first_name) { 143 | this.first_name = first_name; 144 | } 145 | 146 | public String getLast_name() { 147 | return last_name; 148 | } 149 | 150 | public void setLast_name(String last_name) { 151 | this.last_name = last_name; 152 | } 153 | 154 | public String getUsername() { 155 | return username; 156 | } 157 | 158 | public void setUsername(String username) { 159 | this.username = username; 160 | } 161 | 162 | public String getLanguage_code() { 163 | return language_code; 164 | } 165 | 166 | public void setLanguage_code(String language_code) { 167 | this.language_code = language_code; 168 | } 169 | 170 | @Override 171 | public boolean equals(Object o) { 172 | if (this == o) return true; 173 | if (o == null || getClass() != o.getClass()) return false; 174 | User userTg = (User) o; 175 | if(id == userTg.id) 176 | return true; 177 | return username != null && userTg.username != null && userTg.username.equals(username); 178 | } 179 | 180 | @Override 181 | public int hashCode() { 182 | return Objects.hash(id, username); 183 | } 184 | 185 | @NonNull 186 | @Override 187 | public String toString() { 188 | StringBuilder sb = new StringBuilder(); 189 | if(!first_name.isEmpty()) 190 | sb.append(first_name); 191 | sb.append(" "); 192 | if(!last_name.isEmpty()) 193 | sb.append(last_name); 194 | if(!first_name.isEmpty() || !last_name.isEmpty()) 195 | sb.append(" ("); 196 | if(username != null) 197 | sb.append("@").append(username); 198 | else 199 | sb.append("ID ").append(id).append(""); 200 | if(!first_name.isEmpty() || !last_name.isEmpty()) 201 | sb.append(")"); 202 | return sb.toString().trim(); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/communucation/tg/UserProfilePhotos.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.communucation.tg; 2 | 3 | 4 | import org.json.JSONArray; 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.text.ParseException; 9 | import java.util.ArrayList; 10 | 11 | public class UserProfilePhotos { 12 | private int total_count = 0; 13 | private ArrayList> arrayPhotos = new ArrayList<>(); 14 | 15 | public UserProfilePhotos() { 16 | } 17 | 18 | public UserProfilePhotos(int total_count, ArrayList> photos) { 19 | this.total_count = total_count; 20 | this.arrayPhotos = photos; 21 | } 22 | public UserProfilePhotos(JSONObject jsonObject) throws JSONException, ParseException { 23 | fromJson(jsonObject); 24 | } 25 | 26 | public JSONObject toJson() throws JSONException { 27 | JSONObject jsonObject = new JSONObject(); 28 | jsonObject.put("total_count", total_count); 29 | if(arrayPhotos != null && !arrayPhotos.isEmpty()) { 30 | JSONArray jsonArrayPhotos = new JSONArray(); 31 | for (int i = 0; i < arrayPhotos.size(); i++){ 32 | JSONArray jsonArrayPhoto = new JSONArray(); 33 | ArrayList arrayPhoto = arrayPhotos.get(i); 34 | for (int j = 0; j < arrayPhoto.size(); j++){ 35 | jsonArrayPhoto.put(arrayPhoto.get(i).toJson()); 36 | } 37 | jsonArrayPhotos.put(jsonArrayPhoto); 38 | } 39 | jsonObject.put("photos", jsonArrayPhotos); 40 | } 41 | return jsonObject; 42 | } 43 | private void fromJson(JSONObject jsonObject)throws JSONException, ParseException { 44 | if(jsonObject.has("total_count")) 45 | total_count = jsonObject.getInt("total_count"); 46 | arrayPhotos.clear(); 47 | if(jsonObject.has("photos")){ 48 | JSONArray jsonArrayPhotos = jsonObject.getJSONArray("photos"); 49 | for (int i = 0; i < jsonArrayPhotos.length(); i++) { 50 | JSONArray jsonArrayPhoto = jsonArrayPhotos.getJSONArray(i); 51 | ArrayList arrayPhoto = new ArrayList<>(); 52 | for (int j = 0; j < jsonArrayPhoto.length(); j++) { 53 | JSONObject arrayItem = jsonArrayPhoto.getJSONObject(j); 54 | arrayPhoto.add(new PhotoSize(arrayItem)); 55 | } 56 | arrayPhotos.add(arrayPhoto); 57 | } 58 | } 59 | } 60 | 61 | public int getTotal_count() { 62 | return total_count; 63 | } 64 | 65 | public void setTotal_count(int total_count) { 66 | this.total_count = total_count; 67 | } 68 | 69 | public ArrayList> getArrayPhotos() { 70 | return arrayPhotos; 71 | } 72 | 73 | public void setArrayPhotos(ArrayList> arrayPhotos) { 74 | this.arrayPhotos = arrayPhotos; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/TgLoginWindow.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui; 2 | 3 | 4 | import android.app.Activity; 5 | import android.app.Dialog; 6 | import android.os.Handler; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.widget.EditText; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import com.fsoft.ihabot.R; 15 | import com.fsoft.ihabot.ApplicationManager; 16 | import com.fsoft.ihabot.Utils.CommandModule; 17 | import com.fsoft.ihabot.communucation.tg.TgAccount; 18 | import com.fsoft.ihabot.communucation.tg.TgAccountCore; 19 | import com.fsoft.ihabot.communucation.tg.User; 20 | 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | 24 | /** 25 | * Это окно должно заниматься процедурой логина в аккаунт. 26 | * В его задачи входит: 27 | * - получить обьект аккаунта который нужно залогинить 28 | * - открыть окно логина и ждать пока пользователь залогинится 29 | * - проверить токен на валидность 30 | * - как только токен получен, закрыться и сообщить об успешном логине 31 | * - самостоятельно задать токен в обьекте vkAccount и сделать Start Account 32 | * 33 | * 34 | * Created by Dr. Failov on 22.07.2018. 35 | */ 36 | 37 | public class TgLoginWindow extends CommandModule { 38 | private Handler handler = new Handler(); 39 | private TgAccount tgAccount = null; 40 | private Dialog loginDialog = null; 41 | private Activity activity = null; 42 | private OnSuccessfulLoginListener onSuccessfulLoginListener = null; 43 | 44 | private EditText tokenField; 45 | private TextView saveButton; 46 | private View closeButton; 47 | 48 | public TgLoginWindow(Activity activity, OnSuccessfulLoginListener onSuccessfulLoginListener) { 49 | super(); 50 | this.activity = activity; 51 | this.tgAccount = new TgAccount(ApplicationManager.getInstance(), "acc" + new SimpleDateFormat("_yyyy-MM-dd_HH-mm-ss").format(new Date()) + ".json"); 52 | this.onSuccessfulLoginListener = onSuccessfulLoginListener; 53 | showLoginWindow(); 54 | } 55 | 56 | private void showLoginWindow(){ 57 | if(loginDialog == null) { 58 | handler.post(new Runnable() { 59 | @Override 60 | public void run() { 61 | try { 62 | log("Войди в аккаунт"); 63 | loginDialog = new Dialog(activity); 64 | loginDialog.setCancelable(false); 65 | loginDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 66 | loginDialog.setContentView(R.layout.dialog_add_telegram_account); 67 | loginDialog.getWindow().getAttributes().width = WindowManager.LayoutParams.MATCH_PARENT; 68 | tokenField = loginDialog.findViewById(R.id.dialog_add_telegram_account_field_token); 69 | saveButton = loginDialog.findViewById(R.id.dialogAdd_telegram_accountButtonSave); 70 | closeButton = loginDialog.findViewById(R.id.dialogadd_telegram_accountButtonCancel); 71 | if(saveButton != null) 72 | saveButton.setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | saveButton(); 76 | } 77 | }); 78 | if(closeButton != null) 79 | closeButton.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | closeLoginWindow(); 83 | //String resultOfDeletion = applicationManager.getCommunicator().remTgAccount(tgAccount); 84 | //Toast.makeText(activity, resultOfDeletion, Toast.LENGTH_SHORT).show(); 85 | // if(howToRefresh != null) 86 | // howToRefresh.run(); 87 | } 88 | }); 89 | loginDialog.show(); 90 | } catch (Throwable e) { 91 | e.printStackTrace(); 92 | log("! Ошибка показа окна логина: " + e.toString()); 93 | } 94 | } 95 | }); 96 | } 97 | } 98 | private void closeLoginWindow(){ 99 | if(loginDialog != null) { 100 | loginDialog.dismiss(); 101 | loginDialog = null; 102 | } 103 | } 104 | private void saveButton() { 105 | //проверить и если валидно сохранить 106 | if(tokenField == null) 107 | return; 108 | String tokenString = tokenField.getText().toString(); 109 | String[] parts = tokenString.split(":"); 110 | if(parts.length != 2) { 111 | Toast.makeText(activity, "Токен введён неверно.", Toast.LENGTH_SHORT).show(); 112 | return; 113 | } 114 | String idString = parts[0]; 115 | String token = parts[1]; 116 | long id = 0; 117 | try { 118 | id = Long.parseLong(idString); 119 | } 120 | catch (Exception e){ 121 | Toast.makeText(activity, "Токен введён неверно: " + e.getMessage(), Toast.LENGTH_SHORT).show(); 122 | return; 123 | } 124 | tgAccount.setId(id); 125 | tgAccount.setToken(token); 126 | tgAccount.getMe(new TgAccountCore.GetMeListener() { 127 | @Override 128 | public void gotUser(User user) { 129 | Toast.makeText(activity, "Вход выполнен!", Toast.LENGTH_SHORT).show(); 130 | closeLoginWindow(); 131 | //tgAccount.startAccount(); 132 | if(onSuccessfulLoginListener != null) 133 | onSuccessfulLoginListener.onSuccessfulLogin(tgAccount); 134 | } 135 | 136 | @Override 137 | public void error(Throwable error) { 138 | saveButton.setEnabled(true); 139 | saveButton.setText("Сохранить"); 140 | tgAccount.setId(0); 141 | tgAccount.setToken(""); 142 | Toast.makeText(activity, "Токен не сработал: " + error.getClass().getName() + " " + error.getMessage(), Toast.LENGTH_SHORT).show(); 143 | } 144 | }); 145 | saveButton.setEnabled(false); 146 | saveButton.setText("Проверка..."); 147 | } 148 | 149 | public interface OnSuccessfulLoginListener{ 150 | void onSuccessfulLogin(TgAccount tgAccount); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/accounts/AccountsFragment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.accounts; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.ListView; 15 | import android.widget.PopupMenu; 16 | 17 | import androidx.annotation.NonNull; 18 | import androidx.fragment.app.Fragment; 19 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 20 | 21 | import com.fsoft.ihabot.R; 22 | import com.fsoft.ihabot.ApplicationManager; 23 | import com.fsoft.ihabot.communucation.tg.TgAccount; 24 | import com.google.android.material.snackbar.Snackbar; 25 | 26 | public class AccountsFragment extends Fragment { 27 | ListView listView; 28 | SwipeRefreshLayout swipeRefreshLayout; 29 | 30 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 31 | View root = inflater.inflate(R.layout.fragment_accounts_layout, container, false); 32 | listView = root.findViewById(R.id.listview_accounts_list); 33 | swipeRefreshLayout = root.findViewById(R.id.swiperefreshlayout_accounts_list); 34 | listView.setAdapter(new AccountsAdapter(getActivity())); 35 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 36 | @Override 37 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 38 | try { 39 | final TgAccount tgAccount = ApplicationManager.getInstance().getCommunicator().getTgAccounts().get(i); 40 | if(tgAccount == null) 41 | return; 42 | PopupMenu popupMenu = new PopupMenu(getActivity(), view); 43 | popupMenu.inflate(R.menu.account_popup_menu); 44 | if(tgAccount.isEnabled()) 45 | popupMenu.getMenu().findItem(R.id.action_enable_account).setVisible(false); 46 | else 47 | popupMenu.getMenu().findItem(R.id.action_disable_account).setVisible(false); 48 | popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 49 | @Override 50 | public boolean onMenuItemClick(MenuItem item) { 51 | if (item.getItemId() == R.id.action_copy_account_username) { 52 | if(getActivity() != null) { 53 | ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); 54 | String text = "@" + tgAccount.getUserName(); 55 | clipboardManager.setPrimaryClip(ClipData.newPlainText("username", text)); 56 | } 57 | } 58 | if (item.getItemId() == R.id.action_disable_account) { 59 | tgAccount.setEnabled(false); 60 | } 61 | if (item.getItemId() == R.id.action_enable_account) { 62 | tgAccount.setEnabled(true); 63 | } 64 | if (item.getItemId() == R.id.action_delete_account) { 65 | new AlertDialog.Builder(getActivity()) 66 | .setTitle("Удаление аккаунта") 67 | .setMessage("Вы действительно хотите удалить аккаунт " + tgAccount.getScreenName() + "?") 68 | .setIcon(android.R.drawable.ic_dialog_alert) 69 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 70 | public void onClick(DialogInterface dialog, int whichButton) { 71 | try{ 72 | ApplicationManager.getInstance().getCommunicator().remAccount(tgAccount); 73 | Snackbar.make(view, "Аккаунт "+tgAccount.getScreenName()+" успешно удалён", Snackbar.LENGTH_SHORT).show(); 74 | } 75 | catch (Exception e){ 76 | e.printStackTrace(); 77 | Snackbar.make(view, "Ошибка: "+e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show(); 78 | } 79 | }}) 80 | .setNegativeButton(android.R.string.no, null).show(); 81 | } 82 | return false; 83 | } 84 | }); 85 | popupMenu.show(); 86 | } 87 | catch (Exception e){ 88 | e.printStackTrace(); 89 | } 90 | } 91 | }); 92 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 93 | @Override 94 | public void onRefresh() { 95 | if(listView != null) 96 | listView.invalidateViews(); 97 | if(swipeRefreshLayout != null) 98 | swipeRefreshLayout.setRefreshing(false); 99 | } 100 | }); 101 | return root; 102 | } 103 | 104 | @Override 105 | public void onDestroyView() { 106 | super.onDestroyView(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/admins/AddAdminUsersAdapter.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.admins; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.fsoft.ihabot.ApplicationManager; 12 | import com.fsoft.ihabot.R; 13 | import com.fsoft.ihabot.Utils.F; 14 | import com.fsoft.ihabot.communucation.tg.TgAccount; 15 | import com.fsoft.ihabot.communucation.tg.TgAccountCore; 16 | import com.fsoft.ihabot.communucation.tg.User; 17 | import com.fsoft.ihabot.configuration.AdminList; 18 | import com.squareup.picasso.Picasso; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Locale; 22 | import java.util.Timer; 23 | import java.util.TimerTask; 24 | 25 | import jp.wasabeef.picasso.transformations.CropCircleTransformation; 26 | 27 | public class AddAdminUsersAdapter extends BaseAdapter { 28 | Activity activity = null; 29 | ApplicationManager applicationManager = null; 30 | ArrayList users = null; 31 | 32 | 33 | public AddAdminUsersAdapter(Activity activity) { 34 | this.activity = activity; 35 | applicationManager = ApplicationManager.getInstance(); 36 | users = applicationManager.getMessageHistory().getLastUsersList(); 37 | //Удалить из списка тех кто уже админ 38 | ArrayList admins = applicationManager.getAdminList().getUserList(); 39 | for (AdminList.AdminListItem admin:admins){ 40 | users.remove(admin.getUser()); 41 | } 42 | } 43 | 44 | @Override 45 | public void notifyDataSetChanged() { 46 | if(applicationManager == null) 47 | applicationManager = ApplicationManager.getInstance(); 48 | super.notifyDataSetChanged(); 49 | } 50 | 51 | @Override 52 | public void notifyDataSetInvalidated() { 53 | if(applicationManager == null) 54 | applicationManager = ApplicationManager.getInstance(); 55 | super.notifyDataSetInvalidated(); 56 | } 57 | 58 | @Override 59 | public int getCount() { 60 | return users.size(); 61 | } 62 | 63 | @Override 64 | public Object getItem(int i) { 65 | return users.get(i); 66 | } 67 | 68 | @Override 69 | public long getItemId(int i) { 70 | return i; 71 | } 72 | 73 | @Override 74 | public View getView(int position, View convertView, ViewGroup container) { 75 | if (convertView == null) { 76 | convertView = activity.getLayoutInflater().inflate(R.layout.dialog_add_admin_list_item, container, false); 77 | } 78 | 79 | User user = users.get(position); 80 | if(user == null) { //если юзер пустой, надо загрузить по новой, чтобы там не висели подвисшие данные с проглого элемента 81 | return activity.getLayoutInflater().inflate(R.layout.dialog_add_admin_list_item, container, false); 82 | } 83 | 84 | { //NAME 85 | TextView textView = convertView.findViewById(R.id.item_user_textView_name); 86 | if(textView != null) { 87 | textView.setText(user.getName()); 88 | } 89 | } 90 | { //USERNAME 91 | TextView textView = convertView.findViewById(R.id.item_user_textView_username); 92 | if(textView != null) { 93 | if(user.getUsername().isEmpty()) 94 | textView.setText(String.format(Locale.US, "%d", user.getId())); 95 | else 96 | textView.setText(String.format("@%s", user.getUsername())); 97 | } 98 | } 99 | 100 | TgAccount tgAccount = applicationManager.getCommunicator().getWorkingTgAccount(); 101 | if(tgAccount != null){//photo 102 | ImageView imageView = convertView.findViewById(R.id.item_user_imageview_avatar); 103 | if(imageView != null) { 104 | Picasso.get() 105 | .load(R.drawable.tg_account_placeholder) 106 | .transform(new CropCircleTransformation()) 107 | .into(imageView); 108 | // { 109 | // tgAccount.getUserPhotoUrl(new TgAccountCore.GetUserPhotoListener() { 110 | // @Override 111 | // public void gotPhoto(String url) { 112 | // imageView.post(new Runnable() { 113 | // @Override 114 | // public void run() { 115 | // Picasso.get() 116 | // .load(url) 117 | // .placeholder(R.drawable.tg_account_placeholder) 118 | // .transform(new CropCircleTransformation()) 119 | // .into(imageView); 120 | // } 121 | // }); 122 | // } 123 | // 124 | // @Override 125 | // public void noPhoto() { 126 | // imageView.post(new Runnable() { 127 | // @Override 128 | // public void run() { 129 | // Picasso.get() 130 | // .load(R.drawable.tg_account_placeholder) 131 | // .transform(new CropCircleTransformation()) 132 | // .into(imageView); 133 | // } 134 | // }); 135 | // 136 | // } 137 | // 138 | // @Override 139 | // public void error(Throwable error) { 140 | // imageView.post(new Runnable() { 141 | // @Override 142 | // public void run() { 143 | // Picasso.get() 144 | // .load(R.drawable.tg_account_placeholder) 145 | // .transform(new CropCircleTransformation()) 146 | // .into(imageView); 147 | // } 148 | // }); 149 | // 150 | // error.printStackTrace(); 151 | // } 152 | // }, user.getId()); 153 | // } 154 | } 155 | else { 156 | Log.d(F.TAG, "R.id.item_account_imageview_avatar is null =("); 157 | } 158 | } 159 | 160 | 161 | return convertView; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/admins/AdminsFragment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.admins; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.ListView; 15 | import android.widget.PopupMenu; 16 | 17 | import androidx.annotation.NonNull; 18 | import androidx.fragment.app.Fragment; 19 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 20 | 21 | import com.fsoft.ihabot.ApplicationManager; 22 | import com.fsoft.ihabot.R; 23 | import com.fsoft.ihabot.communucation.tg.TgAccount; 24 | import com.fsoft.ihabot.configuration.AdminList; 25 | import com.fsoft.ihabot.ui.accounts.AccountsAdapter; 26 | import com.google.android.material.snackbar.Snackbar; 27 | 28 | public class AdminsFragment extends Fragment { 29 | ListView listView; 30 | SwipeRefreshLayout swipeRefreshLayout; 31 | AdminsAdapter adminsAdapter; 32 | 33 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 34 | View root = inflater.inflate(R.layout.fragment_admins_layout, container, false); 35 | listView = root.findViewById(R.id.listview_admins_list); 36 | swipeRefreshLayout = root.findViewById(R.id.swiperefreshlayout_admins_list); 37 | adminsAdapter = new AdminsAdapter(getActivity()); 38 | listView.setAdapter(adminsAdapter); 39 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 40 | @Override 41 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 42 | try { 43 | final AdminList.AdminListItem adminListItem = ApplicationManager.getInstance().getAdminList().getUserList().get(i); 44 | if(adminListItem == null) 45 | return; 46 | PopupMenu popupMenu = new PopupMenu(getActivity(), view); 47 | popupMenu.inflate(R.menu.admin_popup_menu); 48 | popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 49 | @Override 50 | public boolean onMenuItemClick(MenuItem item) { 51 | if (item.getItemId() == R.id.action_copy_account_username) { 52 | if(getActivity() != null) { 53 | ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); 54 | String text = "@" + adminListItem.getUser().getUsername(); 55 | clipboardManager.setPrimaryClip(ClipData.newPlainText("username", text)); 56 | } 57 | } 58 | if (item.getItemId() == R.id.action_remove_rights) { 59 | try { 60 | for (AdminList.AdminListItem.Right right : AdminList.AdminListItem.getGenericRightsList()) { 61 | if (right != null) 62 | adminListItem.setAllowed(right, false); 63 | } 64 | ApplicationManager.getInstance().getAdminList().saveArrayToFile(); 65 | adminsAdapter.notifyDataSetInvalidated(); 66 | } 67 | catch (Exception e) { 68 | e.printStackTrace(); 69 | Snackbar.make(view, "Ошибка: "+e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show(); 70 | } 71 | } 72 | if (item.getItemId() == R.id.action_delete_admin) { 73 | new AlertDialog.Builder(getActivity()) 74 | .setTitle("Удаление аккаунта") 75 | .setMessage("Вы действительно хотите удалить администратора " + adminListItem.getUser() + "?") 76 | .setIcon(android.R.drawable.ic_dialog_alert) 77 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 78 | public void onClick(DialogInterface dialog, int whichButton) { 79 | try{ 80 | ApplicationManager.getInstance().getAdminList().rem(adminListItem); 81 | Snackbar.make(view, "Аккаунт "+adminListItem.getUser()+" успешно удалён", Snackbar.LENGTH_SHORT).show(); 82 | adminsAdapter.notifyDataSetInvalidated(); 83 | } 84 | catch (Exception e){ 85 | e.printStackTrace(); 86 | Snackbar.make(view, "Ошибка: "+e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show(); 87 | } 88 | }}) 89 | .setNegativeButton(android.R.string.no, null).show(); 90 | } 91 | return false; 92 | } 93 | }); 94 | popupMenu.show(); 95 | } 96 | catch (Exception e){ 97 | e.printStackTrace(); 98 | } 99 | } 100 | }); 101 | 102 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 103 | @Override 104 | public void onRefresh() { 105 | if (listView != null) 106 | listView.invalidateViews(); 107 | if (swipeRefreshLayout != null) 108 | swipeRefreshLayout.setRefreshing(false); 109 | } 110 | }); 111 | return root; 112 | } 113 | 114 | @Override 115 | public void onDestroyView() { 116 | super.onDestroyView(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/gallery/GalleryFragment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.gallery; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.fragment.app.Fragment; 11 | import androidx.lifecycle.ViewModelProvider; 12 | 13 | import com.fsoft.ihabot.databinding.FragmentGalleryBinding; 14 | 15 | public class GalleryFragment extends Fragment { 16 | 17 | private FragmentGalleryBinding binding; 18 | 19 | public View onCreateView(@NonNull LayoutInflater inflater, 20 | ViewGroup container, Bundle savedInstanceState) { 21 | GalleryViewModel galleryViewModel = 22 | new ViewModelProvider(this).get(GalleryViewModel.class); 23 | 24 | binding = FragmentGalleryBinding.inflate(inflater, container, false); 25 | View root = binding.getRoot(); 26 | 27 | final TextView textView = binding.textGallery; 28 | galleryViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); 29 | return root; 30 | } 31 | 32 | @Override 33 | public void onDestroyView() { 34 | super.onDestroyView(); 35 | binding = null; 36 | } 37 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/gallery/GalleryViewModel.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.gallery; 2 | 3 | import androidx.lifecycle.LiveData; 4 | import androidx.lifecycle.MutableLiveData; 5 | import androidx.lifecycle.ViewModel; 6 | 7 | public class GalleryViewModel extends ViewModel { 8 | 9 | private final MutableLiveData mText; 10 | 11 | public GalleryViewModel() { 12 | mText = new MutableLiveData<>(); 13 | mText.setValue("This is gallery fragment"); 14 | } 15 | 16 | public LiveData getText() { 17 | return mText; 18 | } 19 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/home/HomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.home; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.fragment.app.Fragment; 11 | import androidx.lifecycle.ViewModelProvider; 12 | 13 | import com.fsoft.ihabot.databinding.FragmentHomeBinding; 14 | 15 | public class HomeFragment extends Fragment { 16 | 17 | private FragmentHomeBinding binding; 18 | 19 | public View onCreateView(@NonNull LayoutInflater inflater, 20 | ViewGroup container, Bundle savedInstanceState) { 21 | HomeViewModel homeViewModel = 22 | new ViewModelProvider(this).get(HomeViewModel.class); 23 | 24 | binding = FragmentHomeBinding.inflate(inflater, container, false); 25 | View root = binding.getRoot(); 26 | 27 | final TextView textView = binding.textHome; 28 | homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); 29 | return root; 30 | } 31 | 32 | @Override 33 | public void onDestroyView() { 34 | super.onDestroyView(); 35 | binding = null; 36 | } 37 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/home/HomeViewModel.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.home; 2 | 3 | import androidx.lifecycle.LiveData; 4 | import androidx.lifecycle.MutableLiveData; 5 | import androidx.lifecycle.ViewModel; 6 | 7 | public class HomeViewModel extends ViewModel { 8 | 9 | private final MutableLiveData mText; 10 | 11 | public HomeViewModel() { 12 | mText = new MutableLiveData<>(); 13 | mText.setValue("This is home fragment"); 14 | } 15 | 16 | public LiveData getText() { 17 | return mText; 18 | } 19 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/slideshow/SlideshowFragment.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.slideshow; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.fragment.app.Fragment; 11 | import androidx.lifecycle.ViewModelProvider; 12 | 13 | import com.fsoft.ihabot.databinding.FragmentSlideshowBinding; 14 | 15 | public class SlideshowFragment extends Fragment { 16 | 17 | private FragmentSlideshowBinding binding; 18 | 19 | public View onCreateView(@NonNull LayoutInflater inflater, 20 | ViewGroup container, Bundle savedInstanceState) { 21 | SlideshowViewModel slideshowViewModel = 22 | new ViewModelProvider(this).get(SlideshowViewModel.class); 23 | 24 | binding = FragmentSlideshowBinding.inflate(inflater, container, false); 25 | View root = binding.getRoot(); 26 | 27 | final TextView textView = binding.textSlideshow; 28 | slideshowViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); 29 | return root; 30 | } 31 | 32 | @Override 33 | public void onDestroyView() { 34 | super.onDestroyView(); 35 | binding = null; 36 | } 37 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/java/com/fsoft/ihabot/ui/slideshow/SlideshowViewModel.java: -------------------------------------------------------------------------------- 1 | package com.fsoft.ihabot.ui.slideshow; 2 | 3 | import androidx.lifecycle.LiveData; 4 | import androidx.lifecycle.MutableLiveData; 5 | import androidx.lifecycle.ViewModel; 6 | 7 | public class SlideshowViewModel extends ViewModel { 8 | 9 | private final MutableLiveData mText; 10 | 11 | public SlideshowViewModel() { 12 | mText = new MutableLiveData<>(); 13 | mText.setValue("This is slideshow fragment"); 14 | } 15 | 16 | public LiveData getText() { 17 | return mText; 18 | } 19 | } -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/bot_noti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/drawable-v24/bot_noti.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/ic_add_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/ic_cross.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/ic_exclamation.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/ic_tg_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/drawable-v24/ic_tg_logo.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/iha_bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/drawable-v24/iha_bot.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable-v24/tg_account_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/drawable-v24/tg_account_placeholder.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/background_warning.xml: -------------------------------------------------------------------------------- 1 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_add_tg_account.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_gallery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_slideshow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_menu_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/activity_bot.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/app_bar_bot.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 33 | 34 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/content_bot.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/dialog_add_admin.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 27 | 34 | 41 | 42 | 43 | 48 | 49 | 59 | 60 | 67 | 74 | 75 | 85 | 86 | 93 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/dialog_add_admin_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 30 | 37 | 38 | 43 | 44 | 51 | 52 | 56 | 57 | 65 | 66 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/dialog_add_telegram_account.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 21 | 28 | 38 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 63 | 75 | 76 | 84 | 85 | 91 | 105 | 106 | 107 | 108 | 109 | 110 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_accounts_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 16 | 17 | 18 | 19 | 20 | 32 | 33 | 40 | 48 | 49 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_admins_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 35 | 36 | 43 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_admins_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 30 | 37 | 38 | 43 | 44 | 51 | 52 | 56 | 57 | 65 | 66 | 75 | 76 | 77 | 78 | 79 | 87 | 88 | 89 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/fragment_slideshow.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/layout/nav_header_bot.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 22 | 23 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/menu/account_popup_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | 16 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/menu/activity_main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/menu/admin_popup_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/menu/bot.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android-app/app/src/main/res/navigation/mobile_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 23 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/raw/answer_database.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drfailov/FP_iHA_bot/150903e58adbc05563959e507b6e17abfd2d90ae/Android-app/app/src/main/res/raw/answer_database.zip -------------------------------------------------------------------------------- /Android-app/app/src/main/res/raw/synonyme.txt: -------------------------------------------------------------------------------- 1 | сам,сама,самостоятельно 2 | хочешь,желаешь,будешь,want,хочеш,бажаєш,будеш 3 | рот,рыло,ебало,їбало,face 4 | ебал,трахал,жарил,fuck,їбав 5 | настроение,настрой,mood,муд,настрій 6 | могу,can,можу 7 | рад,счастлив,рада,счастлива,доволен,довольна,хэппи,happy,щасливий,задоволений 8 | учусь,обучаюсь,изучаю,учу,study,вивчаю,вчусь 9 | девушка,девка,баба,женщина,девочка,дівчина,дівка,жінка,дівчинка 10 | чего,чо,чё,чаво,чобля,чёбля,what,че 11 | про,о,об,за,about 12 | пошли,идём,идем,пішли,ходімо 13 | пошел,иди,ди,go,пошёл,пшол,сьеби,съеби,беги,пиздуй,йди,пішов,біжи 14 | плохо,ужасно,нехорошо,печально,bad,хреново,хуево,хуёво,херово,погано,жахливо 15 | сколько,скока,скільки 16 | хочу,хачу,требую,want,желаю,бажаю 17 | нужно,need,потрібно,треба 18 | тему,темку 19 | ты,ти,you 20 | любишь,любиш,love,лав,обожаешь,нравится,подобається 21 | айфон,огрызок,iphone,яфон,гейфон,ифон,яблофон 22 | ipad,айпэд,айпед,айпад,ипад,япад,гейпад 23 | ios,иос,айос,айоэс,аос,гейось 24 | эпл,гейпл,apple,эппл,аппле,апл,эйпл 25 | ipod,айпод,ипод,гейпод,япод 26 | понятно,ясно,яснопонятно,пон,ясн,зрозуміло 27 | привет,превед,прифет,прив,привіт 28 | пидр,гей,пидарас,пидорас,пидорасина,пидрила,пидор,пидрила,пидер,підор 29 | уебок,уебан,уеба,уебище,уёбок,уёбище,уёба,уйобок 30 | тварь,скотина,скот 31 | андроид,андро,ведроид,ведро,педроид,андроїд 32 | говно,гуано,говнище,дно,днище,dniwe,хрень,херня,хуйня,плохой,кал,калл,дерьмо,дерьмище,гівно, 33 | рулит,рулз,лучший,лучшая,топ,лучшее,супер,классный,классная,крутой,ахуенен,охуенен,охуенный,хороший,отличный,шикарен,божественен,кращий,гарний,найкращий 34 | шикарно,отлично,чудесно,круто,весело,хорошо,чудово 35 | знаю,шарю,понимаю,разбираюсь,осознаю 36 | знаешь,шаришь,понимаешь,разбираешься,сечёшь,панимэ,understand 37 | сказать,произнести,донести,написать,сообщить,рассказать,расказать,говорить,писать 38 | скажи,произнеси,донеси,напиши,сообщи,расскажи,раскажи,говори,пиши 39 | говоришь,произносишь,доносишь,пишешь,сообщаешь,рассказываешь,расказываешь,говоришь,пишешь 40 | нет,нит,не,no,ноуп,ноу,неа,ні 41 | самс,самсунг,самса,сосунг,samsung 42 | ладно,лан,окай,пускай 43 | гугл,google,гогле,гуголь 44 | сказал,написал,донёс,сообщил 45 | опять,снова,апять,знову 46 | группа,ihateapple,iha 47 | лохи,лошары 48 | нищеброды,нищеры,дебилы,идиоты,пидоры,пидарасы,пидрилы,дауны,школота,ідіоти 49 | нищеброд,нищер,лох,лошара,тупой,дебил,идиот,даун,чмо,ідіот 50 | ору,ор 51 | ржу,ржач,ржака,смешно 52 | человек,человечек,поц,штрих,жмых,пацан,пацанчик,man,мэн,людина 53 | просто,прост 54 | прости,сори,сорян,sorry,вибач 55 | купи,приобрети,достань,возьми,бери,візьми 56 | купить,приобрести,достать,взять,взяти 57 | кто,хто,who 58 | шлюха,блядь,шкура,проститутка,блять,сука,сучка 59 | найс,молодец,красава,огонь,красавчик 60 | фото,фотка,фотография,фотки,фоточка 61 | нахуй,нах,нахер,вжопу,впизду 62 | скинь,отправь,пришли,кинь,покажи 63 | ничего,ничо,нічого 64 | интересно,интересненько,тиресна,цікаво 65 | много,дофига,дохрена,дохуя,дохера,багато 66 | значит,означает,означає 67 | очень,оч,дуже 68 | дай,отдай 69 | зовут,называюь,зовется 70 | умный,знающий,прошаренный,розумний 71 | спать,отдыхать,відпочивати 72 | ага,да,еп,єп,yes 73 | зачем,зочем,нах,нахуя,нахера,нахрена,навіщо 74 | что,шо,what 75 | спасибо,благодарю,посеба,сэнкс,пасиб,tnx,дякую 76 | нельзя,низя,незя 77 | ночи,ночки,night,ночі 78 | стих,стишок,стихи,стихотворение,вірш,віршик 79 | норм,нормас,збс,нормально,хорошо,норма 80 | член,хуй,хер,пенис,dick,cock 81 | люблю,обожаю,love 82 | любить,обожать 83 | любит,обожает,loves 84 | умеешь,можешь 85 | поговорим,пообщаемся,поспілкуємось 86 | почему,пачиму,хули,why,чому 87 | нексус,никсус,никсас,никсес,nexus 88 | дела,делишки,справи 89 | ос,ось,система,операционка,os 90 | бот,ихабот,vkihabot,ihabot 91 | делать,делаешь 92 | миша,дима,витя,коля,вася,рома,макс,артем,леша,паша,стас,тоша,сережа,илья,серый,сережа,антон,олег,юра,ваня,андрей,леша,петя 93 | дина,оля,аня,вика,настя,катя,женя,алина,юля,поля,марина,маша,оксана,лена,ксюша,ира -------------------------------------------------------------------------------- /Android-app/app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /Android-app/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 21 | 22 | 26 | 27 |