fluttertoast: ^3.1.3
dio: ^3.0.8
image_picker: ^0.6.3+1
flutter_material_pickers: ^1.2.0
intl: ^0.16.1
shared_preferences: ^0.5.4
class Endpoint {
//static String _baseURL = "https://leeyurani.com/restofood/public/api";
static String _baseURL = "http://192.168.67.12:8000/api"; //bisa
static String baseFood = "${_baseURL}/foods";
static String baseCity = "${_baseURL}/city";
//Auth routes
static String register = "${_baseURL}/auth/register";
static String login = "${_baseURL}/auth/login";
}class ActionModel {
int status;
String message;
Data data;
ActionModel({this.status, this.message, this.data});
ActionModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data.toJson();
}
return data;
}
}
class Data {
int id;
String username;
String email;
String nik;
String tanggalLahir;
String alamat;
String jenisKelamin;
String kota;
String pathPhoto;
String filePhoto;
Data(
{this.id,
this.username,
this.email,
this.nik,
this.tanggalLahir,
this.alamat,
this.jenisKelamin,
this.kota,
this.pathPhoto,
this.filePhoto});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
email = json['email'];
nik = json['nik'];
tanggalLahir = json['tanggal_lahir'];
alamat = json['alamat'];
jenisKelamin = json['jenis_kelamin'];
kota = json['kota'];
pathPhoto = json['path_photo'];
filePhoto = json['file_photo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['username'] = this.username;
data['email'] = this.email;
data['nik'] = this.nik;
data['tanggal_lahir'] = this.tanggalLahir;
data['alamat'] = this.alamat;
data['jenis_kelamin'] = this.jenisKelamin;
data['kota'] = this.kota;
data['path_photo'] = this.pathPhoto;
data['file_photo'] = this.filePhoto;
return data;
}
}
class CityModel {
int id;
String name;
CityModel({this.id, this.name});
factory CityModel.fromJson(Map<String, dynamic> json) {
return CityModel(
id: json['id'] != null ? int.parse(json['id'].toString()) : 0,
name: json['name'] != null ? json['name'] : ""
);
}
}
import 'package:restofood_api/core/config/endpoint.dart';
import 'package:restofood_api/core/models/city_model.dart';
import 'package:dio/dio.dart';
class CityServices {
static Dio dio = new Dio();
//Get foods data
static Future<List<CityModel>> getAll() async {
var response = await dio.get(
Endpoint.baseCity,
options: Options(
headers: {
"Accept": "application/json"
}
)
);
var _cityData = List<CityModel>();
response.data["data"].forEach((value) {
_cityData.add(CityModel.fromJson(value));
});
print(_cityData[0].name);
return _cityData;
}
}import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_material_pickers/flutter_material_pickers.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:restofood_api/core/models/city_model.dart';
import 'package:restofood_api/core/services/auth_services.dart';
import 'package:restofood_api/core/services/city_services.dart';
import 'package:restofood_api/core/utils/toast_utils.dart';
import 'package:restofood_api/ui/widgets/input_field.dart';
import 'package:restofood_api/ui/widgets/primary_button.dart';
class RegisterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
body: SingleChildScrollView(
child: RegisterBody()
),
),
);
}
}
class RegisterBody extends StatefulWidget {
@override
_RegisterBodyState createState() => _RegisterBodyState();
}
class _RegisterBodyState extends State<RegisterBody> {
var usernameController = TextEditingController();
var passwordController = TextEditingController();
var confirmPasswordController = TextEditingController();
var emailController = TextEditingController();
var namaController = TextEditingController();
var nikController = TextEditingController();
var tanggalController = TextEditingController();
var alamatController = TextEditingController();
var jenisKelaminController = TextEditingController();
var kotaController = TextEditingController();
List<CityModel> cityList;
File image;
void register() async {
if (usernameController.text.isNotEmpty && passwordController.text.isNotEmpty
&& confirmPasswordController.text.isNotEmpty && emailController.text.isNotEmpty
&& namaController.text.isNotEmpty && nikController.text.isNotEmpty
&& tanggalController.text.isNotEmpty && alamatController.text.isNotEmpty
&& jenisKelaminController.text.isNotEmpty && kotaController.text.isNotEmpty
&& image != null
) {
if (passwordController.text == confirmPasswordController.text) {
//call aPI Register
Map<String, dynamic> data = {
"username": usernameController.text,
"password": passwordController.text,
"email": emailController.text,
"nama": namaController.text,
"nik": nikController.text,
"tanggal_lahir": tanggalController.text,
"alamat": alamatController.text,
"image": await MultipartFile.fromFile(image.path),
"jenis_kelamin": jenisKelaminController.text,
"kota": kotaController.text
};
ToastUtils.show("Mencoba Mendaftar");
var response = await AuthServices.register(data);
if (response.status == 201) {
ToastUtils.show(response.message);
Navigator.pop(context);
} else {
ToastUtils.show(response.message);
}
} else {
ToastUtils.show("Password tidak sama");
}
} else {
ToastUtils.show("Silahkan isi semua field");
}
}
void pickTanggal() {
showMaterialDatePicker(
context: context,
selectedDate: DateTime.now(),
onChanged: (value) {
tanggalController.text = DateFormat('yyyy-MM-dd').format(value);
},
);
}
void pickGender() {
List<String> genderList = <String>[
'Laki-Laki',
'Perempuan',
];
showMaterialRadioPicker(
context: context,
title: "Pilih Gender",
items: genderList,
onChanged: (value) {
jenisKelaminController.text = value;
},
);
}
void pickCity() {
if (cityList != null) {
showMaterialScrollPicker(
context: context,
title: "Pilih Kota",
items: cityList.map((x) => x.name).toList(),
onChanged: (value) {
kotaController.text = value;
},
);
}
}
void pickImage() async {
var _image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (_image != null) {
setState(() {
image = _image;
});
}
}
void getCity() async {
cityList = new List<CityModel>();
var _city = await CityServices.getAll();
setState(() {
cityList = _city;
});
}
@override
void initState() {
super.initState();
this.getCity();
}
@override
Widget build(BuildContext context) {
//Jika masih proses ambil data city
if (cityList == null) {
return Container(
height: MediaQuery.of(context).size.height,
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Column(
children: <Widget>[
//Bagian headers
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 2.5,
color: Colors.orange,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: InkWell(
onTap: () => Navigator.pop(context),
child: Icon(Icons.arrow_back, color: Colors.white, size: 30),
),
),
),
Text(
"Register",
style: TextStyle(
fontSize: 35,
color: Colors.white,
fontWeight: FontWeight.bold
),
),
SizedBox(height: 10),
InkWell(
onTap: () => pickImage(),
child: image == null
? Icon(Icons.account_circle, size: 70, color: Colors.white)
: Container(
width: 120,
height: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(80),
image: DecorationImage(
image: ExactAssetImage(image.path)
)
),
)
)
],
),
)
),
//Bagian field Register
Padding(
padding: EdgeInsets.only(left: 20, right: 20, top: 30),
child: Column(
children: <Widget>[
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: usernameController,
hintText: "Username",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: passwordController,
hintText: "Password",
secureText: true,
),
SizedBox(height: 15),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: confirmPasswordController,
hintText: "Confirm Password",
secureText: true,
),
SizedBox(height: 15),
InputField(
action: TextInputAction.done,
type: TextInputType.emailAddress,
controller: emailController,
hintText: "Email Address",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: namaController,
hintText: "Nama Lengkap",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.number,
controller: nikController,
hintText: "NIK",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: tanggalController,
hintText: "Tanggal",
readOnly: true,
onTap: () => pickTanggal(),
),
SizedBox(height: 10),
InputField(
action: TextInputAction.newline,
type: TextInputType.multiline,
controller: alamatController,
hintText: "Alamat",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: jenisKelaminController,
readOnly: true,
hintText: "Jenis Kelamin",
onTap: () => pickGender(),
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: kotaController,
readOnly: true,
hintText: "Kota",
onTap: () => pickCity(),
),
SizedBox(height: 10),
Container(
width: MediaQuery.of(context).size.width,
height: 45,
child: PrimaryButton(
color: Colors.orange,
text: "REGISTER",
onClick: () => register(),
),
),
SizedBox(height: 30),
],
),
)
],
);
}
}import 'package:flutter/material.dart';
import 'package:restofood_api/ui/screens/dashboard_screen.dart';
import 'package:restofood_api/ui/screens/home_screen.dart';
import 'package:restofood_api/ui/screens/login_screen.dart';
import 'package:restofood_api/ui/screens/register_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Restofood",
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.orange,
accentColor: Colors.orange
),
home: LoginScreen(),
routes: {
"/dashboard": (context) => DashboardScreen(),
"/login": (context) => LoginScreen(),
"/register": (context) => RegisterScreen()
},
);
}
} void register(BuildContext context) {
Navigator.pushNamed(context, "/register");
}
SizedBox(height: 15),
Container(
width: MediaQuery.of(context).size.width,
height: 45,
child: PrimaryButton(
color: Colors.grey,
text: "REGISTER",
onClick: () => register(context),
),
)
import 'package:dio/dio.dart';
import 'package:restofood_api/core/config/endpoint.dart';
import 'package:restofood_api/core/models/action_model.dart';
class AuthServices {
static Dio dio = new Dio();
static Future<ActionModel> register(Map registerData) async {
var response = await dio.post(
Endpoint.register,
data: FormData.fromMap(registerData),
options: Options(
headers: {
"Accept": "application/json"
}
)
);
return ActionModel.fromJson(response.data);
}
//untuk mendapatkan login
static Future<ActionModel> login2(Map loginData) async {
var response = await dio.post(
Endpoint.login,
data: FormData.fromMap(loginData),
options: Options(
headers: {
"Accept": "application/json"
}
)
);
return ActionModel.fromJson(response.data);
}
}import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:restofood_api/core/models/action_model.dart';
import 'package:restofood_api/core/services/auth_services.dart';
import 'package:restofood_api/core/utils/toast_utils.dart';
import 'package:restofood_api/ui/screens/home_screen.dart';
import 'package:restofood_api/ui/widgets/input_field.dart';
import 'package:restofood_api/ui/widgets/primary_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
body: SingleChildScrollView(
child: LoginBody()
),
),
);
}
}
class LoginBody extends StatefulWidget {
LoginBody({Key key}) : super(key: key);
@override
_LoginBodyState createState() => _LoginBodyState();
}
class _LoginBodyState extends State<LoginBody> {
var usernameController = TextEditingController();
var passwordController = TextEditingController();
@override
void initState() {
super.initState();
getPref();
}
Future<void> login(BuildContext context) async {
if (usernameController.text.isNotEmpty && passwordController.text.isNotEmpty) {
Map<String, dynamic> data = {
"username": usernameController.text,
"password": passwordController.text
};
ToastUtils.show("Mencoba Login");
var response = await AuthServices.login2(data);
print("Status:"+ response.status.toString());
print("message:"+ response.message.toString());
if(response.status==200){
ToastUtils.show(response.message);
ToastUtils.show("Welcome : " + response.data.email.toString());
savePref(
usernameController.text,
response.data.email.toString(),
response.data.pathPhoto.toString()
);
Navigator.pushNamedAndRemoveUntil(context, "/profile", (Route<dynamic> routes) => false);
}else{
ToastUtils.show(response.message);
}
} else {
ToastUtils.show("Silahkan isi semua field");
}
}
void register(BuildContext context) {
Navigator.pushNamed(context, "/register");
}
savePref(String username, String email, String foto) async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
pref.setString('username', username);
pref.setString('email', email);
pref.setString('foto', foto);
});
}
getPref() async {
SharedPreferences pref = await SharedPreferences.getInstance();
final username = pref.getString('username');
if (username != null) {
Navigator.pushNamedAndRemoveUntil(context, "/profile", (Route<dynamic> routes) => false);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
//Bagian headers
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 2.5,
color: Colors.orange,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.fastfood, size: 40, color: Colors.white),
SizedBox(height: 10),
Text(
"Restofood",
style: TextStyle(
fontSize: 35,
color: Colors.white,
fontWeight: FontWeight.bold
),
)
],
),
)
),
//Bagian field login
Padding(
padding: EdgeInsets.only(left: 20, right: 20, top: 30),
child: Column(
children: <Widget>[
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: usernameController,
hintText: "Username",
),
SizedBox(height: 10),
InputField(
action: TextInputAction.done,
type: TextInputType.text,
controller: passwordController,
hintText: "Password",
secureText: true,
),
SizedBox(height: 15),
Container(
width: MediaQuery.of(context).size.width,
height: 45,
child: PrimaryButton(
color: Colors.orange,
text: "LOGIN",
onClick: () => login(context),
),
),
SizedBox(height: 15),
Container(
width: MediaQuery.of(context).size.width,
height: 45,
child: PrimaryButton(
color: Colors.grey,
text: "REGISTER",
onClick: () => register(context),
),
)
],
),
)
],
);
}
}
import 'package:flutter/material.dart';
import 'package:restofood_api/ui/screens/dashboard_screen.dart';
import 'package:restofood_api/ui/screens/home_screen.dart';
import 'package:restofood_api/ui/screens/login_screen.dart';
import 'package:restofood_api/ui/screens/register_screen.dart';
import 'package:restofood_api/ui/screens/profile_screen.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Restofood",
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.orange,
accentColor: Colors.orange
),
home: cekLogin(),
routes: {
"/dashboard": (context) => DashboardScreen(),
"/profile": (context) => ProfileScreen(),
"/login": (context) => LoginScreen(),
"/register": (context) => RegisterScreen()
},
);
}
}
class cekLogin extends StatefulWidget {
cekLogin({Key key}) : super(key: key);
@override
_cekLoginState createState() => _cekLoginState();
}
class _cekLoginState extends State<cekLogin> {
@override
void initState() {
super.initState();
getPref();
}
getPref() async {
SharedPreferences pref = await SharedPreferences.getInstance();
final username = pref.getString('username');
if (username != null) {
Future.delayed(const Duration(milliseconds: 2000), () {
Navigator.pushNamedAndRemoveUntil(context, "/profile", (Route<dynamic> routes) => false);
});
}else{
Future.delayed(const Duration(milliseconds: 2000), () {
Navigator.pushNamedAndRemoveUntil(context, "/login", (Route<dynamic> routes) => false);
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: spashscreen(),
);
}
Widget spashscreen(){
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.orange,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.fastfood, size: 40, color: Colors.white),
SizedBox(height: 10),
Text(
"Restofood",
style: TextStyle(
fontSize: 35,
color: Colors.white,
fontWeight: FontWeight.bold
),
)
],
),
)
);
}
}import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:restofood_api/core/models/action_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../core/utils/toast_utils.dart';
import '../widgets/primary_button.dart';
class ProfileScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
body: SingleChildScrollView(
child: ProfileBody()
),
),
);
}
}
class ProfileBody extends StatefulWidget {
ProfileBody({Key key}) : super(key: key);
@override
_ProfileBodyState createState() => _ProfileBodyState();
}
class _ProfileBodyState extends State<ProfileBody> {
String username, email, pathPhoto;
@override
void initState() {
super.initState();
getPref();
}
logout(){
ToastUtils.show("Mencoba Logout");
savePref();
Future.delayed(const Duration(milliseconds: 2000), () {
ToastUtils.show("Berhasil Logout");
Navigator.pushNamedAndRemoveUntil(context, "/login", (Route<dynamic> routes) => false);
});
}
savePref() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
pref.remove('username');
pref.remove('email');
pref.remove('profile');
});
}
getPref() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
username = pref.getString('username');
email = pref.getString('email');
pathPhoto = pref.getString('foto');
});
if (username != null) {
}else{
Navigator.pushNamedAndRemoveUntil(context, "/login", (Route<dynamic> routes) => false);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
//Bagian headers
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 2.5,
color: Colors.orange,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(60),
image: DecorationImage(
image: NetworkImage(pathPhoto.toString())
)
),
),
SizedBox(height: 10),
Text(
username,
style: TextStyle(
fontSize: 25,
color: Colors.white,
fontWeight: FontWeight.bold
),
),
SizedBox(height: 5),
Container(
width: MediaQuery.of(context).size.width / 1.8,
child: Text(
email,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
color: Colors.white,
),
),
),
],
),
)
),
//Bagian field login
Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
child: Card(
elevation: 1,
child: Padding(
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Biodata",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold
),
),
Text(
"Asal Kota: " + pathPhoto.toString(),
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
color: Colors.black87
),
),
],
),
),
),
)
],
),
),
SizedBox(height: 15),
Container(
margin: EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
height: 45,
child: PrimaryButton(
color: Colors.orange,
text: "LOGOUT",
onClick: (){
logout();
},
),
)
],
);
}
}