├── .gitignore ├── .idea ├── checkstyle-idea.xml ├── gradle.xml └── runConfigurations.xml ├── .travis.yml ├── LICENSE ├── README.md ├── SkillSwapKeystore.jks ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── objectbox-models │ ├── default.json │ └── default.json.bak ├── proguard-rules.pro ├── release │ └── output.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── github │ │ └── mahadel │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── debug │ └── res │ │ └── values │ │ └── google_api.xml │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── fonts │ │ │ └── IRANSansMobile.ttf │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── mahadel │ │ │ └── demo │ │ │ ├── listener │ │ │ ├── CallbackResult.java │ │ │ └── SkillDetailCallbackResult.java │ │ │ ├── model │ │ │ ├── About.java │ │ │ ├── AuthenticationInfo.java │ │ │ ├── Category.java │ │ │ ├── ConnectionReceiveItem.java │ │ │ ├── ConnectionRequest.java │ │ │ ├── ConnectionSendItem.java │ │ │ ├── ResponseMessage.java │ │ │ ├── SearchResult.java │ │ │ ├── SkillsItem.java │ │ │ ├── User.java │ │ │ ├── UserInfo.java │ │ │ └── UserSkill.java │ │ │ ├── service │ │ │ ├── APIService.java │ │ │ └── MyFirebaseMessagingService.java │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── ConnectionRequestActivity.java │ │ │ │ ├── LauncherActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── SearchActivity.java │ │ │ │ └── SelectSkillActivity.java │ │ │ └── fragment │ │ │ │ ├── AboutFragment.java │ │ │ │ ├── AddSkillFragment.java │ │ │ │ ├── EditProfileFragment.java │ │ │ │ ├── ProfileFragment.java │ │ │ │ ├── SettingsFragment.java │ │ │ │ └── UserSkillDetailFragment.java │ │ │ └── util │ │ │ ├── AppUtil.java │ │ │ ├── Constant.java │ │ │ ├── DatabaseUtil.java │ │ │ ├── FirebaseEventLog.java │ │ │ ├── GridSpacingItemDecoration.java │ │ │ ├── LocaleManager.java │ │ │ ├── MyApplication.java │ │ │ └── RetrofitUtil.java │ └── res │ │ ├── anim │ │ ├── slide_down.xml │ │ └── slide_up.xml │ │ ├── drawable │ │ ├── ic_add_24px.xml │ │ ├── ic_arrow_downward_black_24dp.xml │ │ ├── ic_arrow_upward_black_24dp.xml │ │ ├── ic_book_black_24dp.xml │ │ ├── ic_close_black_24dp.xml │ │ ├── ic_create_black_24dp.xml │ │ ├── ic_delete_black_24dp.xml │ │ ├── ic_done_black_24dp.xml │ │ ├── ic_drawer_menu_24px.xml │ │ ├── ic_english.png │ │ ├── ic_exit_to_app_black_24dp.xml │ │ ├── ic_google_plus_32px.xml │ │ ├── ic_info_white_24dp.xml │ │ ├── ic_language_black_24dp.xml │ │ ├── ic_launcher.png │ │ ├── ic_list_black_24dp.xml │ │ ├── ic_mail_black_24dp.xml │ │ ├── ic_persian.png │ │ ├── ic_person_24dp.xml │ │ ├── ic_search_24px.xml │ │ ├── ic_settings_white_24dp.xml │ │ ├── ic_swap_vert_black_24dp.xml │ │ ├── ic_sync_black_24dp.xml │ │ └── image_border.xml │ │ ├── layout │ │ ├── activity_connection_request.xml │ │ ├── activity_launcher.xml │ │ ├── activity_main.xml │ │ ├── activity_search.xml │ │ ├── activity_select_skill.xml │ │ ├── content_main.xml │ │ ├── dialog_confirm.xml │ │ ├── dialog_edit_profile.xml │ │ ├── dialog_full_screen_loading.xml │ │ ├── dialog_skill_type.xml │ │ ├── error_layout.xml │ │ ├── fragment_about.xml │ │ ├── fragment_add_skill.xml │ │ ├── fragment_profile.xml │ │ ├── fragment_settings.xml │ │ ├── fragment_skill_detail.xml │ │ ├── item_category.xml │ │ ├── item_connection_received.xml │ │ ├── item_connection_sent.xml │ │ ├── item_search.xml │ │ ├── item_skill.xml │ │ └── item_user_skill.xml │ │ ├── menu │ │ ├── menu_appbar.xml │ │ └── menu_primary.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-ldpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-fa │ │ └── strings.xml │ │ ├── values-large │ │ └── dimens.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ids.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml │ ├── release │ └── res │ │ └── values │ │ └── google_api.xml │ └── test │ └── java │ └── com │ └── github │ └── mahadel │ └── demo │ └── ExampleUnitTest.java ├── assets └── welcome-img.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/androidstudio 3 | # Edit at https://www.gitignore.io/?templates=androidstudio 4 | 5 | ### AndroidStudio ### 6 | # Covers files to be ignored for android development using Android Studio. 7 | 8 | # Built application files 9 | *.apk 10 | *.ap_ 11 | 12 | # Files for the ART/Dalvik VM 13 | *.dex 14 | 15 | # Java class files 16 | *.class 17 | 18 | # Generated files 19 | bin/ 20 | gen/ 21 | out/ 22 | 23 | # Gradle files 24 | .gradle 25 | .gradle/ 26 | build/ 27 | 28 | # Signing files 29 | .signing/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Proguard folder generated by Eclipse 35 | proguard/ 36 | 37 | # Log Files 38 | *.log 39 | 40 | # Android Studio 41 | /*/build/ 42 | /*/local.properties 43 | /*/out 44 | /*/*/build 45 | /*/*/production 46 | captures/ 47 | .navigation/ 48 | *.ipr 49 | *~ 50 | *.swp 51 | 52 | # Android Patch 53 | gen-external-apklibs 54 | 55 | # External native build folder generated in Android Studio 2.2 and later 56 | .externalNativeBuild 57 | 58 | # NDK 59 | obj/ 60 | 61 | # IntelliJ IDEA 62 | *.iml 63 | *.iws 64 | /out/ 65 | 66 | # User-specific configurations 67 | .idea/caches/ 68 | .idea/libraries/ 69 | .idea/shelf/ 70 | .idea/workspace.xml 71 | .idea/tasks.xml 72 | .idea/.name 73 | .idea/compiler.xml 74 | .idea/copyright/profiles_settings.xml 75 | .idea/encodings.xml 76 | .idea/misc.xml 77 | .idea/modules.xml 78 | .idea/scopes/scope_settings.xml 79 | .idea/dictionaries 80 | .idea/vcs.xml 81 | .idea/jsLibraryMappings.xml 82 | .idea/datasources.xml 83 | .idea/dataSources.ids 84 | .idea/sqlDataSources.xml 85 | .idea/dynamic.xml 86 | .idea/uiDesigner.xml 87 | .idea/assetWizardSettings.xml 88 | .idea/markdown-exported-files.xml 89 | .idea/markdown-navigator.xml 90 | .idea/markdown-navigator/ 91 | 92 | # OS-specific files 93 | .DS_Store 94 | .DS_Store? 95 | ._* 96 | .Spotlight-V100 97 | .Trashes 98 | ehthumbs.db 99 | Thumbs.db 100 | 101 | # Legacy Eclipse project files 102 | .classpath 103 | .project 104 | .cproject 105 | .settings/ 106 | 107 | # Mobile Tools for Java (J2ME) 108 | .mtj.tmp/ 109 | 110 | # Package Files # 111 | *.war 112 | *.ear 113 | 114 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) 115 | hs_err_pid* 116 | 117 | ## Plugin-specific files: 118 | 119 | # mpeltonen/sbt-idea plugin 120 | .idea_modules/ 121 | 122 | # JIRA plugin 123 | atlassian-ide-plugin.xml 124 | 125 | # Mongo Explorer plugin 126 | .idea/mongoSettings.xml 127 | 128 | # Crashlytics plugin (for Android Studio and IntelliJ) 129 | com_crashlytics_export_strings.xml 130 | crashlytics.properties 131 | crashlytics-build.properties 132 | fabric.properties 133 | #google-services.json 134 | 135 | ### AndroidStudio Patch ### 136 | 137 | !/gradle/wrapper/gradle-wrapper.jar 138 | 139 | # End of https://www.gitignore.io/api/androidstudio 140 | -------------------------------------------------------------------------------- /.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - build-tools-28.0.3 8 | - android-28 9 | licenses: 10 | - '.+' 11 | before_install: 12 | - yes | sdkmanager "platforms;android-28" 13 | - yes | sdkmanager "build-tools;28.0.3" 14 | 15 | sudo: required 16 | install: true 17 | 18 | before_script: 19 | - chmod +x gradlew 20 | 21 | script: 22 | - ./gradlew assembleRelease --stacktrace 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android client for Mahadel project [Deprecated] 2 | 3 | [![Build Status](https://travis-ci.org/Mahadel/android.svg?branch=master)](https://travis-ci.org/Mahadel/android) 4 | 5 |

6 | 7 | 8 | **Download APK** 9 | [https://mahadel.ir/app/mahadel_ir.apk](https://mahadel.ir/app/mahadel_ir.apk) 10 | 11 | **Requirements** 12 | - Android Studio 3.4 Canary 8 13 | - JDK 8 14 | - Android SDK Build tools 28.0.3 15 | - Supports API Level +17 16 | - Support libraries with androidx v1.0.0 17 | 18 | **Highlights** 19 | - Use Material Design 2 20 | - Sign up with Google account 21 | - Support two language. English & Persian 22 | - Support multiple theme 23 | - Use locale Database 24 | 25 | **Libraries & Dependencies** 26 | - [Support libraries]: appcompat / recyclerview / constraintlayout 27 | - [Material Design 2]: MaterialCardView / MaterialButton / Bottom App Bars 28 | - [Play Services Auth]: use for sign up with Google account 29 | - [FastAdapter]: The bullet proof, fast and easy to use adapter library, which minimizes developing time to a fraction 30 | - [AndroidUtilCode]: is a powerful & easy to use library for Android. 31 | - [Calligraphy3]: Custom fonts in Android the easy way 32 | - [CardSlider]: Cardslider is a material design UI controller that allows you to swipe through cards with pictures and accompanying descriptions. 33 | - Square [Retrofit] / [Okhttp] / [Logging-Interceptor] 34 | - [Glide]: An image loading and caching library for Android focused on smooth scrolling 35 | - [CircularImageView] Create circular ImageView in Android in the simplest way possible. 36 | - Firebase Core / Crashlytics / Messaging 37 | - [ButterKnife]: Bind Android views and callbacks to fields and methods. 38 | 39 | 40 | # License 41 | 42 | Copyright 2018 Behrouz Khezry 43 | 44 | Licensed under the Apache License, Version 2.0 (the "License"); 45 | you may not use this file except in compliance with the License. 46 | You may obtain a copy of the License at 47 | 48 | http://www.apache.org/licenses/LICENSE-2.0 49 | 50 | Unless required by applicable law or agreed to in writing, software 51 | distributed under the License is distributed on an "AS IS" BASIS, 52 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 53 | See the License for the specific language governing permissions and 54 | limitations under the License. 55 | 56 | [Support libraries]: https://developer.android.com/jetpack/androidx/ 57 | [Material Design 2]: https://material.io/develop/android/ 58 | [Play Services Auth]: https://developers.google.com/android/guides/setup 59 | [FastAdapter]: https://github.com/mikepenz/FastAdapter 60 | [AndroidUtilCode]: https://github.com/Blankj/AndroidUtilCode 61 | [Calligraphy3]: https://github.com/InflationX/Calligraphy 62 | [CardSlider]: https://github.com/Ramotion/cardslider-android 63 | [Retrofit]: https://github.com/square/retrofit 64 | [Okhttp]: https://github.com/square/okhttp 65 | [Logging-Interceptor]: https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor 66 | [Glide]: https://github.com/bumptech/glide 67 | [CircularImageView]: https://github.com/lopspower/CircularImageView 68 | [ButterKnife]: https://github.com/JakeWharton/butterknife 69 | -------------------------------------------------------------------------------- /SkillSwapKeystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/SkillSwapKeystore.jks -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'io.fabric' 3 | apply plugin: 'io.objectbox' 4 | apply plugin: 'com.getkeepsafe.dexcount' 5 | apply plugin: 'com.jakewharton.butterknife' 6 | 7 | android { 8 | compileSdkVersion 28 9 | defaultConfig { 10 | applicationId "com.github.mahadel.demo" 11 | minSdkVersion 17 12 | targetSdkVersion 28 13 | versionCode 2 14 | versionName "2.0" 15 | vectorDrawables.useSupportLibrary = true 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | signingConfigs { 19 | release { 20 | storeFile file("../SkillSwapKeystore.jks") 21 | storePassword "mahadel" 22 | keyAlias "skillswap" 23 | keyPassword "mahadel" 24 | } 25 | } 26 | buildTypes { 27 | debug { 28 | signingConfig signingConfigs.release 29 | } 30 | release { 31 | signingConfig signingConfigs.release 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | compileOptions { 37 | sourceCompatibility JavaVersion.VERSION_1_8 38 | targetCompatibility JavaVersion.VERSION_1_8 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | implementation 'androidx.appcompat:appcompat:1.0.2' 45 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 46 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 47 | 48 | implementation 'com.google.android.material:material:1.0.0' 49 | 50 | implementation 'com.mikepenz:fastadapter:3.3.0-rc01' 51 | implementation 'com.mikepenz:fastadapter-commons:3.3.0-rc01' 52 | 53 | 54 | implementation 'com.google.android.gms:play-services-auth:16.0.1' 55 | 56 | implementation 'com.github.bkhezry:prefser:v2.2.1-rx2' 57 | 58 | implementation 'com.blankj:utilcode:1.22.5' 59 | 60 | implementation 'io.github.inflationx:viewpump:1.0.0' 61 | implementation 'io.github.inflationx:calligraphy3:3.0.0' 62 | 63 | implementation 'com.github.bkhezry:cardslider-android:1.0.0' 64 | 65 | //Retrofit 66 | implementation "com.squareup.retrofit2:retrofit:2.4.0" 67 | implementation "com.squareup.retrofit2:converter-gson:2.4.0" 68 | //use in development 69 | implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' 70 | 71 | implementation 'com.github.ybq:Android-SpinKit:1.1.0' 72 | 73 | 74 | implementation 'com.github.bumptech.glide:glide:4.8.0' 75 | implementation 'com.mikhaellopez:circularimageview:3.2.0' 76 | 77 | implementation 'com.google.firebase:firebase-core:16.0.6' 78 | implementation 'com.crashlytics.sdk.android:crashlytics:2.9.7' 79 | implementation 'com.google.firebase:firebase-messaging:17.3.4' 80 | 81 | implementation 'com.jakewharton:butterknife:9.0.0-SNAPSHOT' 82 | annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0-SNAPSHOT' 83 | 84 | testImplementation 'junit:junit:4.12' 85 | androidTestImplementation 'androidx.test:runner:1.1.1' 86 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 87 | } 88 | apply plugin: 'com.google.gms.google-services' 89 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "1071346960599", 4 | "firebase_url": "https://learning-1535713853686.firebaseio.com", 5 | "project_id": "learning-1535713853686", 6 | "storage_bucket": "learning-1535713853686.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:1071346960599:android:8236bef5cf74bd34", 12 | "android_client_info": { 13 | "package_name": "com.github.mahadel.demo" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "1071346960599-s73gvah8mgq3u33v4f0jes4btgrclro4.apps.googleusercontent.com", 19 | "client_type": 1, 20 | "android_info": { 21 | "package_name": "com.github.mahadel.demo", 22 | "certificate_hash": "618dec78adab6f3394580900ebe109552c070b07" 23 | } 24 | }, 25 | { 26 | "client_id": "1071346960599-5knq2udj6t34sbebu2jns3ut15hgkjs0.apps.googleusercontent.com", 27 | "client_type": 3 28 | } 29 | ], 30 | "api_key": [ 31 | { 32 | "current_key": "AIzaSyAzwmZIFJWXxCJCfxPLbVPwuVYyCzcXN_8" 33 | } 34 | ], 35 | "services": { 36 | "analytics_service": { 37 | "status": 1 38 | }, 39 | "appinvite_service": { 40 | "status": 2, 41 | "other_platform_oauth_client": [ 42 | { 43 | "client_id": "1071346960599-5knq2udj6t34sbebu2jns3ut15hgkjs0.apps.googleusercontent.com", 44 | "client_type": 3 45 | } 46 | ] 47 | }, 48 | "ads_service": { 49 | "status": 2 50 | } 51 | } 52 | } 53 | ], 54 | "configuration_version": "1" 55 | } -------------------------------------------------------------------------------- /app/objectbox-models/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", 3 | "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", 4 | "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", 5 | "entities": [ 6 | { 7 | "id": "1:6649451113731809914", 8 | "lastPropertyId": "7:4707217512055842288", 9 | "name": "SkillsItem", 10 | "properties": [ 11 | { 12 | "id": "1:1935411510617054693", 13 | "name": "faName" 14 | }, 15 | { 16 | "id": "3:4723080058977232572", 17 | "name": "enName" 18 | }, 19 | { 20 | "id": "4:5546226121616343253", 21 | "name": "id" 22 | }, 23 | { 24 | "id": "5:5579806958750036266", 25 | "name": "uuid" 26 | }, 27 | { 28 | "id": "6:4834869400859879728", 29 | "name": "categoryUuid" 30 | }, 31 | { 32 | "id": "7:4707217512055842288", 33 | "name": "categoryName" 34 | } 35 | ], 36 | "relations": [] 37 | }, 38 | { 39 | "id": "2:3767205738817430246", 40 | "lastPropertyId": "4:2121346716165033776", 41 | "name": "Category", 42 | "properties": [ 43 | { 44 | "id": "1:6503270244296702295", 45 | "name": "faName" 46 | }, 47 | { 48 | "id": "2:8155545121666908827", 49 | "name": "enName" 50 | }, 51 | { 52 | "id": "3:5011038135871749335", 53 | "name": "id" 54 | }, 55 | { 56 | "id": "4:2121346716165033776", 57 | "name": "uuid" 58 | } 59 | ], 60 | "relations": [ 61 | { 62 | "id": "1:8981328351072424287", 63 | "name": "skills" 64 | } 65 | ] 66 | }, 67 | { 68 | "id": "3:3817669123125379166", 69 | "lastPropertyId": "8:121697304359028089", 70 | "name": "UserSkill", 71 | "properties": [ 72 | { 73 | "id": "1:2115942951785124270", 74 | "name": "id" 75 | }, 76 | { 77 | "id": "2:5899342086986849200", 78 | "name": "userUuid" 79 | }, 80 | { 81 | "id": "3:2395552697686257328", 82 | "name": "updatedAt" 83 | }, 84 | { 85 | "id": "4:5504855514496621447", 86 | "name": "skillUuid" 87 | }, 88 | { 89 | "id": "5:1901101044516691525", 90 | "name": "description" 91 | }, 92 | { 93 | "id": "6:8510231762725423951", 94 | "name": "skillType" 95 | }, 96 | { 97 | "id": "7:400816236324596330", 98 | "name": "createdAt" 99 | }, 100 | { 101 | "id": "8:121697304359028089", 102 | "name": "uuid" 103 | } 104 | ], 105 | "relations": [] 106 | } 107 | ], 108 | "lastEntityId": "3:3817669123125379166", 109 | "lastIndexId": "0:0", 110 | "lastRelationId": "1:8981328351072424287", 111 | "lastSequenceId": "0:0", 112 | "modelVersion": 4, 113 | "modelVersionParserMinimum": 4, 114 | "retiredEntityUids": [], 115 | "retiredIndexUids": [], 116 | "retiredPropertyUids": [ 117 | 4699786210537493923 118 | ], 119 | "retiredRelationUids": [], 120 | "version": 1 121 | } -------------------------------------------------------------------------------- /app/objectbox-models/default.json.bak: -------------------------------------------------------------------------------- 1 | { 2 | "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", 3 | "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", 4 | "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", 5 | "entities": [ 6 | { 7 | "id": "1:6649451113731809914", 8 | "lastPropertyId": "7:4707217512055842288", 9 | "name": "SkillsItem", 10 | "properties": [ 11 | { 12 | "id": "1:1935411510617054693", 13 | "name": "faName" 14 | }, 15 | { 16 | "id": "3:4723080058977232572", 17 | "name": "enName" 18 | }, 19 | { 20 | "id": "4:5546226121616343253", 21 | "name": "id" 22 | }, 23 | { 24 | "id": "5:5579806958750036266", 25 | "name": "uuid" 26 | }, 27 | { 28 | "id": "6:4834869400859879728", 29 | "name": "categoryUuid" 30 | }, 31 | { 32 | "id": "7:4707217512055842288", 33 | "name": "categoryName" 34 | } 35 | ], 36 | "relations": [] 37 | }, 38 | { 39 | "id": "2:3767205738817430246", 40 | "lastPropertyId": "4:2121346716165033776", 41 | "name": "Category", 42 | "properties": [ 43 | { 44 | "id": "1:6503270244296702295", 45 | "name": "faName" 46 | }, 47 | { 48 | "id": "2:8155545121666908827", 49 | "name": "enName" 50 | }, 51 | { 52 | "id": "3:5011038135871749335", 53 | "name": "id" 54 | }, 55 | { 56 | "id": "4:2121346716165033776", 57 | "name": "uuid" 58 | } 59 | ], 60 | "relations": [ 61 | { 62 | "id": "1:8981328351072424287", 63 | "name": "skills" 64 | } 65 | ] 66 | }, 67 | { 68 | "id": "3:3817669123125379166", 69 | "lastPropertyId": "7:400816236324596330", 70 | "name": "UserSkill", 71 | "properties": [ 72 | { 73 | "id": "1:2115942951785124270", 74 | "name": "id" 75 | }, 76 | { 77 | "id": "2:5899342086986849200", 78 | "name": "userUuid" 79 | }, 80 | { 81 | "id": "3:2395552697686257328", 82 | "name": "updatedAt" 83 | }, 84 | { 85 | "id": "4:5504855514496621447", 86 | "name": "skillUuid" 87 | }, 88 | { 89 | "id": "5:1901101044516691525", 90 | "name": "description" 91 | }, 92 | { 93 | "id": "6:8510231762725423951", 94 | "name": "skillType" 95 | }, 96 | { 97 | "id": "7:400816236324596330", 98 | "name": "createdAt" 99 | } 100 | ], 101 | "relations": [] 102 | } 103 | ], 104 | "lastEntityId": "3:3817669123125379166", 105 | "lastIndexId": "0:0", 106 | "lastRelationId": "1:8981328351072424287", 107 | "lastSequenceId": "0:0", 108 | "modelVersion": 4, 109 | "modelVersionParserMinimum": 4, 110 | "retiredEntityUids": [], 111 | "retiredIndexUids": [], 112 | "retiredPropertyUids": [ 113 | 4699786210537493923 114 | ], 115 | "retiredRelationUids": [], 116 | "version": 1 117 | } -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":2,"versionName":"2.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/androidTest/java/com/github/mahadel/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.assertEquals; 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.getTargetContext(); 24 | 25 | assertEquals("com.github.bkhezry.learn2learn", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/debug/res/values/google_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 1071346960599-otiq3a2lc3rkfhttna29mb3d64rt4ala.apps.googleusercontent.com 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 34 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/assets/fonts/IRANSansMobile.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/assets/fonts/IRANSansMobile.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/listener/CallbackResult.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.listener; 2 | 3 | import com.github.mahadel.demo.model.UserSkill; 4 | import com.github.mahadel.demo.util.AppUtil; 5 | 6 | /** 7 | * Send result of UserSkill that add to the user. 8 | */ 9 | public interface CallbackResult { 10 | /** 11 | * @param userSkill {@link UserSkill} added user skill 12 | * @param skillType {@link com.github.mahadel.demo.util.AppUtil.SkillType} type of skill that added 13 | */ 14 | void sendResult(UserSkill userSkill, AppUtil.SkillType skillType); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/listener/SkillDetailCallbackResult.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.listener; 2 | 3 | import com.github.mahadel.demo.model.UserSkill; 4 | import com.github.mahadel.demo.util.AppUtil; 5 | 6 | /** 7 | * Handle update and remove functions of user skill 8 | */ 9 | public interface SkillDetailCallbackResult { 10 | 11 | /** 12 | * @param userSkill {@link UserSkill} updated user skill 13 | * @param skillType {@link com.github.mahadel.demo.util.AppUtil.SkillType} type of skill that updated 14 | */ 15 | void update(UserSkill userSkill, AppUtil.SkillType skillType); 16 | 17 | /** 18 | * @param userSkill {@link UserSkill} removed user skill 19 | * @param skillType {@link com.github.mahadel.demo.util.AppUtil.SkillType} type of skill that removed 20 | */ 21 | void remove(UserSkill userSkill, AppUtil.SkillType skillType); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/About.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * About class that handle value of about fragment. 7 | */ 8 | public class About { 9 | 10 | @SerializedName("sponsor_description") 11 | private String sponsorDescription; 12 | 13 | @SerializedName("app_url") 14 | private String appUrl; 15 | 16 | @SerializedName("app_version") 17 | private String appVersion; 18 | 19 | @SerializedName("updated_at") 20 | private String updatedAt; 21 | 22 | @SerializedName("created_at") 23 | private String createdAt; 24 | 25 | @SerializedName("id") 26 | private int id; 27 | 28 | @SerializedName("changelog_url") 29 | private String changelogUrl; 30 | 31 | @SerializedName("sponsor_name") 32 | private String sponsorName; 33 | 34 | @SerializedName("license_url") 35 | private String licenseUrl; 36 | 37 | @SerializedName("sponsor_url") 38 | private String sponsorUrl; 39 | 40 | public String getSponsorDescription() { 41 | return sponsorDescription; 42 | } 43 | 44 | public void setSponsorDescription(String sponsorDescription) { 45 | this.sponsorDescription = sponsorDescription; 46 | } 47 | 48 | public String getAppUrl() { 49 | return appUrl; 50 | } 51 | 52 | public void setAppUrl(String appUrl) { 53 | this.appUrl = appUrl; 54 | } 55 | 56 | public String getAppVersion() { 57 | return appVersion; 58 | } 59 | 60 | public void setAppVersion(String appVersion) { 61 | this.appVersion = appVersion; 62 | } 63 | 64 | public String getUpdatedAt() { 65 | return updatedAt; 66 | } 67 | 68 | public void setUpdatedAt(String updatedAt) { 69 | this.updatedAt = updatedAt; 70 | } 71 | 72 | public String getCreatedAt() { 73 | return createdAt; 74 | } 75 | 76 | public void setCreatedAt(String createdAt) { 77 | this.createdAt = createdAt; 78 | } 79 | 80 | public int getId() { 81 | return id; 82 | } 83 | 84 | public void setId(int id) { 85 | this.id = id; 86 | } 87 | 88 | public String getChangelogUrl() { 89 | return changelogUrl; 90 | } 91 | 92 | public void setChangelogUrl(String changelogUrl) { 93 | this.changelogUrl = changelogUrl; 94 | } 95 | 96 | public String getSponsorName() { 97 | return sponsorName; 98 | } 99 | 100 | public void setSponsorName(String sponsorName) { 101 | this.sponsorName = sponsorName; 102 | } 103 | 104 | public String getLicenseUrl() { 105 | return licenseUrl; 106 | } 107 | 108 | public void setLicenseUrl(String licenseUrl) { 109 | this.licenseUrl = licenseUrl; 110 | } 111 | 112 | public String getSponsorUrl() { 113 | return sponsorUrl; 114 | } 115 | 116 | public void setSponsorUrl(String sponsorUrl) { 117 | this.sponsorUrl = sponsorUrl; 118 | } 119 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/AuthenticationInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | 4 | import com.google.gson.annotations.SerializedName; 5 | 6 | /** 7 | * AuthenticationInfo class that handle values of user authentication 8 | */ 9 | public class AuthenticationInfo { 10 | 11 | @SerializedName("message") 12 | private String message; 13 | 14 | @SerializedName("type") 15 | private String type; 16 | 17 | @SerializedName("uuid") 18 | private String uuid; 19 | 20 | @SerializedName("token") 21 | private String token; 22 | 23 | private String email; 24 | 25 | @SerializedName("fill_info") 26 | private boolean fillInfo; 27 | 28 | private String firebaseId; 29 | 30 | public void setMessage(String message) { 31 | this.message = message; 32 | } 33 | 34 | public String getMessage() { 35 | return message; 36 | } 37 | 38 | public void setType(String type) { 39 | this.type = type; 40 | } 41 | 42 | public String getType() { 43 | return type; 44 | } 45 | 46 | public void setUuid(String uuid) { 47 | this.uuid = uuid; 48 | } 49 | 50 | public String getUuid() { 51 | return uuid; 52 | } 53 | 54 | public void setToken(String token) { 55 | this.token = token; 56 | } 57 | 58 | public String getToken() { 59 | return token; 60 | } 61 | 62 | public String getEmail() { 63 | return email; 64 | } 65 | 66 | public void setEmail(String email) { 67 | this.email = email; 68 | } 69 | 70 | public boolean getFillInfo() { 71 | return fillInfo; 72 | } 73 | 74 | public void setFillInfo(boolean fillInfo) { 75 | this.fillInfo = fillInfo; 76 | } 77 | 78 | public String getFirebaseId() { 79 | return firebaseId; 80 | } 81 | 82 | public void setFirebaseId(String firebaseId) { 83 | this.firebaseId = firebaseId; 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/Category.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import android.view.View; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.appcompat.widget.AppCompatTextView; 7 | 8 | import com.github.mahadel.demo.R; 9 | import com.github.mahadel.demo.util.AppUtil; 10 | import com.google.gson.annotations.SerializedName; 11 | import com.mikepenz.fastadapter.FastAdapter; 12 | import com.mikepenz.fastadapter.items.AbstractItem; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import io.objectbox.annotation.Entity; 19 | import io.objectbox.annotation.Id; 20 | 21 | /** 22 | * Category class that handle values of skill category. 23 | * Each item of it save in the local db. 24 | */ 25 | @Entity 26 | public class Category extends AbstractItem { 27 | @SerializedName("uuid") 28 | private String uuid; 29 | 30 | @SerializedName("fa_name") 31 | private String faName; 32 | 33 | @SerializedName("skills") 34 | private List skills; 35 | 36 | @SerializedName("en_name") 37 | private String enName; 38 | 39 | @Id 40 | private Long id; 41 | 42 | public String getUuid() { 43 | return uuid; 44 | } 45 | 46 | public void setUuid(String uuid) { 47 | this.uuid = uuid; 48 | } 49 | 50 | public String getFaName() { 51 | return faName; 52 | } 53 | 54 | public void setFaName(String faName) { 55 | this.faName = faName; 56 | } 57 | 58 | public List getSkills() { 59 | return skills; 60 | } 61 | 62 | public void setSkills(List skills) { 63 | this.skills = skills; 64 | } 65 | 66 | public String getEnName() { 67 | return enName; 68 | } 69 | 70 | public void setEnName(String enName) { 71 | this.enName = enName; 72 | } 73 | 74 | public Long getId() { 75 | return id; 76 | } 77 | 78 | public void setId(Long id) { 79 | this.id = id; 80 | } 81 | 82 | /** 83 | * Handle values of item in recycler view with FastAdapter library. 84 | */ 85 | @NonNull 86 | @Override 87 | public ViewHolder getViewHolder(@NonNull View view) { 88 | return new ViewHolder(view); 89 | } 90 | 91 | @Override 92 | public int getType() { 93 | return R.id.fastadapter_sample_item_id; 94 | } 95 | 96 | @Override 97 | public int getLayoutRes() { 98 | return R.layout.item_category; 99 | } 100 | 101 | /** 102 | * ViewHolder for handle {@link Category} item in the recycler view 103 | */ 104 | protected static class ViewHolder extends FastAdapter.ViewHolder { 105 | protected View view; 106 | @BindView(R.id.category) 107 | AppCompatTextView category; 108 | 109 | ViewHolder(View view) { 110 | super(view); 111 | ButterKnife.bind(this, view); 112 | this.view = view; 113 | } 114 | 115 | @Override 116 | public void bindView(@NonNull Category item, @NonNull List payloads) { 117 | if (AppUtil.isRTL(view.getContext())) { 118 | category.setText(item.getFaName()); 119 | } else { 120 | category.setText(item.getEnName()); 121 | } 122 | 123 | 124 | } 125 | 126 | @Override 127 | public void unbindView(@NonNull Category item) { 128 | category.setText(null); 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/ConnectionRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * ConnectionRequest class handle send and receive connections. 9 | */ 10 | public class ConnectionRequest { 11 | 12 | @SerializedName("connection_receive") 13 | private List connectionReceive; 14 | 15 | @SerializedName("connection_send") 16 | private List connectionSend; 17 | 18 | public void setConnectionReceive(List connectionReceive) { 19 | this.connectionReceive = connectionReceive; 20 | } 21 | 22 | public List getConnectionReceive() { 23 | return connectionReceive; 24 | } 25 | 26 | public void setConnectionSend(List connectionSend) { 27 | this.connectionSend = connectionSend; 28 | } 29 | 30 | public List getConnectionSend() { 31 | return connectionSend; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * ResponseMessage handle values of each response from server. 7 | */ 8 | public class ResponseMessage { 9 | 10 | @SerializedName("message") 11 | private String message; 12 | 13 | @SerializedName("type") 14 | private String type; 15 | 16 | public void setMessage(String message) { 17 | this.message = message; 18 | } 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | public void setType(String type) { 25 | this.type = type; 26 | } 27 | 28 | public String getType() { 29 | return type; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/SearchResult.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import android.view.View; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | import androidx.appcompat.widget.AppCompatTextView; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.github.mahadel.demo.R; 11 | import com.github.mahadel.demo.util.AppUtil; 12 | import com.github.mahadel.demo.util.DatabaseUtil; 13 | import com.github.mahadel.demo.util.MyApplication; 14 | import com.google.android.material.button.MaterialButton; 15 | import com.google.gson.annotations.SerializedName; 16 | import com.mikepenz.fastadapter.FastAdapter; 17 | import com.mikepenz.fastadapter.items.AbstractItem; 18 | import com.mikepenz.fastadapter.listeners.ClickEventHook; 19 | 20 | import java.util.List; 21 | 22 | import butterknife.BindView; 23 | import butterknife.ButterKnife; 24 | import io.objectbox.Box; 25 | import io.objectbox.BoxStore; 26 | 27 | /** 28 | * SearchResult handle values of search item that receive from server 29 | */ 30 | public class SearchResult extends AbstractItem { 31 | 32 | @SerializedName("learn_skill_uuid") 33 | private String learnSkillUuid; 34 | 35 | @SerializedName("teach_skill_uuid") 36 | private String teachSkillUuid; 37 | 38 | @SerializedName("learn_description") 39 | private String learnDescription; 40 | 41 | @SerializedName("teach_description") 42 | private String teachDescription; 43 | 44 | @SerializedName("user") 45 | private User user; 46 | 47 | public String getLearnSkillUuid() { 48 | return learnSkillUuid; 49 | } 50 | 51 | public void setLearnSkillUuid(String learnSkillUuid) { 52 | this.learnSkillUuid = learnSkillUuid; 53 | } 54 | 55 | public String getTeachSkillUuid() { 56 | return teachSkillUuid; 57 | } 58 | 59 | public void setTeachSkillUuid(String teachSkillUuid) { 60 | this.teachSkillUuid = teachSkillUuid; 61 | } 62 | 63 | public String getLearnDescription() { 64 | return learnDescription; 65 | } 66 | 67 | public void setLearnDescription(String learnDescription) { 68 | this.learnDescription = learnDescription; 69 | } 70 | 71 | public String getTeachDescription() { 72 | return teachDescription; 73 | } 74 | 75 | public void setTeachDescription(String teachDescription) { 76 | this.teachDescription = teachDescription; 77 | } 78 | 79 | public User getUser() { 80 | return user; 81 | } 82 | 83 | public void setUser(User user) { 84 | this.user = user; 85 | } 86 | 87 | @NonNull 88 | @Override 89 | public ViewHolder getViewHolder(@NonNull View view) { 90 | return new ViewHolder(view); 91 | } 92 | 93 | @Override 94 | public int getType() { 95 | return R.id.fastadapter_sample_item_id; 96 | } 97 | 98 | @Override 99 | public int getLayoutRes() { 100 | return R.layout.item_search; 101 | } 102 | 103 | public interface RequestClickListener { 104 | void requestEmail(SearchResult item); 105 | } 106 | 107 | /** 108 | * ViewHolder for handle {@link SearchResult} item in the recycler view 109 | */ 110 | protected static class ViewHolder extends FastAdapter.ViewHolder { 111 | protected View view; 112 | @BindView(R.id.name_text_view) 113 | AppCompatTextView nameTextView; 114 | @BindView(R.id.gender_text_view) 115 | AppCompatTextView genderTextView; 116 | @BindView(R.id.teach_skill_name) 117 | AppCompatTextView teachSkillName; 118 | @BindView(R.id.learn_skill_name) 119 | AppCompatTextView learnSkillName; 120 | @BindView(R.id.teach_description_text_view) 121 | AppCompatTextView teachDescriptionTextView; 122 | @BindView(R.id.learn_description_text_view) 123 | AppCompatTextView learnDescriptionTextView; 124 | @BindView(R.id.request_email_btn) 125 | MaterialButton requestEmailBtn; 126 | Box skillsItemBox; 127 | 128 | ViewHolder(View view) { 129 | super(view); 130 | ButterKnife.bind(this, view); 131 | this.view = view; 132 | BoxStore boxStore = MyApplication.getBoxStore(); 133 | skillsItemBox = boxStore.boxFor(SkillsItem.class); 134 | } 135 | 136 | @Override 137 | public void bindView(@NonNull SearchResult item, @NonNull List payloads) { 138 | nameTextView.setText(String.format("%s %s", item.getUser().getFirstName(), item.getUser().getLastName())); 139 | genderTextView.setText(item.getUser().getGender() == 1 ? R.string.male_label : R.string.female_label); 140 | teachDescriptionTextView.setText(item.getTeachDescription()); 141 | learnDescriptionTextView.setText(item.getLearnDescription()); 142 | if (AppUtil.isRTL(view.getContext())) { 143 | teachSkillName.setText(getSkill(item.getTeachSkillUuid()).getFaName()); 144 | learnSkillName.setText(getSkill(item.getLearnSkillUuid()).getFaName()); 145 | } else { 146 | teachSkillName.setText(getSkill(item.getTeachSkillUuid()).getEnName()); 147 | learnSkillName.setText(getSkill(item.getLearnSkillUuid()).getEnName()); 148 | } 149 | } 150 | 151 | @Override 152 | public void unbindView(@NonNull SearchResult item) { 153 | nameTextView.setText(null); 154 | } 155 | 156 | private SkillsItem getSkill(String skillUuid) { 157 | return DatabaseUtil.getSkillItemQueryWithUUID(skillsItemBox, skillUuid).findFirst(); 158 | } 159 | } 160 | 161 | /** 162 | * RequestButtonClickEvent handle click on request button in search result item. 163 | */ 164 | public static class RequestButtonClickEvent extends ClickEventHook { 165 | private RequestClickListener listener; 166 | 167 | public RequestButtonClickEvent(RequestClickListener doRequestClickListener) { 168 | this.listener = doRequestClickListener; 169 | } 170 | 171 | @Override 172 | public void onClick(@NonNull View view, int position, @NonNull FastAdapter fastAdapter, @NonNull SearchResult item) { 173 | if (listener != null) { 174 | listener.requestEmail(item); 175 | } 176 | } 177 | 178 | @Nullable 179 | @Override 180 | public View onBind(RecyclerView.ViewHolder viewHolder) { 181 | if (viewHolder instanceof SearchResult.ViewHolder) { 182 | return ((ViewHolder) viewHolder).requestEmailBtn; 183 | } 184 | return null; 185 | } 186 | } 187 | 188 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/SkillsItem.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | import android.view.View; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.appcompat.widget.AppCompatTextView; 9 | 10 | import com.github.mahadel.demo.R; 11 | import com.github.mahadel.demo.util.AppUtil; 12 | import com.google.gson.annotations.SerializedName; 13 | import com.mikepenz.fastadapter.FastAdapter; 14 | import com.mikepenz.fastadapter.items.AbstractItem; 15 | 16 | import java.util.List; 17 | 18 | import butterknife.BindView; 19 | import butterknife.ButterKnife; 20 | import io.objectbox.annotation.Entity; 21 | import io.objectbox.annotation.Id; 22 | 23 | /** 24 | * SkillsItem handle values of Skills that received from server. 25 | * Each item of it saved in local db. 26 | */ 27 | @Entity 28 | public class SkillsItem extends AbstractItem implements Parcelable { 29 | 30 | @SerializedName("fa_name") 31 | private String faName; 32 | 33 | @SerializedName("category_uuid") 34 | private String categoryUuid; 35 | 36 | @SerializedName("en_name") 37 | private String enName; 38 | 39 | @Id 40 | @SerializedName("id") 41 | private Long id; 42 | 43 | @SerializedName("uuid") 44 | private String uuid; 45 | 46 | private String categoryName; 47 | 48 | public void setFaName(String faName) { 49 | this.faName = faName; 50 | } 51 | 52 | public String getFaName() { 53 | return faName; 54 | } 55 | 56 | public String getCategoryUuid() { 57 | return categoryUuid; 58 | } 59 | 60 | public void setCategoryUuid(String categoryUuid) { 61 | this.categoryUuid = categoryUuid; 62 | } 63 | 64 | public void setEnName(String enName) { 65 | this.enName = enName; 66 | } 67 | 68 | public String getEnName() { 69 | return enName; 70 | } 71 | 72 | public Long getId() { 73 | return id; 74 | } 75 | 76 | public void setId(Long id) { 77 | this.id = id; 78 | } 79 | 80 | public void setUuid(String uuid) { 81 | this.uuid = uuid; 82 | } 83 | 84 | public String getUuid() { 85 | return uuid; 86 | } 87 | 88 | public String getCategoryName() { 89 | return categoryName; 90 | } 91 | 92 | public void setCategoryName(String categoryName) { 93 | this.categoryName = categoryName; 94 | } 95 | 96 | @NonNull 97 | @Override 98 | public ViewHolder getViewHolder(@NonNull View view) { 99 | return new ViewHolder(view); 100 | } 101 | 102 | @Override 103 | public int getType() { 104 | return R.id.fastadapter_sample_item_id; 105 | } 106 | 107 | @Override 108 | public int getLayoutRes() { 109 | return R.layout.item_skill; 110 | } 111 | 112 | /** 113 | * ViewHolder for handle {@link SkillsItem} item in the recycler view 114 | */ 115 | protected static class ViewHolder extends FastAdapter.ViewHolder { 116 | protected View view; 117 | @BindView(R.id.skill) 118 | AppCompatTextView skill; 119 | 120 | ViewHolder(View view) { 121 | super(view); 122 | ButterKnife.bind(this, view); 123 | this.view = view; 124 | } 125 | 126 | @Override 127 | public void bindView(@NonNull SkillsItem item, @NonNull List payloads) { 128 | if (AppUtil.isRTL(view.getContext())) { 129 | skill.setText(item.getFaName()); 130 | } else { 131 | skill.setText(item.getEnName()); 132 | } 133 | 134 | 135 | } 136 | 137 | @Override 138 | public void unbindView(@NonNull SkillsItem item) { 139 | skill.setText(null); 140 | } 141 | } 142 | 143 | 144 | public static final Creator CREATOR = new Creator() { 145 | @Override 146 | public SkillsItem createFromParcel(Parcel source) { 147 | return new SkillsItem(source); 148 | } 149 | 150 | @Override 151 | public SkillsItem[] newArray(int size) { 152 | return new SkillsItem[size]; 153 | } 154 | }; 155 | 156 | public SkillsItem() { 157 | } 158 | 159 | protected SkillsItem(Parcel in) { 160 | this.faName = in.readString(); 161 | this.categoryUuid = in.readString(); 162 | this.enName = in.readString(); 163 | this.id = (Long) in.readValue(Long.class.getClassLoader()); 164 | this.uuid = in.readString(); 165 | this.categoryName = in.readString(); 166 | } 167 | 168 | @Override 169 | public int describeContents() { 170 | return 0; 171 | } 172 | 173 | @Override 174 | public void writeToParcel(Parcel dest, int flags) { 175 | dest.writeString(this.faName); 176 | dest.writeString(this.categoryUuid); 177 | dest.writeString(this.enName); 178 | dest.writeValue(this.id); 179 | dest.writeString(this.uuid); 180 | dest.writeString(this.categoryName); 181 | } 182 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/User.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * User extend {@link UserInfo} class with addition uuid field 7 | */ 8 | public class User extends UserInfo { 9 | 10 | @SerializedName("uuid") 11 | private String uuid; 12 | 13 | public String getUuid() { 14 | return uuid; 15 | } 16 | 17 | public void setUuid(String uuid) { 18 | this.uuid = uuid; 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * UserInfo handle values of user information. 7 | */ 8 | public class UserInfo { 9 | 10 | @SerializedName("gender") 11 | private int gender; 12 | 13 | @SerializedName("last_name") 14 | private String lastName; 15 | 16 | @SerializedName("first_name") 17 | private String firstName; 18 | 19 | public int getGender() { 20 | return gender; 21 | } 22 | 23 | public void setGender(int gender) { 24 | this.gender = gender; 25 | } 26 | 27 | public String getLastName() { 28 | return lastName; 29 | } 30 | 31 | public void setLastName(String lastName) { 32 | this.lastName = lastName; 33 | } 34 | 35 | public String getFirstName() { 36 | return firstName; 37 | } 38 | 39 | public void setFirstName(String firstName) { 40 | this.firstName = firstName; 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/model/UserSkill.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.model; 2 | 3 | import android.view.View; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.appcompat.widget.AppCompatTextView; 7 | 8 | import com.github.mahadel.demo.R; 9 | import com.github.mahadel.demo.util.AppUtil; 10 | import com.github.mahadel.demo.util.MyApplication; 11 | import com.google.gson.annotations.SerializedName; 12 | import com.mikepenz.fastadapter.FastAdapter; 13 | import com.mikepenz.fastadapter.items.AbstractItem; 14 | 15 | import java.util.List; 16 | 17 | import butterknife.BindView; 18 | import butterknife.ButterKnife; 19 | import io.objectbox.Box; 20 | import io.objectbox.BoxStore; 21 | import io.objectbox.annotation.Entity; 22 | import io.objectbox.annotation.Id; 23 | 24 | /** 25 | * UserSkill handle values of user skill of current user. 26 | * Each item of it saved in local db. 27 | */ 28 | @Entity 29 | public class UserSkill extends AbstractItem { 30 | 31 | @Id 32 | private Long id; 33 | 34 | @SerializedName("uuid") 35 | private String uuid; 36 | 37 | @SerializedName("user_uuid") 38 | private String userUuid; 39 | 40 | @SerializedName("updated_at") 41 | private String updatedAt; 42 | 43 | @SerializedName("skill_uuid") 44 | private String skillUuid; 45 | 46 | @SerializedName("description") 47 | private String description; 48 | 49 | @SerializedName("skill_type") 50 | private int skillType; 51 | 52 | @SerializedName("created_at") 53 | private String createdAt; 54 | 55 | public String getUuid() { 56 | return uuid; 57 | } 58 | 59 | public void setUuid(String uuid) { 60 | this.uuid = uuid; 61 | } 62 | 63 | public Long getId() { 64 | return id; 65 | } 66 | 67 | public void setId(Long id) { 68 | this.id = id; 69 | } 70 | 71 | public String getUserUuid() { 72 | return userUuid; 73 | } 74 | 75 | public void setUserUuid(String userUuid) { 76 | this.userUuid = userUuid; 77 | } 78 | 79 | public String getUpdatedAt() { 80 | return updatedAt; 81 | } 82 | 83 | public void setUpdatedAt(String updatedAt) { 84 | this.updatedAt = updatedAt; 85 | } 86 | 87 | public String getSkillUuid() { 88 | return skillUuid; 89 | } 90 | 91 | public void setSkillUuid(String skillUuid) { 92 | this.skillUuid = skillUuid; 93 | } 94 | 95 | public String getDescription() { 96 | return description; 97 | } 98 | 99 | public void setDescription(String description) { 100 | this.description = description; 101 | } 102 | 103 | public int getSkillType() { 104 | return skillType; 105 | } 106 | 107 | public void setSkillType(int skillType) { 108 | this.skillType = skillType; 109 | } 110 | 111 | public String getCreatedAt() { 112 | return createdAt; 113 | } 114 | 115 | public void setCreatedAt(String createdAt) { 116 | this.createdAt = createdAt; 117 | } 118 | 119 | @NonNull 120 | @Override 121 | public ViewHolder getViewHolder(@NonNull View view) { 122 | return new ViewHolder(view); 123 | } 124 | 125 | @Override 126 | public int getType() { 127 | return R.id.fastadapter_sample_item_id; 128 | } 129 | 130 | @Override 131 | public int getLayoutRes() { 132 | return R.layout.item_user_skill; 133 | } 134 | 135 | /** 136 | * ViewHolder for handle {@link UserSkill} item in the recycler view 137 | */ 138 | protected static class ViewHolder extends FastAdapter.ViewHolder { 139 | protected View view; 140 | @BindView(R.id.skill) 141 | AppCompatTextView skill; 142 | Box skillsItemBox; 143 | 144 | ViewHolder(View view) { 145 | super(view); 146 | ButterKnife.bind(this, view); 147 | this.view = view; 148 | BoxStore boxStore = MyApplication.getBoxStore(); 149 | skillsItemBox = boxStore.boxFor(SkillsItem.class); 150 | } 151 | 152 | @Override 153 | public void bindView(@NonNull UserSkill item, @NonNull List payloads) { 154 | SkillsItem skillsItem = AppUtil.getSkill(skillsItemBox, item.skillUuid); 155 | if (AppUtil.isRTL(view.getContext())) { 156 | AppUtil.rotateYView(view, 180); 157 | skill.setText(skillsItem.getFaName()); 158 | } else { 159 | skill.setText(skillsItem.getEnName()); 160 | } 161 | 162 | 163 | } 164 | 165 | @Override 166 | public void unbindView(@NonNull UserSkill item) { 167 | skill.setText(null); 168 | } 169 | } 170 | 171 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/service/APIService.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.service; 2 | 3 | import com.github.mahadel.demo.model.About; 4 | import com.github.mahadel.demo.model.AuthenticationInfo; 5 | import com.github.mahadel.demo.model.Category; 6 | import com.github.mahadel.demo.model.ConnectionReceiveItem; 7 | import com.github.mahadel.demo.model.ConnectionRequest; 8 | import com.github.mahadel.demo.model.ResponseMessage; 9 | import com.github.mahadel.demo.model.SearchResult; 10 | import com.github.mahadel.demo.model.UserInfo; 11 | import com.github.mahadel.demo.model.UserSkill; 12 | 13 | import java.util.List; 14 | 15 | import retrofit2.Call; 16 | import retrofit2.http.DELETE; 17 | import retrofit2.http.Field; 18 | import retrofit2.http.FormUrlEncoded; 19 | import retrofit2.http.GET; 20 | import retrofit2.http.POST; 21 | import retrofit2.http.PUT; 22 | import retrofit2.http.Path; 23 | 24 | public interface APIService { 25 | 26 | /** 27 | * @param token String token of google login 28 | * @return instance of {@link AuthenticationInfo} from server 29 | */ 30 | @POST("token") 31 | @FormUrlEncoded 32 | Call storeUser( 33 | @Field("token") String token); 34 | 35 | /** 36 | * @param uuid String uuid of user 37 | * @param firstName String first name 38 | * @param lastName String last name 39 | * @param gender Int gender 40 | * @return instance of {@link ResponseMessage} from server 41 | */ 42 | @PUT("user/{uuid}") 43 | @FormUrlEncoded 44 | Call updateUser( 45 | @Path("uuid") String uuid, 46 | @Field("first_name") String firstName, 47 | @Field("last_name") String lastName, 48 | @Field("gender") int gender); 49 | 50 | 51 | /** 52 | * @return List of {@link Category} from server 53 | */ 54 | @GET("category") 55 | Call> getCategories(); 56 | 57 | /** 58 | * @param uuid String uuid of user 59 | * @return List of {@link UserSkill} of user from server 60 | */ 61 | @GET("user/{uuid}/skill") 62 | Call> getUserSkills(@Path("uuid") String uuid); 63 | 64 | /** 65 | * @param uuid String uuid of user 66 | * @param skillUUID String uuid of skill 67 | * @param description String description of user skill 68 | * @param skillType Int skill type of user skill 69 | * @return Instance of {@link UserSkill} that saved in server 70 | */ 71 | @POST("user/{uuid}/skill") 72 | @FormUrlEncoded 73 | Call addUserSkill(@Path("uuid") String uuid, 74 | @Field("skill_uuid") String skillUUID, 75 | @Field("description") String description, 76 | @Field("skill_type") int skillType); 77 | 78 | /** 79 | * @param uuid String uuid of user 80 | * @param userSkillUUID String uuid of userSkill 81 | * @param description String description of userSkill 82 | * @return Instance of {@link UserSkill} that saved in server 83 | */ 84 | @PUT("user/{uuid}/skill") 85 | @FormUrlEncoded 86 | Call editUserSkill(@Path("uuid") String uuid, 87 | @Field("uuid") String userSkillUUID, 88 | @Field("description") String description); 89 | 90 | /** 91 | * @param uuid String uuid of user 92 | * @param userSkillUUID String uuid of userSkill 93 | * @return Instance of {@link ResponseMessage} response from server 94 | */ 95 | @DELETE("user/{uuid}/skill/{user_skill_uuid}") 96 | Call deleteUserSkill(@Path("uuid") String uuid, 97 | @Path("user_skill_uuid") String userSkillUUID); 98 | 99 | /** 100 | * @param uuid String uuid of user 101 | * @return Instance of {@link UserInfo} 102 | */ 103 | @GET("user/{uuid}/info") 104 | Call getUserInfo(@Path("uuid") String uuid); 105 | 106 | /** 107 | * @param uuid String uuid of user 108 | * @return List of {@link SearchResult} that match with search 109 | */ 110 | @GET("search/{uuid}") 111 | Call> search(@Path("uuid") String uuid); 112 | 113 | /** 114 | * @param userUUIDFrom String uuid of current user 115 | * @param userUUIDTo String uuid of receiver user 116 | * @param learnSkillUUIDFrom String uuid of skill want to learn 117 | * @param teachSkillUUIDFrom String uuid of skill 118 | * @param description String description of request connection 119 | * @return Instance of {@link ResponseMessage} response from server 120 | */ 121 | @POST("user/{uuid}/connection") 122 | @FormUrlEncoded 123 | Call requestConnection(@Path("uuid") String userUUIDFrom, 124 | @Field("user_uuid_to") String userUUIDTo, 125 | @Field("learn_skill_uuid_from") String learnSkillUUIDFrom, 126 | @Field("teach_skill_uuid_from") String teachSkillUUIDFrom, 127 | @Field("description") String description); 128 | 129 | /** 130 | * @param uuid String uuid of user 131 | * @return Instance of {@link ConnectionRequest} that hold list of send & receive requests. 132 | */ 133 | @GET("user/{uuid}/connection") 134 | Call getUserConnectionRequest(@Path("uuid") String uuid); 135 | 136 | /** 137 | * @param uuid String uuid of user 138 | * @param connectionUUID String uuid of connection request 139 | * @return Instance {@link ResponseMessage} response from server 140 | */ 141 | @DELETE("user/{uuid}/connection/{connection_uuid}") 142 | Call deleteConnectionRequest(@Path("uuid") String uuid, 143 | @Path("connection_uuid") String connectionUUID); 144 | 145 | /** 146 | * @param uuid String uuid of user 147 | * @param connectionUUID String uuid of connection request 148 | * @param isAccept Int status of connection 149 | * @return Instance of {@link ConnectionReceiveItem} 150 | */ 151 | @PUT("user/{uuid}/connection/{connection_uuid}") 152 | @FormUrlEncoded 153 | Call editConnection(@Path("uuid") String uuid, 154 | @Path("connection_uuid") String connectionUUID, 155 | @Field("is_accept") int isAccept); 156 | 157 | /** 158 | * @param uuid String uuid of user 159 | * @return Instance of {@link ResponseMessage} response from server 160 | */ 161 | @DELETE("user/{uuid}") 162 | Call deleteUserAccount(@Path("uuid") String uuid); 163 | 164 | /** 165 | * @return Instance of {@link About} from server 166 | */ 167 | @GET("about") 168 | Call getAbout(); 169 | 170 | /** 171 | * @param uuid String uuid of user 172 | * @param firebaseId String firebase id token 173 | * @return Instance of {@link ResponseMessage} response from server 174 | */ 175 | @PUT("user/{uuid}/firebase") 176 | @FormUrlEncoded 177 | Call setFirebaseId(@Path("uuid") String uuid, 178 | @Field("firebase_id") String firebaseId); 179 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/service/MyFirebaseMessagingService.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.service; 2 | 3 | import android.app.NotificationChannel; 4 | import android.app.NotificationManager; 5 | import android.app.PendingIntent; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.media.RingtoneManager; 9 | import android.net.Uri; 10 | import android.os.Build; 11 | import android.util.Log; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.core.app.NotificationCompat; 15 | 16 | import com.github.mahadel.demo.R; 17 | import com.github.mahadel.demo.model.AuthenticationInfo; 18 | import com.github.mahadel.demo.model.ResponseMessage; 19 | import com.github.mahadel.demo.ui.activity.MainActivity; 20 | import com.github.mahadel.demo.util.Constant; 21 | import com.github.mahadel.demo.util.RetrofitUtil; 22 | import com.github.pwittchen.prefser.library.rx2.Prefser; 23 | import com.google.firebase.messaging.FirebaseMessagingService; 24 | import com.google.firebase.messaging.RemoteMessage; 25 | 26 | import retrofit2.Call; 27 | import retrofit2.Callback; 28 | import retrofit2.Response; 29 | 30 | public class MyFirebaseMessagingService extends FirebaseMessagingService { 31 | 32 | /** 33 | * Called when message is received. 34 | * 35 | * @param remoteMessage Object representing the message received from Firebase Cloud Messaging. 36 | */ 37 | @Override 38 | public void onMessageReceived(RemoteMessage remoteMessage) { 39 | if (remoteMessage.getNotification() != null) { 40 | sendNotification(remoteMessage.getNotification().getBody(), remoteMessage.getNotification().getTitle()); 41 | } 42 | } 43 | 44 | 45 | /** 46 | * Called if InstanceID token is updated. This may occur if the security of 47 | * the previous token had been compromised. Note that this is called when the InstanceID token 48 | * is initially generated so this is where you would retrieve the token. 49 | */ 50 | @Override 51 | public void onNewToken(String token) { 52 | // If you want to send messages to this application instance or 53 | // manage this apps subscriptions on the server side, send the 54 | // Instance ID token to your app server. 55 | sendRegistrationToServer(token); 56 | } 57 | // [END on_new_token] 58 | 59 | /** 60 | * Persist token to third-party servers. 61 | *

62 | * Modify this method to associate the user's FCM InstanceID token with any server-side account 63 | * maintained by your application. 64 | * 65 | * @param token The new token. 66 | */ 67 | private void sendRegistrationToServer(String token) { 68 | Prefser prefser = new Prefser(this); 69 | AuthenticationInfo info = prefser.get(Constant.TOKEN, AuthenticationInfo.class, null); 70 | if (info != null) { 71 | APIService apiService = RetrofitUtil.getRetrofit(info.getToken()).create(APIService.class); 72 | Call call = apiService.setFirebaseId(info.getUuid(), token); 73 | call.enqueue(new Callback() { 74 | @Override 75 | public void onResponse(@NonNull Call call, @NonNull Response response) { 76 | if (response.isSuccessful()) { 77 | Log.d("submitToken", "success"); 78 | } 79 | } 80 | 81 | @Override 82 | public void onFailure(@NonNull Call call, @NonNull Throwable t) { 83 | Log.d("submitToken", "failed"); 84 | t.printStackTrace(); 85 | } 86 | }); 87 | } 88 | } 89 | 90 | /** 91 | * Create and show a simple notification containing the received FCM message. 92 | * 93 | * @param messageBody FCM message body received. 94 | * @param title FCM message title received. 95 | */ 96 | private void sendNotification(String messageBody, String title) { 97 | Intent intent = new Intent(this, MainActivity.class); 98 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 99 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, 100 | PendingIntent.FLAG_ONE_SHOT); 101 | 102 | String channelId = getString(R.string.default_notification_channel_id); 103 | Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 104 | NotificationCompat.Builder notificationBuilder = 105 | new NotificationCompat.Builder(this, channelId) 106 | .setSmallIcon(R.drawable.ic_persian) 107 | .setContentTitle(title) 108 | .setContentText(messageBody) 109 | .setAutoCancel(true) 110 | .setSound(defaultSoundUri) 111 | .setContentIntent(pendingIntent); 112 | 113 | NotificationManager notificationManager = 114 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 115 | 116 | // Since android Oreo notification channel is needed. 117 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 118 | NotificationChannel channel = new NotificationChannel(channelId, 119 | "Channel human readable title", 120 | NotificationManager.IMPORTANCE_DEFAULT); 121 | notificationManager.createNotificationChannel(channel); 122 | } 123 | 124 | notificationManager.notify(0 /* ID of notification */, notificationBuilder.build()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.activity; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | 6 | import androidx.appcompat.app.AppCompatActivity; 7 | 8 | import com.github.mahadel.demo.R; 9 | import com.github.mahadel.demo.util.Constant; 10 | import com.github.mahadel.demo.util.MyApplication; 11 | import com.github.pwittchen.prefser.library.rx2.Prefser; 12 | 13 | import io.github.inflationx.viewpump.ViewPumpContextWrapper; 14 | 15 | /** 16 | * BaseActivity handle theme and custom font for all activity 17 | * Other activity should be extend it 18 | */ 19 | public class BaseActivity extends AppCompatActivity { 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | //Get type of theme from shared preferences 23 | Prefser prefser = new Prefser(this); 24 | if (prefser.get(Constant.IS_DARK_THEME, Boolean.class, true)) { 25 | setTheme(R.style.BaseAppTheme_Dark); 26 | } else { 27 | setTheme(R.style.BaseAppTheme); 28 | } 29 | super.onCreate(savedInstanceState); 30 | } 31 | 32 | @Override 33 | protected void attachBaseContext(Context base) { 34 | Context newContext = MyApplication.localeManager.setLocale(base); 35 | super.attachBaseContext(ViewPumpContextWrapper.wrap(newContext)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/activity/SelectSkillActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.Window; 7 | import android.view.WindowManager; 8 | import android.widget.Toast; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.recyclerview.widget.GridLayoutManager; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.github.mahadel.demo.R; 15 | import com.github.mahadel.demo.model.Category; 16 | import com.github.mahadel.demo.model.SkillsItem; 17 | import com.github.mahadel.demo.model.UserSkill; 18 | import com.github.mahadel.demo.util.Constant; 19 | import com.github.mahadel.demo.util.DatabaseUtil; 20 | import com.github.mahadel.demo.util.GridSpacingItemDecoration; 21 | import com.github.mahadel.demo.util.MyApplication; 22 | import com.google.android.material.button.MaterialButton; 23 | import com.mikepenz.fastadapter.FastAdapter; 24 | import com.mikepenz.fastadapter.IAdapter; 25 | import com.mikepenz.fastadapter.adapters.ItemAdapter; 26 | import com.mikepenz.fastadapter.listeners.OnClickListener; 27 | 28 | import java.util.List; 29 | 30 | import javax.annotation.Nullable; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | import butterknife.OnClick; 35 | import io.objectbox.Box; 36 | import io.objectbox.BoxStore; 37 | 38 | import static com.github.mahadel.demo.util.AppUtil.dpToPx; 39 | 40 | /** 41 | * SelectSkillActivity select skill from list and return to fragment of requester 42 | */ 43 | public class SelectSkillActivity extends BaseActivity { 44 | @BindView(R.id.recycler_view) 45 | RecyclerView recyclerView; 46 | @BindView(R.id.category_button) 47 | MaterialButton categoryButton; 48 | private Box skillsItemBox; 49 | private Box categoryBox; 50 | private Box userSkillBox; 51 | private FastAdapter mFastAdapterSkill; 52 | private ItemAdapter mItemAdapterSkill; 53 | private FastAdapter mFastAdapterCategory; 54 | private ItemAdapter mItemAdapterCategory; 55 | 56 | @Override 57 | protected void onCreate(Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | requestWindowFeature(Window.FEATURE_NO_TITLE); 60 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 61 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 62 | setContentView(R.layout.activity_select_skill); 63 | ButterKnife.bind(this); 64 | initVariables(); 65 | initRecyclerView(); 66 | initAdapters(); 67 | } 68 | 69 | /** 70 | * Setup init values of variables 71 | */ 72 | private void initVariables() { 73 | BoxStore boxStore = MyApplication.getBoxStore(); 74 | skillsItemBox = boxStore.boxFor(SkillsItem.class); 75 | categoryBox = boxStore.boxFor(Category.class); 76 | userSkillBox = boxStore.boxFor(UserSkill.class); 77 | } 78 | 79 | /** 80 | * Setup recycler view 81 | */ 82 | 83 | private void initRecyclerView() { 84 | RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2); 85 | recyclerView.setLayoutManager(mLayoutManager); 86 | recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(6, getResources()), true)); 87 | } 88 | 89 | /** 90 | * Setup FastAdapter variables & handle event of them 91 | */ 92 | private void initAdapters() { 93 | mItemAdapterCategory = new ItemAdapter<>(); 94 | mFastAdapterCategory = FastAdapter.with(mItemAdapterCategory); 95 | recyclerView.setAdapter(mFastAdapterCategory); 96 | mItemAdapterSkill = new ItemAdapter<>(); 97 | mFastAdapterSkill = FastAdapter.with(mItemAdapterSkill); 98 | mFastAdapterCategory.withOnClickListener(new OnClickListener() { 99 | @Override 100 | public boolean onClick(@Nullable View v, @NonNull IAdapter adapter, @NonNull Category item, int position) { 101 | getSkills(item); 102 | return true; 103 | } 104 | }); 105 | mFastAdapterSkill.withOnClickListener(new OnClickListener() { 106 | @Override 107 | public boolean onClick(@Nullable View v, @NonNull IAdapter adapter, @NonNull SkillsItem item, int position) { 108 | returnResult(item); 109 | return true; 110 | } 111 | }); 112 | getCategory(); 113 | } 114 | 115 | /** 116 | * Get skills from local db that belong to selected category 117 | * 118 | * @param item {@link Category} 119 | */ 120 | private void getSkills(Category item) { 121 | List skillsItems = DatabaseUtil.getSkillItemOfCategory(skillsItemBox, item.getUuid()); 122 | recyclerView.setAdapter(mFastAdapterSkill); 123 | mItemAdapterSkill.clear(); 124 | mItemAdapterSkill.add(skillsItems); 125 | categoryButton.setVisibility(View.VISIBLE); 126 | 127 | } 128 | 129 | /** 130 | * Get categories from local db 131 | */ 132 | private void getCategory() { 133 | List categories = categoryBox.getAll(); 134 | mItemAdapterCategory.clear(); 135 | mItemAdapterCategory.add(categories); 136 | } 137 | 138 | /** 139 | * Return selected skill to the fragment that request it 140 | * 141 | * @param item {@link SkillsItem} 142 | */ 143 | private void returnResult(@NonNull SkillsItem item) { 144 | if (!isUserSkillDuplicate(item)) { 145 | Intent resultIntent = new Intent(); 146 | resultIntent.putExtra(Constant.SKILL_ITEM, item); 147 | setResult(RESULT_OK, resultIntent); 148 | finish(); 149 | } else { 150 | Toast.makeText(SelectSkillActivity.this, getString(R.string.skill_exists_warning), Toast.LENGTH_SHORT).show(); 151 | } 152 | } 153 | 154 | /** 155 | * Check for duplicate select items 156 | * 157 | * @param item {@link SkillsItem} 158 | * @return Boolean 159 | */ 160 | private boolean isUserSkillDuplicate(SkillsItem item) { 161 | UserSkill userSkill = DatabaseUtil.getUserSkillWithSkillUUID(userSkillBox, item.getUuid()); 162 | return userSkill != null; 163 | } 164 | 165 | 166 | @OnClick(R.id.close_image_view) 167 | void closeDialog() { 168 | finish(); 169 | } 170 | 171 | @OnClick(R.id.category_button) 172 | public void handleCategoryButton(View view) { 173 | view.setVisibility(View.GONE); 174 | initAdapters(); 175 | } 176 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/fragment/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.content.ActivityNotFoundException; 6 | import android.content.Intent; 7 | import android.content.pm.PackageManager; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.Window; 14 | import android.view.WindowManager; 15 | 16 | import androidx.annotation.NonNull; 17 | import androidx.appcompat.widget.AppCompatTextView; 18 | import androidx.fragment.app.DialogFragment; 19 | 20 | import com.blankj.utilcode.util.SnackbarUtils; 21 | import com.github.mahadel.demo.R; 22 | import com.github.mahadel.demo.model.About; 23 | import com.github.mahadel.demo.model.AuthenticationInfo; 24 | import com.github.mahadel.demo.service.APIService; 25 | import com.github.mahadel.demo.util.AppUtil; 26 | import com.github.mahadel.demo.util.Constant; 27 | import com.github.mahadel.demo.util.FirebaseEventLog; 28 | import com.github.mahadel.demo.util.RetrofitUtil; 29 | import com.github.pwittchen.prefser.library.rx2.Prefser; 30 | import com.google.android.material.button.MaterialButton; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | import butterknife.OnClick; 35 | import retrofit2.Call; 36 | import retrofit2.Callback; 37 | import retrofit2.Response; 38 | 39 | /** 40 | * AboutFragment showing {@link About} instance values in the fragment 41 | */ 42 | public class AboutFragment extends DialogFragment { 43 | private static final String TAG = "AboutFragment"; 44 | @BindView(R.id.version_app_text_view) 45 | AppCompatTextView versionAppTextView; 46 | @BindView(R.id.update_button) 47 | MaterialButton updateButton; 48 | @BindView(R.id.sponsor_name) 49 | AppCompatTextView sponsorName; 50 | @BindView(R.id.sponsor_description_text_view) 51 | AppCompatTextView sponsorDescriptionTextView; 52 | private Dialog loadingDialog; 53 | private Activity activity; 54 | private About about; 55 | private String versionName; 56 | private AuthenticationInfo info; 57 | 58 | @Override 59 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 60 | View rootView = inflater.inflate(R.layout.fragment_about, container, false); 61 | ButterKnife.bind(this, rootView); 62 | initVariables(); 63 | setAppVersion(); 64 | getAbout(); 65 | return rootView; 66 | } 67 | 68 | /** 69 | * Setup init values of variables 70 | */ 71 | private void initVariables() { 72 | activity = getActivity(); 73 | Prefser prefser = new Prefser(activity); 74 | info = prefser.get(Constant.TOKEN, AuthenticationInfo.class, null); 75 | loadingDialog = AppUtil.getLoadingDialog(activity); 76 | } 77 | 78 | /** 79 | * Get app version 80 | */ 81 | private void setAppVersion() { 82 | versionName = ""; 83 | try { 84 | versionName = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).versionName; 85 | } catch (PackageManager.NameNotFoundException e) { 86 | e.printStackTrace(); 87 | } 88 | versionAppTextView.setText(versionName); 89 | } 90 | 91 | /** 92 | * Get {@link About} instance from server 93 | */ 94 | private void getAbout() { 95 | loadingDialog.show(); 96 | APIService apiService = RetrofitUtil.getRetrofit(info.getToken()).create(APIService.class); 97 | Call call = apiService.getAbout(); 98 | call.enqueue(new Callback() { 99 | @Override 100 | public void onResponse(@NonNull Call call, @NonNull Response response) { 101 | loadingDialog.dismiss(); 102 | if (response.isSuccessful()) { 103 | about = response.body(); 104 | handleAbout(); 105 | } 106 | } 107 | 108 | @Override 109 | public void onFailure(@NonNull Call call, @NonNull Throwable t) { 110 | loadingDialog.dismiss(); 111 | t.printStackTrace(); 112 | FirebaseEventLog.log("server_failure", TAG, "getAbout", t.getMessage()); 113 | } 114 | }); 115 | } 116 | 117 | /** 118 | * Showing values of {@link About} in the UI 119 | */ 120 | private void handleAbout() { 121 | if (!about.getAppVersion().equals(versionName)) { 122 | updateButton.setVisibility(View.VISIBLE); 123 | } 124 | sponsorName.setText(about.getSponsorName()); 125 | sponsorDescriptionTextView.setText(about.getSponsorDescription()); 126 | 127 | } 128 | 129 | @NonNull 130 | @Override 131 | public Dialog onCreateDialog(Bundle savedInstanceState) { 132 | Dialog dialog = super.onCreateDialog(savedInstanceState); 133 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 134 | dialog.setCancelable(true); 135 | WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 136 | lp.copyFrom(dialog.getWindow().getAttributes()); 137 | lp.width = WindowManager.LayoutParams.MATCH_PARENT; 138 | lp.height = WindowManager.LayoutParams.MATCH_PARENT; 139 | dialog.getWindow().setAttributes(lp); 140 | return dialog; 141 | } 142 | 143 | @OnClick(R.id.close_image_view) 144 | void close() { 145 | dismiss(); 146 | if (getFragmentManager() != null) { 147 | getFragmentManager().popBackStackImmediate(); 148 | } 149 | } 150 | 151 | /** 152 | * Handle view click and opening Website in the default browser app 153 | * 154 | * @param view {@link View} 155 | */ 156 | @OnClick({R.id.update_button, R.id.changelog_layout, R.id.license_layout, R.id.sponsor_website, R.id.developer_layout}) 157 | void handleLayoutClicks(View view) { 158 | if (about != null) { 159 | switch (view.getId()) { 160 | case R.id.update_button: 161 | startBrowser(about.getAppUrl(), view); 162 | break; 163 | case R.id.changelog_layout: 164 | startBrowser(about.getChangelogUrl(), view); 165 | break; 166 | case R.id.license_layout: 167 | startBrowser(about.getLicenseUrl(), view); 168 | break; 169 | case R.id.sponsor_website: 170 | startBrowser(about.getSponsorUrl(), view); 171 | break; 172 | case R.id.developer_layout: 173 | startBrowser(getString(R.string.bkhezry_twitter_url), view); 174 | break; 175 | } 176 | } else { 177 | AppUtil.showSnackbar(view, getString(R.string.error_request_message), activity, SnackbarUtils.LENGTH_LONG); 178 | getAbout(); 179 | } 180 | } 181 | 182 | /** 183 | * Showing url in the browser 184 | * 185 | * @param url String 186 | * @param view {@link View} 187 | */ 188 | private void startBrowser(String url, View view) { 189 | try { 190 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 191 | startActivity(browserIntent); 192 | } catch (ActivityNotFoundException e) { 193 | AppUtil.showSnackbar(view, getString(R.string.browser_not_found_label), activity, SnackbarUtils.LENGTH_INDEFINITE); 194 | e.printStackTrace(); 195 | } 196 | 197 | } 198 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/fragment/AddSkillFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Toast; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.appcompat.widget.AppCompatEditText; 14 | import androidx.appcompat.widget.AppCompatTextView; 15 | import androidx.fragment.app.Fragment; 16 | 17 | import com.blankj.utilcode.util.NetworkUtils; 18 | import com.blankj.utilcode.util.SnackbarUtils; 19 | import com.github.mahadel.demo.R; 20 | import com.github.mahadel.demo.listener.CallbackResult; 21 | import com.github.mahadel.demo.model.AuthenticationInfo; 22 | import com.github.mahadel.demo.model.SkillsItem; 23 | import com.github.mahadel.demo.model.UserSkill; 24 | import com.github.mahadel.demo.service.APIService; 25 | import com.github.mahadel.demo.ui.activity.SelectSkillActivity; 26 | import com.github.mahadel.demo.util.AppUtil; 27 | import com.github.mahadel.demo.util.Constant; 28 | import com.github.mahadel.demo.util.FirebaseEventLog; 29 | import com.github.mahadel.demo.util.RetrofitUtil; 30 | import com.github.pwittchen.prefser.library.rx2.Prefser; 31 | import com.google.android.material.button.MaterialButton; 32 | 33 | import butterknife.BindView; 34 | import butterknife.ButterKnife; 35 | import butterknife.OnClick; 36 | import retrofit2.Call; 37 | import retrofit2.Callback; 38 | import retrofit2.Response; 39 | 40 | import static android.app.Activity.RESULT_OK; 41 | 42 | /** 43 | * AddSkillFragment Showing Ui for select skill and submit userSkill to the server 44 | */ 45 | public class AddSkillFragment extends Fragment { 46 | 47 | private static final int REQUEST_SELECT_SKILL = 10001; 48 | private static final String TAG = "AddSkillFragment"; 49 | @BindView(R.id.skill_type_text_view) 50 | AppCompatTextView skillTypeTextView; 51 | @BindView(R.id.skill_description_edit_text) 52 | AppCompatEditText skillDescriptionEditText; 53 | @BindView(R.id.select_skill_button) 54 | MaterialButton selectSkillButton; 55 | private CallbackResult callbackResult; 56 | private AppUtil.SkillType skillType; 57 | private Activity activity; 58 | private SkillsItem skillsItem; 59 | private Prefser prefser; 60 | private Dialog loadingDialog; 61 | private AuthenticationInfo info; 62 | 63 | 64 | /** 65 | * Set callback listener for handle added userSkill to the MainActivity 66 | * 67 | * @param callbackResult CallbackResult 68 | */ 69 | public void setOnCallbackResult(final CallbackResult callbackResult) { 70 | this.callbackResult = callbackResult; 71 | } 72 | 73 | /** 74 | * Set SkillType 75 | * 76 | * @param skillType {@link com.github.mahadel.demo.util.AppUtil.SkillType} 77 | */ 78 | public void setSkillType(AppUtil.SkillType skillType) { 79 | this.skillType = skillType; 80 | } 81 | 82 | 83 | @Override 84 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 85 | View rootView = inflater.inflate(R.layout.fragment_add_skill, container, false); 86 | ButterKnife.bind(this, rootView); 87 | initVariables(); 88 | return rootView; 89 | } 90 | 91 | /** 92 | * Setup init values of variables 93 | */ 94 | private void initVariables() { 95 | activity = getActivity(); 96 | if (activity != null) { 97 | prefser = new Prefser(activity); 98 | loadingDialog = AppUtil.getLoadingDialog(activity); 99 | } 100 | info = prefser.get(Constant.TOKEN, AuthenticationInfo.class, null); 101 | if (skillType == AppUtil.SkillType.WANT_LEARN) { 102 | skillTypeTextView.setText(R.string.add_skill_learn_label); 103 | } else { 104 | skillTypeTextView.setText(R.string.add_skill_teach_label); 105 | } 106 | } 107 | 108 | /** 109 | * Submit click handler. Check internet connection before submit data to the server 110 | * 111 | * @param view {@link View} 112 | */ 113 | @OnClick(R.id.submit_btn) 114 | void submit(View view) { 115 | if (NetworkUtils.isConnected()) { 116 | submitUserSkill(); 117 | } else { 118 | AppUtil.showSnackbar(view, getString(R.string.no_internet_label), activity, SnackbarUtils.LENGTH_LONG); 119 | } 120 | } 121 | 122 | /** 123 | * Submit userSkill to the server 124 | */ 125 | private void submitUserSkill() { 126 | String description = skillDescriptionEditText.getText().toString(); 127 | int skillTypeInt; 128 | if (skillType == AppUtil.SkillType.WANT_TEACH) { 129 | skillTypeInt = 1; 130 | } else { 131 | skillTypeInt = 2; 132 | } 133 | if (skillsItem != null) { 134 | loadingDialog.show(); 135 | APIService apiService = RetrofitUtil.getRetrofit(info.getToken()).create(APIService.class); 136 | Call call = apiService.addUserSkill(info.getUuid(), skillsItem.getUuid(), description, skillTypeInt); 137 | call.enqueue(new Callback() { 138 | @Override 139 | public void onResponse(@NonNull Call call, @NonNull Response response) { 140 | loadingDialog.dismiss(); 141 | if (response.isSuccessful()) { 142 | UserSkill userSkill = response.body(); 143 | handleUserSkill(userSkill); 144 | } 145 | } 146 | 147 | @Override 148 | public void onFailure(@NonNull Call call, @NonNull Throwable t) { 149 | loadingDialog.dismiss(); 150 | t.printStackTrace(); 151 | AppUtil.showSnackbar(skillTypeTextView, getString(R.string.error_request_message), activity, SnackbarUtils.LENGTH_LONG); 152 | FirebaseEventLog.log("server_failure", TAG, "submitUserSkill", t.getMessage()); 153 | } 154 | }); 155 | } else { 156 | Toast.makeText(activity, getString(R.string.select_skill_message_label), Toast.LENGTH_LONG).show(); 157 | } 158 | } 159 | 160 | /** 161 | * Send back userSkill that added to the server to MainActivity 162 | * 163 | * @param userSkill {@link UserSkill} 164 | */ 165 | private void handleUserSkill(UserSkill userSkill) { 166 | if (callbackResult != null) { 167 | callbackResult.sendResult(userSkill, skillType); 168 | AppUtil.hideSoftInput(activity); 169 | } 170 | 171 | } 172 | 173 | @OnClick(R.id.select_skill_button) 174 | void selectSkill() { 175 | showSelectSkillDialog(); 176 | } 177 | 178 | /** 179 | * Start {@link SelectSkillActivity} for getting skill 180 | */ 181 | 182 | private void showSelectSkillDialog() { 183 | Intent intent = new Intent(activity, SelectSkillActivity.class); 184 | startActivityForResult(intent, REQUEST_SELECT_SKILL); 185 | } 186 | 187 | @Override 188 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 189 | super.onActivityResult(requestCode, resultCode, data); 190 | if (requestCode == REQUEST_SELECT_SKILL && resultCode == RESULT_OK) { 191 | skillsItem = data.getParcelableExtra(Constant.SKILL_ITEM); 192 | if (AppUtil.isRTL(activity)) { 193 | selectSkillButton.setText(skillsItem.getFaName()); 194 | } else { 195 | selectSkillButton.setText(skillsItem.getEnName()); 196 | } 197 | 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/fragment/EditProfileFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | import android.widget.RadioGroup; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.appcompat.widget.AppCompatRadioButton; 15 | import androidx.fragment.app.DialogFragment; 16 | 17 | import com.blankj.utilcode.util.NetworkUtils; 18 | import com.blankj.utilcode.util.SnackbarUtils; 19 | import com.github.mahadel.demo.R; 20 | import com.github.mahadel.demo.model.AuthenticationInfo; 21 | import com.github.mahadel.demo.model.ResponseMessage; 22 | import com.github.mahadel.demo.model.UserInfo; 23 | import com.github.mahadel.demo.service.APIService; 24 | import com.github.mahadel.demo.util.AppUtil; 25 | import com.github.mahadel.demo.util.Constant; 26 | import com.github.mahadel.demo.util.FirebaseEventLog; 27 | import com.github.mahadel.demo.util.RetrofitUtil; 28 | import com.github.pwittchen.prefser.library.rx2.Prefser; 29 | import com.google.android.material.textfield.TextInputEditText; 30 | import com.google.android.material.textfield.TextInputLayout; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | import butterknife.OnClick; 35 | import retrofit2.Call; 36 | import retrofit2.Callback; 37 | import retrofit2.Response; 38 | 39 | /** 40 | * EditProfileFragment Edit information of user 41 | */ 42 | public class EditProfileFragment extends DialogFragment { 43 | 44 | private static final String TAG = "EditProfileFragment"; 45 | @BindView(R.id.first_name_edit_text) 46 | TextInputEditText firstNameEditText; 47 | @BindView(R.id.til_first_name) 48 | TextInputLayout tilFirstName; 49 | @BindView(R.id.last_name_edit_text) 50 | TextInputEditText lastNameEditText; 51 | @BindView(R.id.til_last_name) 52 | TextInputLayout tilLastName; 53 | @BindView(R.id.radioMale) 54 | AppCompatRadioButton radioMale; 55 | @BindView(R.id.radioFemale) 56 | AppCompatRadioButton radioFemale; 57 | @BindView(R.id.radioGender) 58 | RadioGroup radioGender; 59 | private Activity activity; 60 | private UserInfo userInfo; 61 | private CallbackListener listener; 62 | private Dialog loadingDialog; 63 | private AuthenticationInfo info; 64 | 65 | /** 66 | * Set callback listener for handle edit event 67 | * 68 | * @param listener {@link CallbackListener} 69 | */ 70 | void setOnCallbackResult(CallbackListener listener) { 71 | this.listener = listener; 72 | } 73 | 74 | @Override 75 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 76 | View rootView = inflater.inflate(R.layout.dialog_edit_profile, container, false); 77 | ButterKnife.bind(this, rootView); 78 | initVariables(); 79 | return rootView; 80 | } 81 | 82 | /** 83 | * Setup init values of variables 84 | */ 85 | private void initVariables() { 86 | activity = getActivity(); 87 | Prefser prefser = new Prefser(activity); 88 | info = prefser.get(Constant.TOKEN, AuthenticationInfo.class, null); 89 | loadingDialog = AppUtil.getLoadingDialog(activity); 90 | firstNameEditText.setText(userInfo.getFirstName()); 91 | lastNameEditText.setText(userInfo.getLastName()); 92 | if (userInfo.getGender() == 1) { 93 | radioMale.setChecked(true); 94 | } else { 95 | radioFemale.setChecked(true); 96 | } 97 | } 98 | 99 | 100 | @NonNull 101 | @Override 102 | public Dialog onCreateDialog(Bundle savedInstanceState) { 103 | Dialog dialog = super.onCreateDialog(savedInstanceState); 104 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 105 | dialog.setCancelable(true); 106 | WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 107 | lp.copyFrom(dialog.getWindow().getAttributes()); 108 | lp.width = WindowManager.LayoutParams.MATCH_PARENT; 109 | lp.height = WindowManager.LayoutParams.MATCH_PARENT; 110 | dialog.getWindow().setAttributes(lp); 111 | return dialog; 112 | } 113 | 114 | /** 115 | * Set user information to the fragment 116 | * 117 | * @param userInfo {@link UserInfo} 118 | */ 119 | void setUserInfo(UserInfo userInfo) { 120 | this.userInfo = userInfo; 121 | } 122 | 123 | /** 124 | * Handle edit profile click event 125 | * 126 | * @param view {@link View} 127 | */ 128 | @OnClick(R.id.submit_info_button) 129 | void editProfileInfo(View view) { 130 | int gender; 131 | String firstName = firstNameEditText.getText().toString(); 132 | String lastName = lastNameEditText.getText().toString(); 133 | if (!firstName.equals("") && !lastName.equals("")) { 134 | if (radioGender.getCheckedRadioButtonId() == R.id.radioFemale) { 135 | gender = 2; 136 | } else { 137 | gender = 1; 138 | } 139 | if (NetworkUtils.isConnected()) { 140 | updateUser(view, firstName, lastName, gender); 141 | } else { 142 | AppUtil.showSnackbar(view, getString(R.string.no_internet_label), activity, SnackbarUtils.LENGTH_LONG); 143 | } 144 | } else { 145 | AppUtil.showSnackbar(view, getString(R.string.field_require_label), activity, SnackbarUtils.LENGTH_LONG); 146 | } 147 | } 148 | 149 | /** 150 | * Update user information in the server 151 | * 152 | * @param view 153 | * @param firstName String first name 154 | * @param lastName String last name 155 | * @param gender Int gender 156 | */ 157 | private void updateUser(View view, final String firstName, final String lastName, final int gender) { 158 | loadingDialog.show(); 159 | APIService apiService = RetrofitUtil.getRetrofit(info.getToken()).create(APIService.class); 160 | Call call = apiService.updateUser(info.getUuid(), firstName, lastName, gender); 161 | call.enqueue(new Callback() { 162 | @Override 163 | public void onResponse(@NonNull Call call, @NonNull Response response) { 164 | loadingDialog.dismiss(); 165 | if (response.isSuccessful()) { 166 | userInfo.setFirstName(firstName); 167 | userInfo.setGender(gender); 168 | userInfo.setLastName(lastName); 169 | if (listener != null) { 170 | listener.sendResult(userInfo); 171 | close(); 172 | } 173 | } 174 | } 175 | 176 | @Override 177 | public void onFailure(@NonNull Call call, @NonNull Throwable t) { 178 | loadingDialog.dismiss(); 179 | t.printStackTrace(); 180 | AppUtil.showSnackbar(view, getString(R.string.error_request_message), activity, SnackbarUtils.LENGTH_LONG); 181 | FirebaseEventLog.log("server_failure", TAG, "updateUser", t.getMessage()); 182 | } 183 | }); 184 | 185 | } 186 | 187 | @OnClick(R.id.close_image_view) 188 | void close() { 189 | dismiss(); 190 | if (getFragmentManager() != null) { 191 | getFragmentManager().popBackStackImmediate(); 192 | } 193 | } 194 | 195 | public interface CallbackListener { 196 | void sendResult(UserInfo userInfo); 197 | } 198 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/ui/fragment/SettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.appcompat.widget.AppCompatImageView; 15 | import androidx.fragment.app.DialogFragment; 16 | 17 | import com.github.mahadel.demo.R; 18 | import com.github.mahadel.demo.ui.activity.MainActivity; 19 | import com.github.mahadel.demo.util.Constant; 20 | import com.github.mahadel.demo.util.LocaleManager; 21 | import com.github.mahadel.demo.util.MyApplication; 22 | import com.github.pwittchen.prefser.library.rx2.Prefser; 23 | 24 | import butterknife.BindView; 25 | import butterknife.ButterKnife; 26 | import butterknife.OnClick; 27 | 28 | /** 29 | * SettingsFragment change language & theme of application 30 | */ 31 | public class SettingsFragment extends DialogFragment { 32 | @BindView(R.id.persian_image_view) 33 | AppCompatImageView persianImageView; 34 | @BindView(R.id.english_image_view) 35 | AppCompatImageView englishImageView; 36 | private Activity activity; 37 | private Prefser prefser; 38 | 39 | @Override 40 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 41 | View rootView = inflater.inflate(R.layout.fragment_settings, container, false); 42 | ButterKnife.bind(this, rootView); 43 | initVariables(); 44 | setUpLocale(); 45 | return rootView; 46 | } 47 | 48 | /** 49 | * Setup init values of variables 50 | */ 51 | private void initVariables() { 52 | activity = getActivity(); 53 | prefser = new Prefser(activity); 54 | } 55 | 56 | @NonNull 57 | @Override 58 | public Dialog onCreateDialog(Bundle savedInstanceState) { 59 | Dialog dialog = super.onCreateDialog(savedInstanceState); 60 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 61 | dialog.setCancelable(true); 62 | WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 63 | lp.copyFrom(dialog.getWindow().getAttributes()); 64 | lp.width = WindowManager.LayoutParams.MATCH_PARENT; 65 | lp.height = WindowManager.LayoutParams.MATCH_PARENT; 66 | dialog.getWindow().setAttributes(lp); 67 | return dialog; 68 | } 69 | 70 | @OnClick(R.id.close_image_view) 71 | void close() { 72 | dismiss(); 73 | if (getFragmentManager() != null) { 74 | getFragmentManager().popBackStackImmediate(); 75 | } 76 | } 77 | 78 | /** 79 | * Handle change language click event 80 | * 81 | * @param view {@link View} 82 | */ 83 | 84 | @OnClick({R.id.persian_image_view, R.id.english_image_view}) 85 | void handleLanguage(View view) { 86 | switch (view.getId()) { 87 | case R.id.persian_image_view: 88 | restartApp(LocaleManager.LANGUAGE_PERSIAN); 89 | break; 90 | case R.id.english_image_view: 91 | restartApp(LocaleManager.LANGUAGE_ENGLISH); 92 | break; 93 | } 94 | } 95 | 96 | /** 97 | * Setup locale layout 98 | */ 99 | private void setUpLocale() { 100 | if (MyApplication.localeManager.getLanguage().equals(LocaleManager.LANGUAGE_PERSIAN)) { 101 | changeLanguagePersian(); 102 | } else { 103 | changeLanguageEnglish(); 104 | } 105 | } 106 | 107 | /** 108 | * Set new locale & restart app 109 | * 110 | * @param language String selected language 111 | */ 112 | private void restartApp(String language) { 113 | MyApplication.localeManager.setNewLocale(activity, language); 114 | Intent i = new Intent(activity, MainActivity.class); 115 | startActivity(i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)); 116 | System.exit(0); 117 | } 118 | 119 | private void changeLanguagePersian() { 120 | persianImageView.setBackgroundResource(R.drawable.image_border); 121 | englishImageView.setBackgroundResource(android.R.color.transparent); 122 | } 123 | 124 | private void changeLanguageEnglish() { 125 | englishImageView.setBackgroundResource(R.drawable.image_border); 126 | persianImageView.setBackgroundResource(android.R.color.transparent); 127 | } 128 | 129 | /** 130 | * Handle change theme click event 131 | * 132 | * @param view View {@link View} 133 | */ 134 | @OnClick({R.id.dark_theme_button, R.id.light_theme_button}) 135 | void handleThemeClick(View view) { 136 | switch (view.getId()) { 137 | case R.id.dark_theme_button: 138 | prefser.put(Constant.IS_DARK_THEME, true); 139 | restartActivity(); 140 | break; 141 | case R.id.light_theme_button: 142 | prefser.put(Constant.IS_DARK_THEME, false); 143 | restartActivity(); 144 | break; 145 | } 146 | } 147 | 148 | /** 149 | * Restart app after change theme of it 150 | */ 151 | 152 | private void restartActivity() { 153 | activity.finish(); 154 | final Intent intent = activity.getIntent(); 155 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 156 | activity.startActivity(intent); 157 | } 158 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/Constant.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | public class Constant { 4 | public static final String LANGUAGE = "language"; 5 | public static final String BASE_URL = "https://demo.mahadel.ir/api/v1/"; 6 | public static final String TOKEN = "token"; 7 | public static final String GRAVATAR_URL = "https://www.gravatar.com/avatar/"; 8 | public static final String IS_DARK_THEME = "is-dark-theme"; 9 | public static final String SKILL_ITEM = "skill-item"; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/DatabaseUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import com.github.mahadel.demo.model.SkillsItem; 4 | import com.github.mahadel.demo.model.SkillsItem_; 5 | import com.github.mahadel.demo.model.UserSkill; 6 | import com.github.mahadel.demo.model.UserSkill_; 7 | 8 | import java.util.List; 9 | 10 | import io.objectbox.Box; 11 | import io.objectbox.query.Query; 12 | 13 | public class DatabaseUtil { 14 | 15 | /** 16 | * Get userSkills with type of it 17 | * 18 | * @param userSkillBox {@link Box} 19 | * @param skillType Int 20 | * @return Instance of {@link Query} 21 | */ 22 | public static Query getUserSkillWithType(Box userSkillBox, int skillType) { 23 | return userSkillBox.query() 24 | .equal(UserSkill_.skillType, skillType) 25 | .orderDesc(UserSkill_.id) 26 | .build(); 27 | } 28 | 29 | /** 30 | * Get userSkill with skill uuid 31 | * 32 | * @param userSkillBox {@link Box} 33 | * @param uuid String uuid 34 | * @return Instance of {@link UserSkill} 35 | */ 36 | public static UserSkill getUserSkillWithSkillUUID(Box userSkillBox, String uuid) { 37 | return userSkillBox.query() 38 | .equal(UserSkill_.skillUuid, uuid) 39 | .build().findFirst(); 40 | } 41 | 42 | /** 43 | * Get userSkill with uuid 44 | * 45 | * @param userSkillBox {@link Box} 46 | * @param uuid String uuid 47 | * @return Instance of {@link UserSkill} 48 | */ 49 | public static UserSkill getUserSkillWithUUID(Box userSkillBox, String uuid) { 50 | return userSkillBox.query() 51 | .equal(UserSkill_.uuid, uuid) 52 | .build().findFirst(); 53 | } 54 | 55 | /** 56 | * Get SkillItem with uuid 57 | * 58 | * @param skillsItemBox {@link Box} 59 | * @param uuid String uuid 60 | * @return Instance of {@link Query} 61 | */ 62 | 63 | public static Query getSkillItemQueryWithUUID(Box skillsItemBox, String uuid) { 64 | return skillsItemBox.query() 65 | .equal(SkillsItem_.uuid, uuid) 66 | .build(); 67 | } 68 | 69 | /** 70 | * Get list of skills item with uuid of category 71 | * 72 | * @param skillsItemBox {@link Box} 73 | * @param categoryUUID String uuid 74 | * @return List of {@link SkillsItem} 75 | */ 76 | public static List getSkillItemOfCategory(Box skillsItemBox, String categoryUUID) { 77 | return skillsItemBox.query() 78 | .equal(SkillsItem_.categoryUuid, categoryUUID) 79 | .build().find(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/FirebaseEventLog.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import android.os.Bundle; 4 | 5 | public class FirebaseEventLog { 6 | 7 | public static void log(String event, String tag, String function, String message) { 8 | Bundle bundle = new Bundle(); 9 | bundle.putString("tag", tag); 10 | bundle.putString("function", function); 11 | bundle.putString("error_message", message); 12 | MyApplication.getFirebaseAnalytics().logEvent(event, bundle); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/GridSpacingItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import android.graphics.Rect; 4 | import android.view.View; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | 9 | public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { 10 | private int spanCount; 11 | private int spacing; 12 | private boolean includeEdge; 13 | 14 | public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { 15 | this.spanCount = spanCount; 16 | this.spacing = spacing; 17 | this.includeEdge = includeEdge; 18 | } 19 | 20 | @Override 21 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 22 | int position = parent.getChildAdapterPosition(view); // item position 23 | int column = position % spanCount; // item column 24 | 25 | if (includeEdge) { 26 | outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) 27 | outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) 28 | 29 | if (position < spanCount) { // top edge 30 | outRect.top = spacing; 31 | } 32 | outRect.bottom = spacing; // item bottom 33 | } else { 34 | outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing) 35 | outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) 36 | if (position >= spanCount) { 37 | outRect.top = spacing; // item top 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/LocaleManager.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | import android.content.res.Configuration; 7 | import android.content.res.Resources; 8 | import android.preference.PreferenceManager; 9 | 10 | import java.util.Locale; 11 | 12 | import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 13 | import static android.os.Build.VERSION_CODES.N; 14 | 15 | /** 16 | * Utils for handle locale language change 17 | */ 18 | public class LocaleManager { 19 | 20 | public static final String LANGUAGE_ENGLISH = "en"; 21 | public static final String LANGUAGE_PERSIAN = "fa"; 22 | private final SharedPreferences prefs; 23 | 24 | LocaleManager(Context context) { 25 | prefs = PreferenceManager.getDefaultSharedPreferences(context); 26 | } 27 | 28 | public static Locale getLocale(Resources res) { 29 | Configuration config = res.getConfiguration(); 30 | return AppUtil.isAtLeastVersion(N) ? config.getLocales().get(0) : config.locale; 31 | } 32 | 33 | public Context setLocale(Context c) { 34 | return updateResources(c, getLanguage()); 35 | } 36 | 37 | public Context setNewLocale(Context c, String language) { 38 | persistLanguage(language); 39 | return updateResources(c, language); 40 | } 41 | 42 | public String getLanguage() { 43 | return prefs.getString(Constant.LANGUAGE, LANGUAGE_PERSIAN); 44 | } 45 | 46 | @SuppressLint("ApplySharedPref") 47 | private void persistLanguage(String language) { 48 | prefs.edit().putString(Constant.LANGUAGE, language).commit(); 49 | } 50 | 51 | private Context updateResources(Context context, String language) { 52 | Locale locale = new Locale(language); 53 | Locale.setDefault(locale); 54 | 55 | Resources res = context.getResources(); 56 | Configuration config = new Configuration(res.getConfiguration()); 57 | if (AppUtil.isAtLeastVersion(JELLY_BEAN_MR1)) { 58 | config.setLocale(locale); 59 | context = context.createConfigurationContext(config); 60 | } else { 61 | config.locale = locale; 62 | res.updateConfiguration(config, res.getDisplayMetrics()); 63 | } 64 | return context; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | 7 | import com.github.mahadel.demo.BuildConfig; 8 | import com.github.mahadel.demo.R; 9 | import com.github.mahadel.demo.model.MyObjectBox; 10 | import com.google.firebase.analytics.FirebaseAnalytics; 11 | 12 | import io.github.inflationx.calligraphy3.CalligraphyConfig; 13 | import io.github.inflationx.calligraphy3.CalligraphyInterceptor; 14 | import io.github.inflationx.viewpump.ViewPump; 15 | import io.objectbox.BoxStore; 16 | import io.objectbox.android.AndroidObjectBrowser; 17 | 18 | public class MyApplication extends Application { 19 | private static BoxStore boxStore; 20 | public static LocaleManager localeManager; 21 | private static FirebaseAnalytics firebaseAnalytics; 22 | 23 | public static FirebaseAnalytics getFirebaseAnalytics() { 24 | return firebaseAnalytics; 25 | } 26 | 27 | @Override 28 | public void onCreate() { 29 | super.onCreate(); 30 | ViewPump.init(ViewPump.builder() 31 | .addInterceptor(new CalligraphyInterceptor( 32 | new CalligraphyConfig.Builder() 33 | .setDefaultFontPath("fonts/IRANSansMobile.ttf") 34 | .setFontAttrId(R.attr.fontPath) 35 | .build())) 36 | .build()); 37 | firebaseAnalytics = FirebaseAnalytics.getInstance(this); 38 | createBoxStore(); 39 | 40 | } 41 | 42 | 43 | /** 44 | * Return instance of box store 45 | * 46 | * @return Instance of {@link BoxStore} 47 | */ 48 | 49 | public static BoxStore getBoxStore() { 50 | return boxStore; 51 | } 52 | 53 | /** 54 | * Create static {@link BoxStore} instance 55 | */ 56 | private void createBoxStore() { 57 | boxStore = MyObjectBox.builder().androidContext(MyApplication.this).build(); 58 | if (BuildConfig.DEBUG) { 59 | new AndroidObjectBrowser(boxStore).start(this); 60 | } 61 | } 62 | 63 | @Override 64 | protected void attachBaseContext(Context base) { 65 | localeManager = new LocaleManager(base); 66 | super.attachBaseContext(localeManager.setLocale(base)); 67 | } 68 | 69 | @Override 70 | public void onConfigurationChanged(Configuration newConfig) { 71 | super.onConfigurationChanged(newConfig); 72 | localeManager.setLocale(this); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mahadel/demo/util/RetrofitUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo.util; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import java.io.IOException; 6 | 7 | import okhttp3.Interceptor; 8 | import okhttp3.OkHttpClient; 9 | import okhttp3.Request; 10 | import okhttp3.Response; 11 | import okhttp3.logging.HttpLoggingInterceptor; 12 | import retrofit2.Retrofit; 13 | import retrofit2.converter.gson.GsonConverterFactory; 14 | 15 | /** 16 | * Retrofit Utils 17 | */ 18 | public class RetrofitUtil { 19 | 20 | /** 21 | * Get retrofit instance 22 | * 23 | * @param token String token of user 24 | * @return Instance of {@link Retrofit} 25 | */ 26 | public static Retrofit getRetrofit(String token) { 27 | return new Retrofit.Builder().baseUrl(Constant.BASE_URL) 28 | .client(getHeader(token)) 29 | .addConverterFactory(GsonConverterFactory.create()) 30 | .build(); 31 | } 32 | 33 | /** 34 | * Get OkHttpClient with authorization header & logging interceptor 35 | * 36 | * @param authorizationValue String user token 37 | * @return Instance of {@link OkHttpClient} 38 | */ 39 | private static OkHttpClient getHeader(final String authorizationValue) { 40 | //delete this interceptor in released app 41 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 42 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 43 | //end interceptor 44 | return new OkHttpClient.Builder() 45 | .addInterceptor(interceptor) 46 | .addNetworkInterceptor( 47 | new Interceptor() { 48 | @Override 49 | public Response intercept(@NonNull Chain chain) throws IOException { 50 | Request request = null; 51 | if (authorizationValue != null) { 52 | Request original = chain.request(); 53 | // Request customization: add request headers 54 | Request.Builder requestBuilder = original.newBuilder() 55 | .addHeader("Authorization", authorizationValue); 56 | 57 | request = requestBuilder.build(); 58 | } 59 | assert request != null; 60 | return chain.proceed(request); 61 | } 62 | }) 63 | .build(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_24px.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_downward_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_upward_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_book_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_create_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drawer_menu_24px.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/drawable/ic_english.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_exit_to_app_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_google_plus_32px.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_language_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_list_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mail_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_persian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/drawable/ic_persian.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_24px.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_swap_vert_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sync_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/image_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 42 | 43 | 50 | 51 | 60 | 61 | 62 | 63 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_select_skill.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 22 | 23 | 34 | 35 | 41 | 42 | 48 | 49 | 52 | 53 | 58 | 59 | 62 | 63 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 16 | 17 | 28 | 29 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 55 | 56 | 62 | 63 | 74 | 75 | 81 | 82 | 87 | 88 | 93 | 94 | 95 | 96 | 104 | 105 | 112 | 113 | 119 | 120 | 131 | 132 | 138 | 139 | 144 | 145 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_confirm.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 21 | 22 | 30 | 31 | 37 | 38 | 42 | 43 | 51 | 52 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit_profile.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 20 | 21 | 22 | 30 | 31 | 38 | 39 | 50 | 51 | 52 | 62 | 63 | 74 | 75 | 76 | 82 | 83 | 90 | 91 | 98 | 99 | 100 | 101 | 102 | 114 | 115 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_full_screen_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_skill_type.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 23 | 24 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/error_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 24 | 25 | 30 | 31 | 36 | 37 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_add_skill.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | 30 | 31 | 37 | 38 | 39 | 46 | 47 | 54 | 55 | 65 | 66 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_skill_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | 30 | 31 | 35 | 36 | 43 | 44 | 47 | 48 | 56 | 57 | 58 | 64 | 65 | 72 | 73 | 83 | 84 | 87 | 88 | 89 | 96 | 97 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 17 | 18 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_connection_received.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 24 | 25 | 31 | 32 | 35 | 36 | 41 | 42 | 43 | 44 | 45 | 52 | 53 | 58 | 59 | 65 | 66 | 69 | 70 | 75 | 76 | 77 | 82 | 83 | 89 | 90 | 93 | 94 | 99 | 100 | 101 | 102 | 103 | 104 | 112 | 113 | 121 | 122 | 127 | 128 | 136 | 137 | 138 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 25 | 26 | 31 | 32 | 38 | 39 | 46 | 47 | 48 | 51 | 52 | 58 | 59 | 65 | 66 | 69 | 70 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 85 | 89 | 90 | 97 | 98 | 104 | 105 | 112 | 113 | 120 | 121 | 129 | 130 | 136 | 137 | 144 | 145 | 152 | 153 | 154 | 155 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_skill.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 17 | 18 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_user_skill.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 17 | 18 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_appbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

5 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_primary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-fa/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | تبادل مهارت دمو 3 | ورود با حساب‌کاربری گوگل 4 | تایید 5 | نام 6 | نام‌خانوادگی 7 | مرد 8 | زن 9 | نام مهارت: 10 | توضیحات: 11 | قصد یادگیری دارم 12 | قصد یاددادن دارم 13 | می‌خوام یاد بگیرم 14 | می‌خوام یاد بدم 15 | انتخاب مهارت 16 | این مهارت قبلا اضافه شده است. 17 | پروفایل 18 | تنظیمات 19 | درباره 20 | ویرایش 21 | حذف 22 | از حذف مهارت مطمئن هستید؟ 23 | لغو 24 | بله 25 | زبان 26 | تم 27 | روشن 28 | تاریک 29 | بهروز خضری 30 | توسعه‌دهنده 31 | وب‌سایت 32 | اسپانسر 33 | لایسنس 34 | تغییرات برنامه 35 | نسخه‌برنامه 36 | لطفا ارتباط اینترنت را چک کنید 37 | باشه 38 | خطا در حین دریافت اطلاعات 39 | تلاش مجدد 40 | لطفا تمامی اطلاعات را وارد نمایید 41 | لطفا مهارت مورد نظر را انتخاب کنید 42 | درخواست 43 | درخواست‌ها 44 | جستجو 45 | ارسال ایمیل 46 | حذف درخواست 47 | دریافت شده 48 | ارسال شده 49 | رد درخواست 50 | قبول درخواست 51 | درخواست با موفقیت ارسال شد. 52 | مهارتی وجود ندارد 53 | برای اضافه کردن مهارت دکمه + را فشار دهید 54 | حذف 55 | خروج 56 | برای خروج از برنامه مطمئن هستید؟ 57 | از حذف کامل حساب‌کاربری خود مطمئن هستید؟ 58 | به‌روزرسانی 59 | دسته‌بندی 60 | جستجو نتیجه‌ای نداشت 61 | لطفا بعدا جستجو نمایید 62 | جنسیت: 63 | کاربر یافت‌شده: 64 | یاد می‌گیرد: 65 | یاد می‌دهد: 66 | ارسال شده به: 67 | ایمیل: 68 | ارسال درخواست به: 69 | حساب‌کاربری شخص حذف شده است 70 | درخواست شما رد شده است 71 | هنوز پاسخ داده نشده است 72 | درخواستی یافت نشد 73 | در صورت ثبت درخواست، در اینجا نمایش داده می‌شود 74 | از حذف این درخواست مطمئن هستید؟ 75 | درخواست تبادل مهارت 76 | برنامه‌ ارسال ایمیل در دسترس نیست 77 | یاد می‌گیرم: 78 | یاد می‌دهم: 79 | دریافت شده از: 80 | برنامه مرورگر یافت نشد 81 | دسترسی غیرمجاز. لطفا دوباره وارد شوید 82 | خطایی روی داد. دوباره تلاش کنید 83 | ایمیل کاربر در دسترس نیست 84 | درخواست شما تکراری است. لطفا منتظر پاسخ باشید. 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/res/values-large/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 250dp 4 | 260dp 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #039be5 4 | #e6e6e6 5 | #999999 6 | #666666 7 | #37474F 8 | #263238 9 | #141d26 10 | #00ffffff 11 | #FFFFFF 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 150dp 4 | 160dp 5 | 6 | 1dp 7 | 3dp 8 | 5dp 9 | 10dp 10 | 15dp 11 | 20dp 12 | 25dp 13 | 35dp 14 | 40dp 15 | 50dp 16 | 130dp 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Skill Swap Demo 3 | Login with Google account 4 | Submit 5 | First Name 6 | Last Name 7 | Male 8 | Female 9 | Skill name: 10 | Description: 11 | Add skill want learn 12 | Add skill want teach 13 | I want to learn 14 | I want to teach 15 | Select skill 16 | This skill already exists. 17 | Profile 18 | Settings 19 | About 20 | Edit 21 | Remove 22 | Are you sure want remove skill? 23 | Cancel 24 | Yes 25 | Language 26 | Theme 27 | Light 28 | Dark 29 | \@bkhezry 30 | Behrouz Khezry 31 | Developer 32 | Access Website 33 | Sponsor 34 | License 35 | Changelog 36 | Version 37 | Please check internet connection 38 | OK 39 | Error during get data from server 40 | Retry 41 | Please fill all fields 42 | Please select a skill 43 | Request 44 | Connections 45 | Search 46 | Send Email 47 | Delete 48 | Received 49 | Sent 50 | Reject 51 | Accept 52 | request sent successfully. 53 | No skill 54 | For add skill press + button 55 | Delete 56 | Logout 57 | Are you sure want logout from app? 58 | Are you sure want delete your account permanently? 59 | Update 60 | Category 61 | No search result 62 | Please search later 63 | Gender: 64 | Account found: 65 | Learns: 66 | Teaches: 67 | Sent to: 68 | Email: 69 | Send request to: 70 | Account deleted 71 | Your request rejected 72 | No response yet 73 | No request found 74 | Submitted request will be showing here 75 | Are you sure want remove this request? 76 | Request skill swap 77 | Mail app not available 78 | I learn: 79 | I teach: 80 | Received from: 81 | https://twitter.com/bkhezry 82 | Browser not found 83 | Access is deny, Please login again 84 | fcm_default_channel 85 | Error occurred. Please try again 86 | Email of user not available 87 | Request is duplicate. Please wait for response. 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 19 | 20 | 31 | 32 | 41 | 42 | 51 | 52 | 55 | 56 | 59 | 60 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 29 | -------------------------------------------------------------------------------- /app/src/release/res/values/google_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 1071346960599-otiq3a2lc3rkfhttna29mb3d64rt4ala.apps.googleusercontent.com 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/test/java/com/github/mahadel/demo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.github.mahadel.demo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /assets/welcome-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/assets/welcome-img.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | maven { url 'https://maven.fabric.io/public' } 6 | google() 7 | jcenter() 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.4.0-alpha08' 12 | classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.3' 13 | classpath "io.objectbox:objectbox-gradle-plugin:2.2.0" 14 | classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-rc2' 15 | classpath 'com.google.gms:google-services:4.2.0' 16 | classpath 'io.fabric.tools:gradle:1.27.0' 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | google() 25 | maven { url 'https://maven.fabric.io/public' } 26 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 27 | jcenter() 28 | maven { url 'https://jitpack.io' } 29 | } 30 | } 31 | 32 | task clean(type: Delete) { 33 | delete rootProject.buildDir 34 | } 35 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | android.jetifier.blacklist=butterknife-compiler 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mahadel/android/c55090900894df7fa927e6775e0f919f012e9082/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 13 13:57:16 IRST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1-milestone-1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------