├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── ML model-Backend ├── Dockerfile ├── app.py ├── dataset │ ├── data.csv │ ├── data_train_fix.csv │ ├── dataset.csv │ └── dataset_train_fix_labeled.csv ├── model │ ├── APLOD_Net_Revision(_h5_format).ipynb │ └── aplod_version_2.h5 └── requirements.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lawstech │ │ └── aplod │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── ic_launcher_new-playstore.png │ ├── java │ │ └── com │ │ │ └── lawstech │ │ │ └── aplod │ │ │ ├── MainActivity.kt │ │ │ ├── SplashScreen.kt │ │ │ ├── data │ │ │ ├── AplodRepository.kt │ │ │ ├── IAplodDataSource.kt │ │ │ └── source │ │ │ │ ├── local │ │ │ │ └── entity │ │ │ │ │ ├── MemberEntity.kt │ │ │ │ │ ├── PasalEntity.kt │ │ │ │ │ └── SentimentEntity.kt │ │ │ │ └── remote │ │ │ │ ├── Api │ │ │ │ ├── ApiConfig.kt │ │ │ │ └── ApiService.kt │ │ │ │ ├── RemoteDataSource.kt │ │ │ │ └── response │ │ │ │ └── SentimentResponse.kt │ │ │ ├── onboard │ │ │ ├── OnBoardingActivity.kt │ │ │ ├── adapter │ │ │ │ └── OnBoardingViewPagerAdapter.kt │ │ │ └── onBoardModel │ │ │ │ └── OnBoardingData.kt │ │ │ ├── ui │ │ │ ├── about_us │ │ │ │ ├── AboutUsPageAdapter.kt │ │ │ │ ├── AboutUsViewModel.kt │ │ │ │ ├── MemberAdapter.kt │ │ │ │ └── fragment │ │ │ │ │ ├── AboutUsFragment.kt │ │ │ │ │ ├── AplodAboutFragment.kt │ │ │ │ │ └── MemberFragment.kt │ │ │ ├── di │ │ │ │ └── Injection.kt │ │ │ ├── faq │ │ │ │ ├── FaqAdapter.kt │ │ │ │ ├── FaqFragment.kt │ │ │ │ └── FaqViewModel.kt │ │ │ └── home │ │ │ │ ├── HomeFragment.kt │ │ │ │ ├── HomeFragmentCallback.kt │ │ │ │ └── HomeViewModel.kt │ │ │ ├── utils │ │ │ ├── DataDummy.kt │ │ │ └── JsonHelper.kt │ │ │ └── viewmodel │ │ │ └── ViewModelFactory.kt │ └── res │ │ ├── color │ │ └── nav_color.xml │ │ ├── drawable-v24 │ │ ├── background_ungu_dark.png │ │ ├── bg_recyclerview_item.png │ │ ├── careful_gesture_3.png │ │ ├── handphone_gesture_1.png │ │ ├── hate_speech.png │ │ ├── ic_launcher_foreground.xml │ │ ├── indicator_selector.xml │ │ ├── law_tech.png │ │ ├── oke_gesture_2.png │ │ ├── selected.xml │ │ └── unselected.xml │ │ ├── drawable │ │ ├── agnes.jpeg │ │ ├── alex.jpeg │ │ ├── bondan.jpeg │ │ ├── custom_button.xml │ │ ├── fachri.jpg │ │ ├── home_fragment.png │ │ ├── ic_baseline_bookmark.xml │ │ ├── ic_baseline_home_24.xml │ │ ├── ic_baseline_people_24.xml │ │ ├── ic_baseline_question_answer_24.xml │ │ ├── ic_baseline_refresh_24.xml │ │ ├── ic_baseline_share.xml │ │ ├── ic_broken_image.xml │ │ ├── ic_dashboard_black_24dp.xml │ │ ├── ic_error.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_loading.xml │ │ ├── ic_purple_wave.xml │ │ ├── ic_purple_wave2.xml │ │ ├── icha.jpg │ │ ├── ikhwan.jpg │ │ ├── logo.png │ │ ├── logo_fix_no_ellipse_2.png │ │ ├── not_ok.png │ │ ├── ok.png │ │ ├── ok_hand.png │ │ ├── paper_plane.png │ │ ├── paper_plane_1.png │ │ └── rounded.xml │ │ ├── font │ │ ├── poppins_bold.ttf │ │ ├── poppins_italic.ttf │ │ └── poppins_regular.ttf │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_onboarding.xml │ │ ├── activity_splash_screen.xml │ │ ├── fragment_about_aplod.xml │ │ ├── fragment_about_us.xml │ │ ├── fragment_faq.xml │ │ ├── fragment_home.xml │ │ ├── fragment_member.xml │ │ ├── item_member.xml │ │ ├── item_pasal.xml │ │ └── onboarding_screen_layout.xml │ │ ├── menu │ │ └── bottom_nav_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── mobile_navigation.xml │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── lawstech │ └── aplod │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | # Local configuration file (sdk path, etc) 17 | local.properties 18 | # Proguard folder generated by Eclipse 19 | proguard/ 20 | # Log Files 21 | *.log 22 | # Android Studio Navigation editor temp files 23 | .navigation/ 24 | # Android Studio captures folder 25 | captures/ 26 | # IntelliJ Files 27 | .idea/ 28 | *.iml 29 | *.iws 30 | *.ipr 31 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Aplod -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ML model-Backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-slim 2 | 3 | ENV APP_HOME /app 4 | WORKDIR $APP_HOME 5 | COPY . ./ 6 | 7 | RUN pip3 install -r requirements.txt 8 | 9 | CMD exec gunicorn --bind :$PORT --workers 1 --worker-class uvicorn.workers.UvicornWorker --threads 8 app:app 10 | -------------------------------------------------------------------------------- /ML model-Backend/app.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from fastapi import FastAPI, Form 3 | import pandas as pd 4 | from starlette.responses import HTMLResponse 5 | from tensorflow.keras.preprocessing.text import Tokenizer 6 | from tensorflow.keras.preprocessing.sequence import pad_sequences 7 | import tensorflow as tf 8 | import string 9 | import re 10 | 11 | def preProcess_data(text): 12 | 13 | 14 | #cleaning the data 15 | 16 | text = text.lower() 17 | new_text = re.sub('[^a-zA-z0-9\s]','',text) 18 | new_text = re.sub('rt', '', new_text) 19 | #Hapus Tanda Baca 20 | remove = string.punctuation 21 | translator = str.maketrans(remove, ' '*len(remove)) 22 | new_text = new_text.translate(translator) 23 | #hapus ASCII dan UNICODE 24 | new_text = new_text.encode('ascii', 'ignore').decode('utf-8') 25 | new_text = re.sub(r'[^\x00-\x7f]','r',new_text) 26 | #remove newline 27 | new_text = new_text.replace('\n', ' ') 28 | 29 | return new_text 30 | 31 | app = FastAPI() 32 | 33 | data = pd.read_csv('dataset/dataset.csv') 34 | tokenizer = Tokenizer(num_words=2000, split=' ') 35 | tokenizer.fit_on_texts(data['Sentences'].values) 36 | 37 | 38 | 39 | def my_pipeline(text): #pipeline 40 | text_new = preProcess_data(text) 41 | X = tokenizer.texts_to_sequences(pd.Series(text_new).values) 42 | X = pad_sequences(X, maxlen=28) 43 | return X 44 | 45 | 46 | @app.get('/') #basic get view 47 | def basic_view(): 48 | return {"WELCOME": "GO TO /docs route, or /post or send post request to /predict "} 49 | 50 | 51 | 52 | @app.get('/predict', response_class=HTMLResponse) #data input by forms 53 | def take_inp(): 54 | return '''
55 |

APLOD sentiment analysis model

56 | 57 | 58 |

Our Knights

59 |

Muhammad Bondan Vitto Ramadhan (M0040231) - Machine Learning - Institut Teknologi Sepuluh Nopember

60 |

Muhammad Ikhwan Khalid Nasution (M0121267) - Machine Learning - Universitas Telkom

61 |

Adimas Fachri Ranunegoro (C0121288) - Cloud Computing - Universitas Telkom

62 |

Agnesia Indryany Mangopo (C0121278) - Cloud Computing - Universitas Telkom

63 |

Annisaa Utami (A2242180) - Mobile Programming (Android) - Universitas Islam Negeri Syarif Hidayatullah

64 |

Alex Lianardo (A0121283) - Mobile Programming (Android) - Universitas Telkom

65 | 66 |
''' 67 | 68 | 69 | 70 | @app.post('/predict') #prediction on data 71 | def predict(text:str = Form(...)): #input is from forms 72 | clean_text = my_pipeline(text) #cleaning and preprocessing of the texts 73 | loaded_model = tf.keras.models.load_model('model/aplod_version_2.h5') #loading the saved model 74 | predictions = loaded_model.predict(clean_text) #making predictions 75 | sentiment = int(np.argmax(predictions)) #index of maximum prediction 76 | probability = max(predictions.tolist()[0]) #probability of maximum prediction 77 | if sentiment==0: #assigning appropriate name to prediction 78 | t_sentiment = 'Negatif' 79 | elif sentiment==1: 80 | t_sentiment = 'Positif' 81 | 82 | return { #returning a dictionary as endpoint 83 | "Kalimat": text, 84 | "Sentimen": t_sentiment, 85 | "Hasil": probability 86 | } 87 | -------------------------------------------------------------------------------- /ML model-Backend/model/aplod_version_2.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/ML model-Backend/model/aplod_version_2.h5 -------------------------------------------------------------------------------- /ML model-Backend/requirements.txt: -------------------------------------------------------------------------------- 1 | sklearn 2 | fastapi 3 | pandas 4 | pydantic 5 | tensorflow==2.3.0 6 | uvicorn 7 | h5py==2.10.0 8 | python-multipart 9 | numpy==1.18.0 10 | gunicorn 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo fix no ellipse](https://user-images.githubusercontent.com/55023518/121027586-4a164d80-c7d1-11eb-9432-63b89e9af274.png) 2 | 3 | # Bangkit 2021 Capstone Team : Law's Tech Team (B21-CAP0036) 4 | 5 | Hello everyone!. Here is our repository for Bangkit 2021 Capstone project. Our team consist of 2 Machine Learning, 2 Android, and 2 Cloud Computing. 6 | 7 | 8 | ## Our Knights 9 | 10 | | Nama | Bangkit-ID | Path | 11 | |:---------------------:|:----------:|:----------------:| 12 | | Muhammad Bondan Vitto Ramadhan | M0040231 | Machine Learning | 13 | | Muhammad Ikhwan Khalid Nasution | M0121267 | Machine Learning | 14 | | Adimas Fachri Ranunegoro | C0121288 | Cloud Computing | 15 | | Agnesia Indryany Mangopo | C0121278 | Cloud Computing | 16 | | Alex Lianardo | A0121283 | Android | 17 | | Annisaa Utami | A2242180 | Android | 18 | 19 | ## What is this project 20 | We make a mobile application named **APLOD** (Aman Pesannya Let’s gO uploaD). **APLOD** is a hate speech comment detector application integrated with ITE Law. With this application, everyone can check whether a sentence contains harmful words that can violate ITE Law before uploading it to social media. We want to reduce hate comments made by Indonesian people on social media platforms such as Twitter, Instagram, etc. Hate comments not only can hurt someone but also can lead to ITE Law violation. 21 | 22 | Logo    23 | Logo    24 | Logo    25 | 26 | 27 | 28 | ## Tech Stacks 29 | 30 | ![stack](https://user-images.githubusercontent.com/55023518/121032474-7fbd3580-c7d5-11eb-9b0a-7c7ed74f8a46.jpg) 31 | 32 | ## Our Model Performance 33 | Aplod-Net has been trained on over 10.000 labeled Sentences and got 85% accuracy on test data 34 | 35 | ![Capture1](https://user-images.githubusercontent.com/56960819/121265130-7ec5fa00-c8e2-11eb-8349-10e3ec87e13e.PNG) 36 | 37 | ![Capture2](https://user-images.githubusercontent.com/56960819/121265167-8d141600-c8e2-11eb-8e88-594c43d7e334.PNG) 38 | 39 | ## Guidance for running our model on local 40 | Make sure you intalled all this dependencies first on your local machine. You can use conda virtual env for making things easier with pip 41 | ```text 42 | sklearn==0.24.2 43 | fastapi==‎0.64.0 44 | pandas==1.2.4 45 | pydantic==0.28 46 | tensorflow==2.3.0 47 | uvicorn==0.8.6 48 | h5py==2.10.0 49 | python-multipart==0.0.5 50 | numpy==1.18.0 51 | ``` 52 | 53 | For using our NLP Model, You must clone our repository first with this following command : 54 | 55 | `git clone https://github.com/aplawtech/aplod.git` 56 | 57 | after cloning the repository, go to the aplod directory and run the following command on your favorite CLI (make sure you are in /aplod directory) : 58 | 59 | ` uvicorn app:app --host=0.0.0.0 --port=${PORT:-5000} ` 60 | 61 | We already provide you all of the data set and NLP model, so you just need to run the command above 62 | 63 | You can also test our API [Here](https://aplodfix-wk452lxpxq-et.a.run.app/predict) 64 | 65 | ## Library Used in Android Application 66 | 1. [RecyclerView](https://developer.android.com/guide/topics/ui/layout/recyclerview) 67 | 2. [Lifecycle](https://developer.android.com/jetpack/androidx/releases/lifecycle) 68 | 3. [Glide](https://github.com/bumptech/glide) 69 | 4. [CircleImageView by hdodenhof](https://github.com/hdodenhof/CircleImageView) 70 | 5. [Retrofit 2](https://square.github.io/retrofit/) 71 | 6. [Material Design](https://material.io/develop/android) 72 | 73 | ## Fork Repository 74 | In order to duplicate our repository to become your repository on your own github account, you need to **fork** this repository 75 | ![image](https://user-images.githubusercontent.com/85149518/120605441-405eb400-c478-11eb-9304-4dcd1fa61a71.png)
76 | Forking repository allows you to modificate this project without affecting the original project. 77 | 78 | ## Clone Repository 79 | Download code from branch "main" **OR** 80 | 2. Clone Repository. Click on dropdown Code and **copy** HTTPS link 81 | 2. Clone Repository. Click on dropdown Code and **copy** HTTPS link
82 | ![Image Copy HTTPS](https://camo.githubusercontent.com/1c0cf8056422ff414eee75142b213c5970e085c2e33c0a6d69dc2639d98216f1/68747470733a2f2f6669727374636f6e747269627574696f6e732e6769746875622e696f2f6173736574732f526561646d652f636f70792d746f2d636c6970626f6172642e706e67) 83 | ``` 84 | git clone https://github.com/aplawtech/aplod.git 85 | ``` 86 | 87 | ### Next Step 88 | 1. Work on the project locally in your own computer 89 | 2. **Create new Branch** based on the feature you make using " git checkout -b "
90 | Example : 91 | ``` 92 | git checkout -b layout-member 93 | ``` 94 | 3. **Commit** changes to your branch. Don't forget to give proper commit message so other people can understand it
95 | Example: 96 | ``` 97 | git commit -m "add layout-member" 98 | ``` 99 | 4. **Push** to your branch
100 | Example: 101 | ``` 102 | git push origin layout-member 103 | ``` 104 | 105 | ## Project Update 106 | 107 | **TBD** 108 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-parcelize' 5 | } 6 | 7 | android { 8 | compileSdkVersion 30 9 | buildToolsVersion "30.0.3" 10 | 11 | defaultConfig { 12 | applicationId "com.lawstech.aplod" 13 | minSdkVersion 21 14 | targetSdkVersion 30 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | compileOptions { 28 | sourceCompatibility JavaVersion.VERSION_1_8 29 | targetCompatibility JavaVersion.VERSION_1_8 30 | } 31 | kotlinOptions { 32 | jvmTarget = '1.8' 33 | } 34 | buildFeatures { 35 | viewBinding true 36 | mlModelBinding true 37 | } 38 | } 39 | 40 | dependencies { 41 | 42 | //kotlin 43 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 44 | implementation 'androidx.core:core-ktx:1.3.2' 45 | 46 | //ui 47 | implementation 'androidx.appcompat:appcompat:1.2.0' 48 | implementation "com.google.android.material:material:$materialVersion" 49 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 50 | implementation 'androidx.navigation:navigation-fragment:2.3.5' 51 | implementation 'androidx.navigation:navigation-ui:2.3.5' 52 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 53 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 54 | implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' 55 | implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' 56 | 57 | //recycler 58 | implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion" 59 | implementation "com.github.bumptech.glide:glide:$glideVersion" 60 | implementation "de.hdodenhof:circleimageview:$circleImageView" 61 | implementation 'org.tensorflow:tensorflow-lite-support:0.1.0-rc1' 62 | implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0-rc1' 63 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 64 | 65 | //testing 66 | testImplementation 'junit:junit:4.+' 67 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 68 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 69 | 70 | //Retrofit 71 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 72 | implementation "com.squareup.retrofit2:converter-gson:2.9.0" 73 | implementation "com.squareup.okhttp3:logging-interceptor:4.9.0" 74 | } -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lawstech/aplod/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.lawstech.aplod", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/ic_launcher_new-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/ic_launcher_new-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod 2 | 3 | import android.os.Bundle 4 | import com.google.android.material.bottomnavigation.BottomNavigationView 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.appcompat.app.AppCompatDelegate 7 | import androidx.navigation.findNavController 8 | import androidx.navigation.ui.AppBarConfiguration 9 | import androidx.navigation.ui.setupActionBarWithNavController 10 | import androidx.navigation.ui.setupWithNavController 11 | 12 | class MainActivity : AppCompatActivity() { 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 17 | setContentView(R.layout.activity_main) 18 | val navView: BottomNavigationView = findViewById(R.id.nav_view) 19 | 20 | val navController = findNavController(R.id.nav_host_fragment) 21 | // Passing each menu ID as a set of Ids because each 22 | // menu should be considered as top level destinations. 23 | val appBarConfiguration = AppBarConfiguration( 24 | setOf( 25 | R.id.navigation_home, R.id.navigation_faq, R.id.navigation_about_us 26 | ) 27 | ) 28 | setupActionBarWithNavController(navController, appBarConfiguration) 29 | navView.setupWithNavController(navController) 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/SplashScreen.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod 2 | 3 | import android.content.Intent 4 | import androidx.appcompat.app.AppCompatActivity 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.view.Window 9 | import android.view.WindowManager 10 | import androidx.appcompat.app.AppCompatDelegate 11 | import com.lawstech.aplod.onboard.OnBoardingActivity 12 | 13 | @Suppress("DEPRECATION") 14 | class SplashScreen : AppCompatActivity() { 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | hideBar() 18 | setContentView(R.layout.activity_splash_screen) 19 | 20 | show() 21 | 22 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 23 | } 24 | 25 | 26 | private fun show(){ 27 | Handler(Looper.getMainLooper()).postDelayed({ 28 | val i = Intent(this, OnBoardingActivity::class.java) 29 | startActivity(i) 30 | finish() 31 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) 32 | }, 4000) 33 | } 34 | 35 | private fun hideBar(){ 36 | requestWindowFeature(Window.FEATURE_NO_TITLE)//will hide the title 37 | supportActionBar?.hide() //hide the title bar 38 | this.window.setFlags( 39 | WindowManager.LayoutParams.FLAG_FULLSCREEN, 40 | WindowManager.LayoutParams.FLAG_FULLSCREEN) //show the activity in full screen 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/AplodRepository.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import com.lawstech.aplod.data.source.local.entity.SentimentEntity 6 | import com.lawstech.aplod.data.source.remote.RemoteDataSource 7 | import com.lawstech.aplod.data.source.remote.response.SentimentResponse 8 | 9 | class AplodRepository private constructor(private val remoteDataSource: RemoteDataSource) : 10 | IAplodDataSource { 11 | 12 | companion object { 13 | @Volatile 14 | private var instance: AplodRepository? = null 15 | 16 | fun getInstance(remoteDataSource: RemoteDataSource): AplodRepository = 17 | instance ?: synchronized(this) { 18 | instance ?: AplodRepository(remoteDataSource).apply { instance = this } 19 | } 20 | } 21 | 22 | override fun getSentiment(kalimat: String): LiveData { 23 | val sentimentResult = MutableLiveData() 24 | remoteDataSource.getSentiment( 25 | kalimat, object : RemoteDataSource.LoadSentiment { 26 | override fun sentimentResult(sentimentResponse: SentimentResponse) { 27 | val responseResultSentiment = SentimentEntity( 28 | sentimentResponse.Kalimat, 29 | sentimentResponse.Sentimen, 30 | sentimentResponse.Hasil 31 | ) 32 | sentimentResult.postValue(responseResultSentiment) 33 | } 34 | 35 | } 36 | ) 37 | return sentimentResult 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/IAplodDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data 2 | 3 | import androidx.lifecycle.LiveData 4 | import com.lawstech.aplod.data.source.local.entity.MemberEntity 5 | import com.lawstech.aplod.data.source.local.entity.PasalEntity 6 | import com.lawstech.aplod.data.source.local.entity.SentimentEntity 7 | 8 | interface IAplodDataSource { 9 | 10 | fun getSentiment(kalimat: String): LiveData 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/local/entity/MemberEntity.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.local.entity 2 | 3 | data class MemberEntity ( 4 | var memberId: String?, 5 | var memberName: String?, 6 | var memberPath: String?, 7 | var memberUniv: String?, 8 | var memberPhoto: Int 9 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/local/entity/PasalEntity.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.local.entity 2 | 3 | data class PasalEntity ( 4 | var idPasal: Int, 5 | var namaPasal: String?, 6 | var nomorPasal: String?, 7 | var penjelasanPasal: String? 8 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/local/entity/SentimentEntity.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.local.entity 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class SentimentEntity ( 8 | var kalimat: String? = null, 9 | var sentimen: String? = null, 10 | var hasil: Double = 0.0 11 | ) : Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/remote/Api/ApiConfig.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.remote.Api 2 | 3 | import okhttp3.OkHttpClient 4 | import okhttp3.logging.HttpLoggingInterceptor 5 | import retrofit2.Retrofit 6 | import retrofit2.converter.gson.GsonConverterFactory 7 | 8 | class ApiConfig { 9 | companion object { 10 | fun getApiService(): ApiService { 11 | val loggingInterceptor = 12 | HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) 13 | val client = OkHttpClient.Builder() 14 | .addInterceptor(loggingInterceptor) 15 | .build() 16 | val retrofit = Retrofit.Builder() 17 | .baseUrl("https://aplodfix-wk452lxpxq-et.a.run.app/") 18 | .addConverterFactory(GsonConverterFactory.create()) 19 | .client(client) 20 | .build() 21 | return retrofit.create(ApiService::class.java) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/remote/Api/ApiService.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.remote.Api 2 | 3 | import com.lawstech.aplod.data.source.remote.response.SentimentResponse 4 | import retrofit2.Call 5 | import retrofit2.http.Field 6 | import retrofit2.http.FormUrlEncoded 7 | import retrofit2.http.POST 8 | 9 | interface ApiService { 10 | @FormUrlEncoded 11 | @POST("predict") 12 | fun getSentiment( 13 | @Field("text") text: String 14 | ): Call 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/remote/RemoteDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.remote 2 | 3 | import android.util.Log 4 | import com.lawstech.aplod.data.source.remote.Api.ApiConfig 5 | import com.lawstech.aplod.data.source.remote.response.SentimentResponse 6 | import com.lawstech.aplod.utils.JsonHelper 7 | import retrofit2.Call 8 | import retrofit2.Callback 9 | import retrofit2.Response 10 | 11 | class RemoteDataSource private constructor(private val jsonHelper: JsonHelper) { 12 | 13 | companion object { 14 | @Volatile 15 | private var instance: RemoteDataSource? = null 16 | 17 | fun getInstance(helper: JsonHelper): RemoteDataSource = 18 | instance ?: synchronized(this) { 19 | instance ?: RemoteDataSource(helper).apply { instance = this } 20 | } 21 | } 22 | 23 | fun getSentiment(kalimat: String, callback: LoadSentiment) { 24 | ApiConfig.getApiService().getSentiment(kalimat) 25 | .enqueue(object : Callback { 26 | override fun onResponse( 27 | call: Call, 28 | response: Response 29 | ) { 30 | if (response.isSuccessful) { 31 | response.body()?.let { callback.sentimentResult(it) } 32 | } 33 | } 34 | 35 | override fun onFailure(call: Call, t: Throwable) { 36 | Log.e("Gagal", t.toString()) 37 | } 38 | }) 39 | } 40 | 41 | interface LoadSentiment { 42 | fun sentimentResult(sentimentResponse: SentimentResponse) 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/data/source/remote/response/SentimentResponse.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.data.source.remote.response 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class SentimentResponse ( 6 | 7 | @field:SerializedName("Kalimat") 8 | val Kalimat: String, 9 | 10 | @field:SerializedName("Sentimen") 11 | val Sentimen: String, 12 | 13 | @field:SerializedName("Hasil") 14 | val Hasil: Double 15 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/onboard/OnBoardingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.onboard 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.content.SharedPreferences 7 | import androidx.appcompat.app.AppCompatActivity 8 | import android.os.Bundle 9 | import android.view.Window 10 | import android.view.WindowManager 11 | import android.widget.TextView 12 | import androidx.appcompat.app.AppCompatDelegate 13 | import androidx.viewpager.widget.ViewPager 14 | import com.google.android.material.tabs.TabLayout 15 | import com.lawstech.aplod.MainActivity 16 | import com.lawstech.aplod.R 17 | import com.lawstech.aplod.onboard.adapter.OnBoardingViewPagerAdapter 18 | import com.lawstech.aplod.onboard.onBoardModel.OnBoardingData 19 | 20 | @Suppress("DEPRECATION") 21 | class OnBoardingActivity : AppCompatActivity() { 22 | 23 | var onBoardingViewPagerAdapter: OnBoardingViewPagerAdapter? = null 24 | var tabLayout: TabLayout? = null 25 | var onBoardingViewPager: ViewPager? = null 26 | var next: TextView? = null 27 | var position = 0 28 | var sharedPreferences : SharedPreferences? = null 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | super.onCreate(savedInstanceState) 32 | hideBar() 33 | setContentView(R.layout.activity_onboarding) 34 | 35 | if(restorePrefData()){ 36 | val i=Intent(applicationContext, MainActivity::class.java) 37 | startActivity(i) 38 | finishAffinity() 39 | } 40 | 41 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 42 | 43 | onBoard() 44 | } 45 | 46 | private fun onBoard(){ 47 | tabLayout = findViewById(R.id.tab_indicator) 48 | next = findViewById(R.id.nextView) 49 | 50 | val onBoardingData: MutableList = ArrayList() 51 | onBoardingData.add(OnBoardingData("Safe yourself from the ITE Law Violation",R.drawable.handphone_gesture_1)) 52 | onBoardingData.add(OnBoardingData("Check a sentence to know whether it's safe to upload or not to social media",R.drawable.oke_gesture_2)) 53 | onBoardingData.add(OnBoardingData("Remember! Always be careful of what you say on social media!",R.drawable.careful_gesture_3)) 54 | 55 | setOnBoardingViewPagerAdapter(onBoardingData) 56 | 57 | position = onBoardingViewPager!!.currentItem 58 | 59 | next?.setOnClickListener{ 60 | if (position < onBoardingData.size){ 61 | position++ 62 | onBoardingViewPager!!.currentItem = position 63 | } 64 | if(position == onBoardingData.size){ 65 | savePrefData() 66 | val i=Intent(applicationContext, MainActivity::class.java) 67 | startActivity(i) 68 | } 69 | } 70 | 71 | tabLayout!!.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{ 72 | override fun onTabReselected(tab: TabLayout.Tab?) { 73 | } 74 | 75 | override fun onTabUnselected(tab: TabLayout.Tab?) { 76 | } 77 | 78 | @SuppressLint("SetTextI18n") 79 | override fun onTabSelected(tab: TabLayout.Tab?) { 80 | position = tab!!.position 81 | if (tab.position == onBoardingData.size - 1) { 82 | next!!.text = "Get Started" 83 | }else{ 84 | next!!.text = "Next" 85 | } 86 | } 87 | }) 88 | } 89 | 90 | private fun setOnBoardingViewPagerAdapter(onBoardingData: List) { 91 | onBoardingViewPager = findViewById(R.id.screenPager) 92 | onBoardingViewPagerAdapter = OnBoardingViewPagerAdapter(this,onBoardingData) 93 | onBoardingViewPager!!.adapter = onBoardingViewPagerAdapter 94 | tabLayout?.setupWithViewPager(onBoardingViewPager) 95 | } 96 | 97 | private fun savePrefData(){ 98 | sharedPreferences = applicationContext.getSharedPreferences("pref", Context.MODE_PRIVATE) 99 | val editor = sharedPreferences!!.edit() 100 | editor.putBoolean("isFirstTimeRun", true) 101 | editor.apply() 102 | } 103 | 104 | private fun restorePrefData(): Boolean{ 105 | sharedPreferences = applicationContext.getSharedPreferences("pref", Context.MODE_PRIVATE) 106 | return sharedPreferences!!.getBoolean("isFirstTimeRun", false) 107 | } 108 | 109 | private fun hideBar(){ 110 | requestWindowFeature(Window.FEATURE_NO_TITLE)//will hide the title 111 | supportActionBar?.hide() //hide the title bar 112 | this.window.setFlags( 113 | WindowManager.LayoutParams.FLAG_FULLSCREEN, 114 | WindowManager.LayoutParams.FLAG_FULLSCREEN) //show the activity in full screen 115 | } 116 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/onboard/adapter/OnBoardingViewPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.onboard.adapter 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.ImageView 9 | import android.widget.TextView 10 | import androidx.viewpager.widget.PagerAdapter 11 | import com.lawstech.aplod.R 12 | import com.lawstech.aplod.onboard.onBoardModel.OnBoardingData 13 | 14 | class OnBoardingViewPagerAdapter(private var context: Context, private var onBoardingData: List): PagerAdapter() { 15 | 16 | override fun getCount(): Int { 17 | return onBoardingData.size 18 | } 19 | 20 | override fun isViewFromObject(view: View, `object`: Any): Boolean { 21 | return view == `object` 22 | } 23 | 24 | override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { 25 | container.removeView(`object` as View) 26 | } 27 | 28 | @SuppressLint("InflateParams") 29 | override fun instantiateItem(container: ViewGroup, position: Int): Any { 30 | val view = LayoutInflater.from(context).inflate(R.layout.onboarding_screen_layout, null) 31 | 32 | val imageView: ImageView = view.findViewById(R.id.imageView) 33 | val desc: TextView = view.findViewById(R.id.descView) 34 | 35 | imageView.setImageResource(onBoardingData[position].image) 36 | desc.text = onBoardingData[position].desc 37 | 38 | container.addView(view) 39 | 40 | return view 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/onboard/onBoardModel/OnBoardingData.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.onboard.onBoardModel 2 | 3 | class OnBoardingData(var desc: String, var image: Int) -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/AboutUsPageAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us 2 | 3 | import android.content.Context 4 | import androidx.annotation.StringRes 5 | import androidx.fragment.app.Fragment 6 | import androidx.fragment.app.FragmentManager 7 | import androidx.fragment.app.FragmentPagerAdapter 8 | import com.lawstech.aplod.R 9 | import com.lawstech.aplod.ui.about_us.fragment.AplodAboutFragment 10 | import com.lawstech.aplod.ui.about_us.fragment.MemberFragment 11 | 12 | class AboutUsPageAdapter(private val mContext: Context, fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { 13 | 14 | companion object { 15 | @StringRes 16 | private val TAB_TITLES = intArrayOf(R.string.aplod, R.string.member) 17 | } 18 | 19 | override fun getCount(): Int = TAB_TITLES.size 20 | 21 | override fun getItem(position: Int): Fragment = 22 | when (position) { 23 | 0 -> AplodAboutFragment() 24 | 1 -> MemberFragment() 25 | else -> Fragment() 26 | } 27 | 28 | override fun getPageTitle(position: Int): CharSequence = mContext.resources.getString( 29 | TAB_TITLES[position]) 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/AboutUsViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.lawstech.aplod.data.source.local.entity.MemberEntity 5 | import com.lawstech.aplod.utils.DataDummy 6 | 7 | class AboutUsViewModel() : ViewModel() { 8 | 9 | fun getMembers(): List = DataDummy.generateDummyMembers() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/MemberAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.Glide 7 | import com.bumptech.glide.request.RequestOptions 8 | import com.lawstech.aplod.R 9 | import com.lawstech.aplod.data.source.local.entity.MemberEntity 10 | import com.lawstech.aplod.databinding.ItemMemberBinding 11 | 12 | class MemberAdapter : RecyclerView.Adapter(){ 13 | private var listMember = ArrayList() 14 | 15 | fun setMember(members: List?) { 16 | if (members == null) return 17 | this.listMember.clear() 18 | this.listMember.addAll(members) 19 | } 20 | 21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MemberViewHolder { 22 | val itemMemberBinding = ItemMemberBinding.inflate(LayoutInflater.from(parent.context), parent, false) 23 | return MemberViewHolder(itemMemberBinding) 24 | } 25 | 26 | override fun onBindViewHolder(holder: MemberViewHolder, position: Int) { 27 | val member = listMember[position] 28 | holder.bind(member) 29 | } 30 | 31 | override fun getItemCount(): Int = listMember.size 32 | 33 | class MemberViewHolder(private val binding: ItemMemberBinding) : RecyclerView.ViewHolder(binding.root) { 34 | fun bind(member: MemberEntity) { 35 | with(binding) { 36 | txtFullName.text = member.memberName 37 | txtId.text = member.memberId 38 | txtPath.text = member.memberPath 39 | 40 | Glide.with(itemView.context) 41 | .load(member.memberPhoto) 42 | .apply(RequestOptions.placeholderOf(R.drawable.ic_loading)) 43 | .error(R.drawable.ic_error) 44 | .into(imgMemberPhoto) 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/fragment/AboutUsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us.fragment 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.lawstech.aplod.databinding.FragmentAboutUsBinding 9 | import com.lawstech.aplod.ui.about_us.AboutUsPageAdapter 10 | 11 | class AboutUsFragment : Fragment() { 12 | 13 | private lateinit var fragmentAboutUsBinding: FragmentAboutUsBinding 14 | 15 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 16 | fragmentAboutUsBinding = FragmentAboutUsBinding.inflate(layoutInflater, container, false) 17 | return fragmentAboutUsBinding.root 18 | } 19 | 20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 21 | super.onViewCreated(view, savedInstanceState) 22 | val aboutUsPageAdapter = context?.let { AboutUsPageAdapter(it, this.childFragmentManager) } 23 | fragmentAboutUsBinding.viewPager.adapter = aboutUsPageAdapter 24 | fragmentAboutUsBinding.tabs.setupWithViewPager(fragmentAboutUsBinding.viewPager) 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/fragment/AplodAboutFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us.fragment 2 | 3 | import android.os.Bundle 4 | import androidx.fragment.app.Fragment 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import com.lawstech.aplod.R 9 | 10 | // TODO: Rename parameter arguments, choose names that match 11 | // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER 12 | private const val ARG_PARAM1 = "param1" 13 | private const val ARG_PARAM2 = "param2" 14 | 15 | /** 16 | * A simple [Fragment] subclass. 17 | * Use the [AplodAbouttFragment.newInstance] factory method to 18 | * create an instance of this fragment. 19 | */ 20 | class AplodAboutFragment : Fragment() { 21 | // TODO: Rename and change types of parameters 22 | private var param1: String? = null 23 | private var param2: String? = null 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | arguments?.let { 28 | param1 = it.getString(ARG_PARAM1) 29 | param2 = it.getString(ARG_PARAM2) 30 | } 31 | } 32 | 33 | override fun onCreateView( 34 | inflater: LayoutInflater, container: ViewGroup?, 35 | savedInstanceState: Bundle? 36 | ): View? { 37 | // Inflate the layout for this fragment 38 | return inflater.inflate(R.layout.fragment_about_aplod, container, false) 39 | } 40 | 41 | companion object { 42 | /** 43 | * Use this factory method to create a new instance of 44 | * this fragment using the provided parameters. 45 | * 46 | * @param param1 Parameter 1. 47 | * @param param2 Parameter 2. 48 | * @return A new instance of fragment AplodAbouttFragment. 49 | */ 50 | // TODO: Rename and change types and number of parameters 51 | @JvmStatic 52 | fun newInstance(param1: String, param2: String) = 53 | AplodAboutFragment().apply { 54 | arguments = Bundle().apply { 55 | putString(ARG_PARAM1, param1) 56 | putString(ARG_PARAM2, param2) 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/about_us/fragment/MemberFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.about_us.fragment 2 | 3 | import android.os.Bundle 4 | import androidx.fragment.app.Fragment 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.lifecycle.ViewModelProvider 9 | import androidx.recyclerview.widget.LinearLayoutManager 10 | import com.lawstech.aplod.databinding.FragmentMemberBinding 11 | import com.lawstech.aplod.ui.about_us.AboutUsViewModel 12 | import com.lawstech.aplod.ui.about_us.MemberAdapter 13 | import com.lawstech.aplod.utils.DataDummy 14 | 15 | class MemberFragment : Fragment() { 16 | 17 | private lateinit var viewModel: AboutUsViewModel 18 | private var _fragmentMemberBinding: FragmentMemberBinding? = null 19 | private val binding get() = _fragmentMemberBinding 20 | 21 | private lateinit var adapter: MemberAdapter 22 | 23 | override fun onCreateView( 24 | inflater: LayoutInflater, container: ViewGroup?, 25 | savedInstanceState: Bundle? 26 | ): View? { 27 | // Inflate the layout for this fragment 28 | _fragmentMemberBinding = FragmentMemberBinding.inflate(inflater, container, false) 29 | return binding?.root 30 | } 31 | 32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 33 | super.onViewCreated(view, savedInstanceState) 34 | if (activity != null) { 35 | viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[AboutUsViewModel::class.java] 36 | val members = viewModel.getMembers() 37 | 38 | adapter = MemberAdapter() 39 | adapter.setMember(members) 40 | 41 | binding?.rvMember?.layoutManager = LinearLayoutManager(context) 42 | binding?.rvMember?.setHasFixedSize(true) 43 | binding?.rvMember?.adapter = adapter 44 | } 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/di/Injection.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.di 2 | 3 | import android.content.Context 4 | import com.lawstech.aplod.data.AplodRepository 5 | import com.lawstech.aplod.data.source.remote.RemoteDataSource 6 | import com.lawstech.aplod.utils.JsonHelper 7 | 8 | object Injection { 9 | fun provideRepository(context: Context): AplodRepository { 10 | 11 | val remoteDataSource = RemoteDataSource.getInstance(JsonHelper(context)) 12 | 13 | return AplodRepository.getInstance(remoteDataSource) 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/faq/FaqAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.faq 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.lawstech.aplod.data.source.local.entity.PasalEntity 7 | import com.lawstech.aplod.databinding.ItemPasalBinding 8 | 9 | class FaqAdapter : RecyclerView.Adapter() { 10 | private var listPasal = ArrayList() 11 | 12 | fun setPasal(pasal: List?) { 13 | if (pasal == null) return 14 | this.listPasal.clear() 15 | this.listPasal.addAll(pasal) 16 | } 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FaqAdapter.PasalViewHolder { 19 | val itemPasalBinding = ItemPasalBinding.inflate(LayoutInflater.from(parent.context), parent, false) 20 | return PasalViewHolder(itemPasalBinding) 21 | } 22 | 23 | override fun onBindViewHolder(holder: FaqAdapter.PasalViewHolder, position: Int) { 24 | val pasal = listPasal[position] 25 | holder.bind(pasal) 26 | } 27 | 28 | override fun getItemCount(): Int = listPasal.size 29 | 30 | class PasalViewHolder(private val binding: ItemPasalBinding) : RecyclerView.ViewHolder(binding.root) { 31 | fun bind(pasal: PasalEntity) { 32 | with(binding) { 33 | txtNamaPasal.text = pasal.namaPasal 34 | txtNomorPasal.text = pasal.nomorPasal 35 | txtPenjelasanPasal.text = pasal.penjelasanPasal 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/faq/FaqFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.faq 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.lifecycle.ViewModelProvider 9 | import androidx.recyclerview.widget.LinearLayoutManager 10 | import com.lawstech.aplod.databinding.FragmentFaqBinding 11 | 12 | class FaqFragment : Fragment() { 13 | 14 | private lateinit var faqViewModel: FaqViewModel 15 | private lateinit var fragmentFaqBinding: FragmentFaqBinding 16 | 17 | override fun onCreateView( 18 | inflater: LayoutInflater, 19 | container: ViewGroup?, 20 | savedInstanceState: Bundle? 21 | ): View { 22 | fragmentFaqBinding = FragmentFaqBinding.inflate(layoutInflater, container, false) 23 | return fragmentFaqBinding.root 24 | } 25 | 26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 27 | super.onViewCreated(view, savedInstanceState) 28 | if (activity != null) { 29 | faqViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[FaqViewModel::class.java] 30 | val pasal = faqViewModel.getPasal() 31 | 32 | val pasalAdapter = FaqAdapter() 33 | pasalAdapter.setPasal(pasal) 34 | 35 | with(fragmentFaqBinding.rvPasal) { 36 | layoutManager = LinearLayoutManager(context) 37 | setHasFixedSize(true) 38 | adapter = pasalAdapter 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/faq/FaqViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.faq 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.lawstech.aplod.data.source.local.entity.PasalEntity 5 | import com.lawstech.aplod.utils.DataDummy 6 | 7 | class FaqViewModel : ViewModel() { 8 | 9 | fun getPasal(): List = DataDummy.generateDummyPasal() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/home/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.home 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.os.Bundle 7 | import android.text.Editable 8 | import android.text.TextWatcher 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.view.inputmethod.InputMethodManager 13 | import androidx.core.app.ShareCompat 14 | import androidx.fragment.app.Fragment 15 | import androidx.lifecycle.ViewModelProvider 16 | import com.lawstech.aplod.databinding.FragmentHomeBinding 17 | import com.lawstech.aplod.viewmodel.ViewModelFactory 18 | import java.util.* 19 | 20 | 21 | class HomeFragment : Fragment() { 22 | 23 | private lateinit var homeViewModel: HomeViewModel 24 | private lateinit var fragmentHomeBinding: FragmentHomeBinding 25 | private lateinit var kalimat: String 26 | 27 | override fun onCreateView( 28 | inflater: LayoutInflater, 29 | container: ViewGroup?, 30 | savedInstanceState: Bundle? 31 | ): View { 32 | fragmentHomeBinding = FragmentHomeBinding.inflate(layoutInflater, container, false) 33 | return fragmentHomeBinding.root 34 | } 35 | 36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 37 | super.onViewCreated(view, savedInstanceState) 38 | 39 | checkValidationToSend() 40 | 41 | fragmentHomeBinding.btnCheck.setOnClickListener { 42 | checkSentiment() 43 | } 44 | 45 | fragmentHomeBinding.btnSend.setOnClickListener { 46 | onShareClick() 47 | } 48 | } 49 | 50 | private fun onShareClick() { 51 | kalimat = fragmentHomeBinding.inputComment.text.toString() 52 | if (activity != null) { 53 | val mimeType = "text/plain" 54 | ShareCompat.IntentBuilder 55 | .from(requireActivity()) 56 | .setType(mimeType) 57 | .setChooserTitle("Bagikan aplikasi ini sekarang.") 58 | .setText(kalimat) 59 | .startChooser() 60 | } 61 | } 62 | 63 | @SuppressLint("SetTextI18n") 64 | private fun checkSentiment() { 65 | hideKeyboard() 66 | 67 | kalimat = fragmentHomeBinding.inputComment.text.toString() 68 | 69 | val labelTiga = arrayOf("pemerintah","pemerintahan","KPK", "polisi", "pejabat", "dpr", "presiden", "jokowi", "anies") 70 | val labelEmpat = arrayOf("kamu", "dia", "seperti") 71 | val labelLima = arrayOf("bunuh", "laporin", "hancur", "kubunuh", "sebarin", "menyebarkan","bongkar", "hilang", "bom") 72 | val labelEnam = arrayOf("kristen", "islam", "buddha", "konghucu", "budha", "hindu","katolik", "agama", "arab", "cina") 73 | 74 | if (kalimat.isEmpty()){ 75 | fragmentHomeBinding.progressBar.visibility = View.INVISIBLE 76 | } 77 | else{ 78 | fragmentHomeBinding.progressBar.visibility = View.VISIBLE 79 | } 80 | 81 | val factory = ViewModelFactory.getInstance(requireContext()) 82 | homeViewModel = ViewModelProvider(this, factory)[HomeViewModel::class.java] 83 | 84 | homeViewModel.getSentiment(kalimat).observe(viewLifecycleOwner, { sentiment -> 85 | fragmentHomeBinding.tvSentimen.text = sentiment.sentimen.toString() 86 | when (fragmentHomeBinding.tvSentimen.text) { 87 | "Negatif" -> { 88 | 89 | fragmentHomeBinding.imgNotOk.visibility = View.VISIBLE 90 | fragmentHomeBinding.kataKasarDetected.visibility = View.VISIBLE 91 | fragmentHomeBinding.progressBar.visibility = View.INVISIBLE 92 | 93 | for (badWords in labelTiga.indices){ 94 | val badWord = labelTiga[badWords] 95 | if (kalimat.toLowerCase(Locale.ROOT).contains(badWord)){ 96 | visibleLanggarPasal(true) 97 | fragmentHomeBinding.undangUndang.text = "Menghina Pemerintah atau Badan Umum : Pasal 207 KUHP & Pasal 208 KUHP" 98 | } 99 | } 100 | for (badWords in labelEmpat.indices){ 101 | val badWord = labelEmpat[badWords] 102 | if (kalimat.toLowerCase(Locale.ROOT).contains(badWord)){ 103 | visibleLanggarPasal(true) 104 | fragmentHomeBinding.undangUndang.text = "Menghina atau Mencemari Nama Baik Orang Lain : Pasal 27 ayat (3) UU ITE" 105 | } 106 | } 107 | for (badWords in labelLima.indices){ 108 | val badWord = labelLima[badWords] 109 | if (kalimat.toLowerCase(Locale.ROOT).contains(badWord)){ 110 | visibleLanggarPasal(true) 111 | fragmentHomeBinding.undangUndang.text = "Mengancam Orang Lain : Pasal 29 UU ITE" 112 | } 113 | } 114 | for (badWords in labelEnam.indices){ 115 | val badWord = labelEnam[badWords] 116 | if (kalimat.toLowerCase(Locale.ROOT).contains(badWord)){ 117 | visibleLanggarPasal(true) 118 | fragmentHomeBinding.undangUndang.text = "Menyinggung SARA : Pasal 28 ayat (2) UU ITE" 119 | } 120 | } 121 | } 122 | "Positif" -> { 123 | visibleLanggarPasal(false) 124 | } 125 | "Netral" -> { 126 | visibleLanggarPasal(false) 127 | } 128 | else -> { 129 | visibleLanggarPasal(false) 130 | } 131 | } 132 | }) 133 | } 134 | 135 | private fun checkValidationToSend(){ 136 | fragmentHomeBinding.inputComment.addTextChangedListener(object : TextWatcher 137 | { 138 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 139 | 140 | } 141 | 142 | override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 143 | fragmentHomeBinding.imgNotOk.visibility = View.INVISIBLE 144 | fragmentHomeBinding.imgOk.visibility = View.INVISIBLE 145 | fragmentHomeBinding.tvAman.visibility = View.INVISIBLE 146 | fragmentHomeBinding.kataKasarDetected.visibility = View.INVISIBLE 147 | fragmentHomeBinding.langgarPasalDetected.visibility = View.INVISIBLE 148 | fragmentHomeBinding.pasalCard.visibility = View.INVISIBLE 149 | fragmentHomeBinding.btnSend.visibility = View.INVISIBLE 150 | fragmentHomeBinding.progressBar.visibility = View.INVISIBLE 151 | fragmentHomeBinding.undangUndang.visibility = View.INVISIBLE 152 | } 153 | 154 | override fun afterTextChanged(p0: Editable?) { 155 | } 156 | }) 157 | } 158 | 159 | private fun Fragment.hideKeyboard() { 160 | view?.let { activity?.hideKeyboard(it) } 161 | } 162 | 163 | private fun Context.hideKeyboard(view: View) { 164 | val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager 165 | inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) 166 | } 167 | 168 | private fun visibleLanggarPasal(state: Boolean) { 169 | if (state) { 170 | fragmentHomeBinding.imgNotOk.visibility = View.VISIBLE 171 | fragmentHomeBinding.kataKasarDetected.visibility = View.VISIBLE 172 | fragmentHomeBinding.langgarPasalDetected.visibility = View.VISIBLE 173 | fragmentHomeBinding.pasalCard.visibility = View.VISIBLE 174 | fragmentHomeBinding.undangUndang.visibility = View.VISIBLE 175 | } else { 176 | fragmentHomeBinding.progressBar.visibility = View.INVISIBLE 177 | fragmentHomeBinding.imgOk.visibility = View.VISIBLE 178 | fragmentHomeBinding.tvAman.visibility = View.VISIBLE 179 | fragmentHomeBinding.btnSend.visibility = View.VISIBLE 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/home/HomeFragmentCallback.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.home 2 | 3 | interface HomeFragmentCallback { 4 | fun onShareClick() 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/ui/home/HomeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.ui.home 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.ViewModel 5 | import com.lawstech.aplod.data.AplodRepository 6 | import com.lawstech.aplod.data.source.local.entity.SentimentEntity 7 | 8 | class HomeViewModel(private val mAplodRepository: AplodRepository) : ViewModel() { 9 | 10 | fun getSentiment(kalimat: String): LiveData = 11 | mAplodRepository.getSentiment(kalimat) 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/utils/DataDummy.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.utils 2 | 3 | import com.lawstech.aplod.R 4 | import com.lawstech.aplod.data.source.local.entity.MemberEntity 5 | import com.lawstech.aplod.data.source.local.entity.PasalEntity 6 | 7 | object DataDummy { 8 | 9 | fun generateDummyMembers(): ArrayList { 10 | val members = ArrayList() 11 | 12 | members.add(MemberEntity( 13 | "C0121288", 14 | "Adimas Fachri Ranunegoro", 15 | "Cloud Computing", 16 | "Universitas Telkom Bandung", 17 | R.drawable.fachri 18 | )) 19 | members.add( 20 | MemberEntity( 21 | "C0121278", 22 | "Agnesia Indryany Mangopo", 23 | "Cloud Computing", 24 | "Universitas Telkom Bandung", 25 | R.drawable.agnes 26 | )) 27 | members.add(MemberEntity( 28 | "A0121283", 29 | "Alex Lianardo", 30 | "Mobile Development", 31 | "Universitas Telkom Bandung", 32 | R.drawable.alex 33 | )) 34 | members.add(MemberEntity( 35 | "A2242180", 36 | "Annisaa Utami", 37 | "Mobile Development", 38 | "UIN Syarif Hidayatullah Jakarta", 39 | R.drawable.icha 40 | )) 41 | members.add(MemberEntity( 42 | "M0040231", 43 | "Muhammad Bondan Vitto Ramadhan", 44 | "Machine Learning", 45 | "Institut Teknologi Sepuluh Nopember Surabaya", 46 | R.drawable.bondan 47 | )) 48 | members.add(MemberEntity( 49 | "M0121267", 50 | "Muhammad Ikhwan Khalid Nasution", 51 | "Machine Learning", 52 | "Universitas Telkom Bandung", 53 | R.drawable.ikhwan 54 | )) 55 | 56 | return members 57 | } 58 | 59 | fun generateDummyPasal(): ArrayList { 60 | val pasal = ArrayList() 61 | 62 | pasal.add( 63 | PasalEntity( 64 | 1, 65 | "Menghina Pemerintah atau Badan Umum", 66 | "Pasal 207 KUHP", 67 | "Barang siapa dengan sengaja di muka umum dengan lisan atau tulisan menghina suatu penguasa atau badan umum yang ada di Indonesia, diancam dengan pidana penjara paling lama satu tahun enam bulan atau pidana denda paling banyak empat ribu lima ratus rupiah." 68 | )) 69 | pasal.add( 70 | PasalEntity( 71 | 2, 72 | "Menghina Pemerintah atau Badan Umum", 73 | "Pasal 208 KUHP", 74 | "Barang siapa menyiapkan, mempertontonkan atau menempelkan tulisan atau gambar yang isinya penghinaan bagi sesuatu kekuasaan yang ada di Negara Indonesia atau bagi sesuatu mejelis umum yang ada di sana, dengan niat supaya isi yang menghina itu diketahui oleh orang banyak atau lebih diketahui oleh orang banyak, di hukum penjara paling lama 4 bulan atau denda sebanyak Rp 4.500.000." 75 | )) 76 | pasal.add( 77 | PasalEntity( 78 | 3, 79 | "Menghina atau Mencemari Nama Baik Orang Lain", 80 | "Pasal 27 ayat (3) UU ITE", 81 | "Setiap Orang dengan sengaja dan tanpa hak mendistribusikan dan/atau mentransmisikan dan/atau membuat dapat diaksesnya Informasi Elektronik dan/atau Dokumen Elektronik yang memiliki muatan penghinaan dan/atau pencemaran nama baik.” Perbuatan tersebut diancam pidana penjara paling lama 4 (empat) tahun dan/atau denda paling banyak 750 juta Rupiah." 82 | )) 83 | pasal.add( 84 | PasalEntity( 85 | 4, 86 | "Mengancam Orang Lain", 87 | "Pasal 29 UU ITE", 88 | "Setiap Orang dengan sengaja dan tanpa hak mengirimkan Informasi Elektronik dan/atau Dokumen Elektronik yang berisi ancaman kekerasan atau menakut-nakuti yang ditujukan secara pribadi.” Perbuatan tersebut diancam pidana penjara paling lama 4 (empat) tahun dan/atau denda paling banyak Rp750 juta." 89 | )) 90 | pasal.add( 91 | PasalEntity( 92 | 5, 93 | "Menyinggung SARA", 94 | "Pasal 28 ayat (2) UU ITE", 95 | "Setiap Orang dengan sengaja dan tanpa hak menyebarkan informasi yang ditujukan untuk menimbulkan rasa kebencian atau permusuhan individu dan/atau kelompok masyarakat tertentu berdasarkan atas suku, agama, ras, dan antargolongan (SARA).” Perbuatan tersebut diancam pidana penjara paling lama 6 (enam) tahun dan/atau denda paling banyak 1 Miliar Rupiah." 96 | )) 97 | 98 | return pasal 99 | } 100 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/utils/JsonHelper.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.utils 2 | 3 | import android.content.Context 4 | 5 | import org.json.JSONException 6 | import org.json.JSONObject 7 | import java.io.IOException 8 | 9 | class JsonHelper(private val context: Context) { 10 | 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lawstech/aplod/viewmodel/ViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package com.lawstech.aplod.viewmodel 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.ViewModelProvider 6 | import com.lawstech.aplod.data.AplodRepository 7 | import com.lawstech.aplod.ui.di.Injection 8 | import com.lawstech.aplod.ui.home.HomeViewModel 9 | 10 | class ViewModelFactory private constructor(private val mAplodRepository: AplodRepository) : ViewModelProvider.NewInstanceFactory() { 11 | 12 | companion object { 13 | @Volatile 14 | private var instance: ViewModelFactory? = null 15 | 16 | fun getInstance(context: Context): ViewModelFactory = 17 | instance ?: synchronized(this) { 18 | instance ?: ViewModelFactory(Injection.provideRepository(context)).apply { 19 | instance = this 20 | } 21 | } 22 | } 23 | 24 | @Suppress("UNCHECKED_CAST") 25 | override fun create(modelClass: Class): T { 26 | when { 27 | modelClass.isAssignableFrom(HomeViewModel::class.java) -> { 28 | return HomeViewModel(mAplodRepository) as T 29 | } 30 | else -> throw Throwable("Unknown ViewModel class: " + modelClass.name) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/res/color/nav_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/background_ungu_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/background_ungu_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/bg_recyclerview_item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/bg_recyclerview_item.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/careful_gesture_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/careful_gesture_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/handphone_gesture_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/handphone_gesture_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/hate_speech.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/hate_speech.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/indicator_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/law_tech.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/law_tech.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/oke_gesture_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable-v24/oke_gesture_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/unselected.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/agnes.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/agnes.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/alex.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/alex.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/bondan.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/bondan.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/fachri.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/fachri.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/home_fragment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/home_fragment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_bookmark.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_home_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_people_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_question_answer_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_refresh_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_share.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_broken_image.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dashboard_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_purple_wave.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_purple_wave2.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/icha.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ikhwan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/ikhwan.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo_fix_no_ellipse_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/logo_fix_no_ellipse_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/not_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/not_ok.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/ok.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ok_hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/ok_hand.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/paper_plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/paper_plane.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/paper_plane_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/drawable/paper_plane_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/font/poppins_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/font/poppins_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aplawtech/aplod/5b07cff5811a387eec99f5493a27dff13ef78bd1/app/src/main/res/font/poppins_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 23 | 24 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_onboarding.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 20 | 21 | 33 | 34 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 31 | 32 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about_aplod.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 24 | 25 | 40 | 41 | 58 | 59 | 74 | 75 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about_us.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_faq.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | 37 | 38 | 50 | 51 | 52 |