Membuat Aplikasi Android Sistem Informasi DesaKu - Part 18
Aplikasi Android Sistem Informasi Desaku ini merupakan Tutorial Part 18, jadi jika anda belum mengikuti Tutorial Part 17 diharapkan anda untuk mengikuti Tutorial Part 17 dahulu untuk memudahkan anda dalam memahami Tutorial Part 18 ini.
Pada Tutorial Part 17 sebelumnya kita membuat Folder Page
dan juga menambahkan File Component disertai dengan penambahan code kemudian kita juga telah melakukan testing langsung melihat hasil dari perubahan code ke aplikasi android dengan menjalankan server debug
. Pada Tutorial Part 18 ini kita akan melakukan perubahan code pada file Admin_Artikel_DesaKu.js
Baiklah sekarang buka folder project yaitu DesaKu
dengan menggunakan Visual Studio Code

Sekarang buka file Admin_Artikel_DesaKu.js
yang ada di folder src/screen/page
.

Kemudian sekarang lakukan perubahan code pada code import component dari react-native
- Awal code seperti ini
import {
View,
Text,
} from 'react-native'
Perubahan Code seperti ini
import {
View,
Text,
StyleSheet,
Image,
StatusBar,
YellowBox,
TouchableOpacity,
FlatList,
ActivityIndicator,
RefreshControl,
Linking
} from 'react-native'

Setelah itu lakukan penambahan code pada code constructor
seperti berikut
constructor(props) {
super(props);
this.state = {
data:[],
isLoding: true,
refreshing: false
}
}

Kemudian kita akan membuat sebuah function, function adalah digunakan untuk membungkus program menjadi bagian-bagian kecil. Buat dan letakan function
setelah code constructor
.
Admin_List_Artikel_DesaKu = () =>{
return fetch('https://sisteminformasidesaku.000webhostapp.com/api/Artikel_DesaKu/list_artikel_desaku.php')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
this.setState({
isLoding:false,
data: responseJson
})
})
}

Kemudian tambahkan code componentDidMount
agar function nya dijalan otomatis ketika aplikasi dijalankan pada saat awal buka aplikasinya dan letakan code ini setelah code Function
.
componentDidMount(){
this.Admin_List_Artikel_DesaKu()
}

Setelah membuat sebuah fucntion componentDidMount
seperti berikut codenya
FlatListItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}

Setelah membuat sebuah fucntion _onRefresh
seperti berikut codenya.
_onRefresh(){
this.setState({refreshing: true}) ;
this.Admin_List_Artikel_DesaKu().then(() => {
this.setState({
refreshing: false
})
})
}

Setelah membuat sebuah fucntion ListEmptyView
seperti berikut codenya.
ListEmptyView = (isLoading = this.state.isLoading) => {
if (isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}else{
return (
<View>
<Text style={{textAlign: 'center'}}> Tidak Ada Data.</Text>
</View>
);
}
}

Setelah membuat sebuah fucntion renderItems
seperti berikut codenya.
renderItems = ({ item }) => {
const { id, title_artikel_desaku, tanggal_post_artikel_desaku, photo_artikel_desaku} = item
return (
<View style={styles.containerList}>
<View style={styles.conGambar}>
<Image source={{ uri: photo_artikel_desaku }} style={styles.gmbr} />
</View>
<View style={styles.note}>
<Text style={styles.Judul}>{title_artikel_desaku}</Text>
<Text style={styles.tgl}>{tanggal_post_artikel_desaku}</Text>
</View>
</View>
)
}

Kemudian tambahkan code FlatList
pada retrun
, dan untuk posisinya anda bisa lihat digambar dibawah ini kemudian berikut code nya.
<View style={styles.maincontainer}>
<View style={styles.header}>
<Text style={styles.textHeader}>Artikel DesaKu</Text>
<Text style={styles.textHeader}>Logout</Text>
</View>
<FlatList
data={this.state.data}
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.toString()}
renderItem={this.renderItems}
ListEmptyComponent={this.ListEmptyView}
refreshControl={
<RefreshControl refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
/>
</View>

Kemudian tambahkan code styling berikut sebelum code export default
const styles = StyleSheet.create({
maincontainer:{
flex:1
},
containerList:{
margin:5,
backgroundColor:'#009688',
flexDirection:'row',
borderRadius: 15
},
gmbr:{
height: 100,
width: 100,
resizeMode:"center",
borderRadius: 20
},
conGambar:{
alignItems: 'center',
width: 120,
justifyContent:'center',
},
note:{
width: 220,
},
Judul:{
fontSize: 18,
fontWeight:'bold',
color:'#fff'
},
tgl:{
fontSize: 13,
color:'#fff'
},
Title:{
flexDirection:'row',
justifyContent:'space-between'
},
jdlTitle:{
fontSize:20,
fontWeight:'bold'
},
header:{
height: 40,
width: '100%',
backgroundColor: '#009688',
alignItems:'center',
justifyContent:'center',
flexDirection:'row',
justifyContent:'space-between',
},
textHeader:{
fontSize: 20,
color:'#fff',
fontWeight:'bold',
marginLeft: 10,
marginRight: 10
}
})
Kemudian sekarang akan menambahkan Button Floating
dengan cara menginstall library berikut ini. Saya harap ada bisa menginstall library atau jika bisa anda harus baca lagi Tutorial Part Sebelumnya.
sudo npm install --save react-native-action-button
sudo npm install --save react-native-vector-icons
sudo npm install --save react-native-modalbox@latest
Jika proses install selesai sekarang tambahkan import component berikut ini kedalam file Admin_Artikel_DesaKu.js
.
import ActionButton from 'react-native-action-button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Modal from 'react-native-modalbox';

Setelah itu tambahkan code berikut ini kedalam file android/app/build.gradle
kemudian jangan lupa untuk melakukan react-native run-android
.
project.ext.vectoricons = [
iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ] // Name of the font files you want to copy
]
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

Kemudian tambahkan berikuti dibagian return dibawah Flatlist
.
<ActionButton buttonColor="rgba(231,76,60,1)">
<ActionButton.Item buttonColor='#1abc9c' title="Add Artikel DesaKu" onPress={() => this.refs.modal7.open()}>
<Icon name="note-add" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
Setelah itu tambahkan code ini dibagian styles
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},

Kemudian tambahkan code ini kedalam constructor
isOpen: false,
isDisabled: false,
swipeToClose: true,
sliderValue: 0.3

Setalah itu tambahkan code berikut ini setelah constructor
onClose() {
console.log('Modal just closed');
}
onOpen() {
console.log('Modal just opened');
}
onClosingState(state) {
console.log('the open/close of the swipeToClose just changed');
}
renderList() {
var list = [];
for (var i=0;i<50;i++) {
list.push(<Text style={styles.text} key={i}>Elem {i}</Text>);
}
return list;
}

Kemudian tambahkan code di antara render
dan retrun
var BContent = (
<View style={[styles.btn, styles.btnModal]}>
<Text style= {{ color: '#fff'}} onPress={() => this.setState({isOpen: false})}>X</Text>
</View>
);

Kemudian tambahkan code Modal
berikut ini setelah ActionButon
<Modal style={[styles.modal, styles.modal3]} position={"center"} ref={"modal3"} isDisabled={this.state.isDisabled}>
<View>
<View style={styles.MainContainer}>
<Text style={{ fontSize: 25, textAlign: 'center', marginBottom: 7 }}> Tambah Artikel DesaKu </Text>
</View>
</View>
</Modal>

Setelah itu tambahkan code styling berikut ini di variabel styles
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},
modal3: {
flex: 1,
backgroundColor: '#F0FFFF',
marginTop: 10,
marginBottom: 30,
marginLeft: 5,
marginRight: 10,
width: '90%',
borderRadius: 30
},
MainContainer: {
alignItems: 'center',
justifyContent: 'center'
},

Kemudian kitakan menginstall 2 library yaitu rn-fetch-blob
dan react-native-image-picker
sudo npm install --save rn-fetch-blob
sudo npm install --save react-native-image-picker
Setelah menginstall kedua library tersebut, langkah selanjutnya ada menjalankan perintah berikut ini.
react-native link
RNFB_ANDROID_PERMISSIONS=true react-native link rn-fetch-blob
Setelah itu lakukan install ulang aplikasi Debug
dengan menjalankan perintah berikut ini.
react-native run-android
Kemudian Import
kedua library tersebut kedalam file Admin_Artikel_DesaKu.js
import ImagePicker from 'react-native-image-picker';
import RNFetchBlob from 'rn-fetch-blob';
Setelah itu tambahkan import
component berikut ini.
TextInput,
PixelRatio
Dan tambahkan code pada constructor
ImageSource: null,
data: null,
title_artikel_desaku : ''
tanggal_post_artikel_desaku:''
penjelasan_artikel_desaku: ''

Kemudian tambahkan code berikuti ini setelah code constructor
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true
}
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
let source = { uri: response.uri };
this.setState({
ImageSource: source,
data: response.data
});
}
});
}

Jangan lupa buat folder uploads
dan tambakan code pada file tambah_artikel_desaku.php
yang berada di folder Artikel_DesaKu
di web https://files.000webhost.com/
<?php
//Define your host here.
$hostname = "localhost";
//Define your database User Name here.
$username = "id11934325_desaku";
//Define your database Password here.
$password = "Mikrotik@122";
//Define your Database Name here.
$dbname = "id11934325_desaku";
$conn = mysqli_connect($hostname, $username, $password, $dbname);
//mysql_select_db($dbname, $conn);
// Type your website name or domain name here.
$domain_name = "https://sisteminformasidesaku.000webhostapp.com/api/Artikel_DesaKu" ;
// Image uploading folder.
$penjelasan_artikel_desaku = "uploads/";
// Generating random image name each time so image name will not be same .
$penjelasan_artikel_desaku = $penjelasan_artikel_desaku . "/" .rand() . "_" . time() . ".jpeg";
// Receiving image tag sent from application.
$title_artikel_desaku = $_POST["title_artikel_desaku"];
$tanggal_post_artikel_desaku = $_POST["tanggal_post_artikel_desaku"];
$photo_artikel_desaku = $_POST["photo_artikel_desaku"];
$CheckSQL = "SELECT * FROM Artikel_DesaKu WHERE title_artikel_desaku='$title_artikel_desaku'";
// Executing SQL Query.
$check = mysqli_fetch_array(mysqli_query($conn,$CheckSQL));
// if( empty($title_artikel_desaku) || empty($tanggal_post_artikel_desaku) || empty($penjelasan_artikel_desaku)){
// $EmptyFormMessage = 'Pastikan Form Terisi...!';
// $EmptyFormJson = json_encode($EmptyFormMessage);
// echo $EmptyFormJson ;
// }
// else{
if(isset($check)){
$titleArtikelExistMSG = 'Data Sudah Ada !!!';
// Converting the message into JSON format.
$titleArtikelExistJson = json_encode($titleArtikelExistMSG);
// Echo the message.
echo $titleArtikelExistJson ;
}else{
// Receiving image sent from Application
if(move_uploaded_file($_FILES['image']['tmp_name'], $penjelasan_artikel_desaku)){
// Adding domain name with image random name.
$penjelasan_artikel_desaku = $domain_name . $penjelasan_artikel_desaku ;
$Sql_Query = "insert into Artikel_DesaKu ( title_artikel_desaku, tanggal_post_artikel_desaku, photo_artikel_desaku, penjelasan_artikel_desaku) VALUES('$title_artikel_desaku' , '$tanggal_post_artikel_desaku', '$photo_artikel_desaku', '$penjelasan_artikel_desaku')";
if(mysqli_query($conn,$Sql_Query)){
$MESSAGE = "Artikel Sukses Ditambahkan" ;
echo json_encode($MESSAGE);
}
else{
echo 'Please Try Again !!! ';
}
mysqli_close($conn);
}
}
// }
?>
Kemudian tambahan code ini pada file Tambah_Artikel_DesaKu.js
.
signOut =() =>{
AsyncStorage.removeItem('admin')
this.props.navigation.navigate('Auth')
}

Tambahkan code TouchableOpacity
pada TEXT
logout
<TouchableOpacity onPress={() => this.signOut()}>
<Text style={styles.textHeader}>Logout</Text>
</TouchableOpacity>

Berikut Code Lengkap File Admin_Artikel_DesaKu.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
Image,
StatusBar,
YellowBox,
TouchableOpacity,
FlatList,
ActivityIndicator,
RefreshControl,
Linking,
TextInput,
PixelRatio,
ScrollView,
AsyncStorage
} from 'react-native'
import ActionButton from 'react-native-action-button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Modal from 'react-native-modalbox';
import ImagePicker from 'react-native-image-picker';
import RNFetchBlob from 'rn-fetch-blob';
class Admin_Artikel_DesaKu extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoding: true,
refreshing: false,
isOpen: false,
isDisabled: false,
swipeToClose: true,
sliderValue: 0.3,
ImageSource: null,
data: null,
title_artikel_desaku: '',
tanggal_post_artikel_desaku: '',
photo_artikel_desaku: '',
}
}
signOut =() =>{
AsyncStorage.removeItem('admin')
this.props.navigation.navigate('Auth')
}
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true
}
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
let source = { uri: response.uri };
this.setState({
ImageSource: source,
data: response.data
});
}
});
}
uploadImageToServer = () => {
RNFetchBlob.fetch('POST', 'https://sisteminformasidesaku.000webhostapp.com/api/Artikel_DesaKu/tambah_artikel_desaku.php', {
Authorization: "Bearer access-token",
otherHeader: "foo",
'Content-Type': 'multipart/form-data',
}, [
{ name: 'image', filename: 'image.png', type: 'image/png', data: this.state.data },
{ name: 'title_artikel_desaku', data: this.state.title_artikel_desaku },
{ name: 'tanggal_post_artikel_desaku', data: this.state.tanggal_post_artikel_desaku },
{ name: 'photo_artikel_desaku', data: this.state.photo_artikel_desaku },
]).then((resp) => {
var tempMSG = resp.data;
tempMSG = tempMSG.replace(/^"|"$/g, '');
alert(tempMSG);
}).catch((error) => {
console.error(error)
})
}
onClose() {
console.log('Modal just closed');
}
onOpen() {
console.log('Modal just opened');
}
onClosingState(state) {
console.log('the open/close of the swipeToClose just changed');
}
renderList() {
var list = [];
for (var i = 0; i < 50; i++) {
list.push(<Text style={styles.text} key={i}>Elem {i}</Text>);
}
return list;
}
Admin_List_Artikel_DesaKu = () => {
return fetch('https://sisteminformasidesaku.000webhostapp.com/api/Artikel_DesaKu/list_artikel_desaku.php')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
this.setState({
isLoding: false,
data: responseJson
})
})
}
componentDidMount() {
this.Admin_List_Artikel_DesaKu()
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
_onRefresh() {
this.setState({ refreshing: true });
this.Admin_List_Artikel_DesaKu().then(() => {
this.setState({
refreshing: false
})
})
}
ListEmptyView = (isLoading = this.state.isLoading) => {
if (isLoading) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
} else {
return (
<View>
<Text style={{ textAlign: 'center' }}> Tidak Ada Data.</Text>
</View>
);
}
}
renderItems = ({ item }) => {
const { id, title_artikel_desaku, tanggal_post_artikel_desaku, photo_artikel_desaku } = item
return (
<View style={styles.containerList}>
<View style={styles.conGambar}>
<Image source={{ uri: photo_artikel_desaku }} style={styles.gmbr} />
</View>
<View style={styles.note}>
<Text style={styles.Judul}>{title_artikel_desaku}</Text>
<Text style={styles.tgl}>{tanggal_post_artikel_desaku}</Text>
</View>
</View>
)
}
render() {
YellowBox.ignoreWarnings(['RNFetchBlob']);
var BContent = (
<View style={[styles.btn, styles.btnModal]}>
<Text style={{ color: '#fff' }} onPress={() => this.setState({ isOpen: false })}>X</Text>
</View>
);
return (
<View style={styles.maincontainer}>
<View style={styles.header}>
<Text style={styles.textHeader}>Artikel DesaKu</Text>
<TouchableOpacity onPress={() => this.signOut()}>
<Text style={styles.textHeader}>Logout</Text>
</TouchableOpacity>
</View>
<FlatList
data={this.state.data}
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.toString()}
renderItem={this.renderItems}
ListEmptyComponent={this.ListEmptyView}
refreshControl={
<RefreshControl refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
/>
<ActionButton buttonColor="rgba(231,76,60,1)">
<ActionButton.Item buttonColor='#1abc9c' title="Add Artikel DesaKu" onPress={() => this.refs.modal3.open()}>
<Icon name="note-add" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
<Modal style={[styles.modal, styles.modal3]} position={"center"} ref={"modal3"} isDisabled={this.state.isDisabled}>
<View>
<ScrollView>
<View style={styles.container}>
<TouchableOpacity onPress={this.selectPhotoTapped.bind(this)}>
<View style={styles.ImageContainer}>
{this.state.ImageSource === null ? <Text>Select a Photo</Text> :
<Image style={styles.ImageContainer} source={this.state.ImageSource} />
}
</View>
</TouchableOpacity>
<TextInput
placeholder="Masukan Judul Artikel "
onChangeText={data => this.setState({ title_artikel_desaku: data })}
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
/>
<TextInput
placeholder="Masukan Tgl Postingan "
onChangeText={data => this.setState({ tanggal_post_artikel_desaku: data })}
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
/>
<TextInput
placeholder="Masukan Lokasi Posting Artikel "
onChangeText={data => this.setState({ photo_artikel_desaku: data })}
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
/>
<TouchableOpacity onPress={this.uploadImageToServer} activeOpacity={0.6} style={styles.button} >
<Text style={styles.TextStyle}> Upload Now </Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
</Modal>
</View>
);
}
}
const styles = StyleSheet.create({
maincontainer: {
flex: 1
},
containerList: {
margin: 5,
backgroundColor: '#009688',
flexDirection: 'row',
borderRadius: 15
},
gmbr: {
height: 100,
width: 100,
resizeMode: "center",
borderRadius: 20
},
conGambar: {
alignItems: 'center',
width: 120,
justifyContent: 'center',
},
note: {
width: 220,
},
Judul: {
fontSize: 18,
fontWeight: 'bold',
color: '#fff'
},
tgl: {
fontSize: 13,
color: '#fff'
},
Title: {
flexDirection: 'row',
justifyContent: 'space-between'
},
jdlTitle: {
fontSize: 20,
fontWeight: 'bold'
},
header: {
height: 40,
width: '100%',
backgroundColor: '#009688',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
},
textHeader: {
fontSize: 20,
color: '#fff',
fontWeight: 'bold',
marginLeft: 10,
marginRight: 10
},
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},
modal3: {
flex: 1,
backgroundColor: '#F0FFFF',
marginTop: 10,
marginBottom: 30,
marginLeft: 5,
marginRight: 10,
width: '90%',
borderRadius: 30
},
MainContainer: {
alignItems: 'center',
justifyContent: 'center'
},
container: {
flex: 1,
alignItems: 'center',
paddingTop: 20
},
ImageContainer: {
borderRadius: 10,
width: 250,
height: 250,
borderColor: '#9B9B9B',
borderWidth: 1 / PixelRatio.get(),
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#CDDC39',
},
TextInputStyle: {
textAlign: 'center',
height: 40,
width: '80%',
borderRadius: 10,
borderWidth: 1,
borderColor: '#028b53',
marginTop: 20
},
TextInputStyleDetail: {
textAlign: 'center',
height: 50,
width: '80%',
borderRadius: 10,
borderWidth: 1,
borderColor: '#028b53',
marginTop: 20,
flexWrap:'wrap'
},
button: {
width: '80%',
backgroundColor: '#00BCD4',
borderRadius: 7,
marginTop: 20
},
TextStyle: {
color: '#fff',
textAlign: 'center',
padding: 10
}
})
export default Admin_Artikel_DesaKu;
Berikut tampilan pada aplikasi nya



Demikian Tutorial Part 18 ini kita akan lanjutkan pada Tutorial Part 19