diff --git a/app/build.gradle b/app/build.gradle index 1410921..a852d33 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.application' + id 'com.google.gms.google-services' } android { @@ -34,9 +35,15 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0-beta01' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.firebase:firebase-auth:21.0.3' + implementation 'com.google.firebase:firebase-storage:20.0.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' implementation 'com.makeramen:roundedimageview:2.3.0' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' + implementation 'com.github.gabriel-TheCode:AestheticDialogs:1.3.6' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ca112ed..0d24464 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + diff --git a/app/src/main/assets/font/bebas.ttf b/app/src/main/assets/font/bebas.ttf new file mode 100644 index 0000000..ead2c4d Binary files /dev/null and b/app/src/main/assets/font/bebas.ttf differ diff --git a/app/src/main/assets/font/opensans.ttf b/app/src/main/assets/font/opensans.ttf new file mode 100644 index 0000000..ba6db9b Binary files /dev/null and b/app/src/main/assets/font/opensans.ttf differ diff --git a/app/src/main/java/com/capstone/foodify/shipper/API/FoodApi.java b/app/src/main/java/com/capstone/foodify/shipper/API/FoodApi.java new file mode 100644 index 0000000..53abf56 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/API/FoodApi.java @@ -0,0 +1,78 @@ +package com.capstone.foodify.shipper.API; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + + +public interface FoodApi { + Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create(); + + FoodApi apiService = new Retrofit.Builder() + .baseUrl("http://192.168.1.183:8080/api/").addConverterFactory(GsonConverterFactory.create(gson)) + .build() + .create(FoodApi.class); + +// @GET("products/random?pageSize=10") +// Call recommendFood(); +// +// @GET("products/enable?pageNo=0&pageSize=10&sortBy=createdTime&sortDir=desc") +// Call recentFood(); +// +// @GET("shops/enable?pageNo=0&pageSize=10&sortBy=id&sortDir=asc") +// Call allShops(); +// +// @GET("products/search/{name}") +// Call searchFoodByName(@Path("name") String name, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("products") +// Call listFood(@Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("categories/randoms?pageNo=0&pageSize=7") +// Call listCategory(); +// +// @GET("products/categories") +// Call listFoodByCategory(@Query("id") List id, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("products/categoriesAndName") +// Call listFoodByCategoriesAndName(@Query("id") List id, @Query("name") String name, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("products/{id}") +// Call detailFood(@Path("id") String id); +// +// @GET("shops/{id}") +// Call detailShop(@Path("id") int id); +// +// @GET("products/shops/{id}") +// Call listFoodByShopId(@Path("id") int id, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("districts/{districtId}/wards") +// Call> wardResponse(@Path("districtId") int district_id); +// +// @GET("districts") +// Call> districtResponse(); +// +// @GET("sliders") +// Call> listSlider(); +// +// @Headers({"accept: */*", "Content-Type: application/json"}) +// @POST("auth/signup") +// Call register(@Body User user); +// +// @POST("auth/check") +// Call checkEmailOrPhoneExist (@Body User user); +// +// @GET("products/{productId}/comments") +// Call getCommentByProductId(@Path("productId") int productId, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @GET("products/{productId}/users/{userId}") +// Call getUserComment(@Path("productId") int productId, @Path("userId") int userId); +// +// @GET("shops/{id}") +// Call getShopById(@Path("id") int id); +// +// @GET("products/{productId}/user") +// Call checkUserBuyProduct(@Path("productId") int productId, @Query("userId") int userId); +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/API/FoodApiToken.java b/app/src/main/java/com/capstone/foodify/shipper/API/FoodApiToken.java new file mode 100644 index 0000000..2d9c7bc --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/API/FoodApiToken.java @@ -0,0 +1,89 @@ +package com.capstone.foodify.shipper.API; + +import androidx.annotation.NonNull; + +import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Model.User; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.IOException; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import retrofit2.Call; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.http.GET; +import retrofit2.http.Path; + +public interface FoodApiToken { + Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create(); + + OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() { + @NonNull + @Override + public Response intercept(@NonNull Chain chain) throws IOException { + Request newRequest = chain.request().newBuilder().addHeader("Authorization", "Bearer " + Common.TOKEN).build(); + return chain.proceed(newRequest); + } + }).build(); + + + FoodApiToken apiService = new Retrofit.Builder() + .client(client) + .baseUrl("http://192.168.1.183:8080/api/").addConverterFactory(GsonConverterFactory.create(gson)) + .build() + .create(FoodApiToken.class); + + +// @POST("users/{userId}/loves/{productId}") +// Call addFoodToFavorite(@Path("userId") int userId, @Path("productId") int productId); +// +// @DELETE("users/{userId}/loves/{productId}") +// Call removeFoodFromFavorite(@Path("userId") int userId, @Path("productId") int productId); + + @GET("users/email/{userEmail}") + Call getUserFromEmail(@Path("userEmail") String userEmail); + +// @GET("users/{userId}/loves") +// Call getListFavoriteFood(@Path("userId") int userId, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @PUT("users/{userId}") +// Call updateUser(@Path("userId") int userId, @Body User user); +// +// @GET("users/{userId}/loves/{productId}") +// Call checkFoodIsFavorite(@Path("userId") int userId, @Path("productId") int productId); +// +// @POST("users/{userId}/addresses") +// Call createAddressUser(@Path("userId") int userId, @Body Address address); +// +// @PUT("users/{userId}/addresses/{addressId}") +// Call editAddressUser(@Path("userId") int userId, @Path("addressId") int addressId, @Body Address address); +// +// @DELETE("users/{userId}/addresses/{addressId}") +// Call deleteAddressUser(@Path("userId") int userId, @Path("addressId") int addressId); +// +// @POST("users/{userId}/orders") +// Call createOrder(@Path("userId") int userId, @Body Order order); +// +// @POST("products/{productId}/comments") +// Call createComment(@Path("productId") int productId, @Body Comment comment); +// +// @DELETE("products/{productId}/comments/{commentId}") +// Call deleteComment(@Path("productId") int productId, @Path("commentId") int commentId); +// +// @PUT("products/{productId}/comments/{commentId}") +// Call updateComment(@Path("productId") int productId, @Path("commentId") int commentId, @Body Comment comment); +// +// @GET("users/{userId}/orders/status/{status}") +// Call getOrderUser(@Path("userId") int userId, @Path("status") String status, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); +// +// @DELETE("users/{userId}/orders/{orderId}") +// Call deleteOrder(@Path("userId") int userId, @Path("orderId") int orderId); +// +// @PUT("users/{userId}/orders/{orderId}/status") +// Call updateOrderStatus(@Path("userId") int userId, @Path("orderId") int orderId, @Query("status") String status); +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/API/GoogleMapApi.java b/app/src/main/java/com/capstone/foodify/shipper/API/GoogleMapApi.java new file mode 100644 index 0000000..4e3dc89 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/API/GoogleMapApi.java @@ -0,0 +1,27 @@ +package com.capstone.foodify.shipper.API; + +import com.capstone.foodify.shipper.Model.GoogleMap.GoogleMapResponse; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import retrofit2.Call; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface GoogleMapApi { + + Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create(); + + GoogleMapApi apiService = new Retrofit.Builder() + .baseUrl("https://maps.googleapis.com/").addConverterFactory(GsonConverterFactory.create(gson)) + .build() + .create(GoogleMapApi.class); + + @GET("maps/api/geocode/json") + Call getGeoCode(@Query("address") String address, @Query("key") String key); + + @GET("maps/api/geocode/json") + Call getAddress(@Query("latlng") String LatLng, @Query("key") String key); +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/ChangePasswordActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/ChangePasswordActivity.java new file mode 100644 index 0000000..810874f --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/ChangePasswordActivity.java @@ -0,0 +1,16 @@ +package com.capstone.foodify.shipper.Activity; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +import com.capstone.foodify.shipper.R; + +public class ChangePasswordActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_change_password); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java index 9a18d84..29ef096 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java @@ -45,10 +45,10 @@ public class MainActivity extends AppCompatActivity { int id = item.getItemId(); switch (id) { case R.id.activity_order: - viewPager2.setCurrentItem(0); + viewPager2.setCurrentItem(0, false); break; case R.id.activity_profile: - viewPager2.setCurrentItem(1); + viewPager2.setCurrentItem(1, false); break; } return false; diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java index c2ab468..8a86a8e 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java @@ -2,15 +2,35 @@ package com.capstone.foodify.shipper.Activity; import androidx.appcompat.app.AppCompatActivity; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; +import android.view.View; +import android.widget.Button; import com.capstone.foodify.shipper.R; public class OrderDetailActivity extends AppCompatActivity { + Button btn_shipping; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_order_detail); + + btn_shipping = findViewById(R.id.btn_shipping); + + btn_shipping.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("google.navigation:q=16.0230,108.2498&mode=l")); + intent.setPackage("com.google.android.apps.maps"); + startActivity(intent); + } + }); + + + } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java index 715a3c7..f292771 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java @@ -1,35 +1,303 @@ package com.capstone.foodify.shipper.Activity; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.splashscreen.SplashScreen; - import android.content.Intent; import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; import android.view.View; import android.widget.Button; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.splashscreen.SplashScreen; + +import com.capstone.foodify.shipper.API.FoodApiToken; +import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Model.User; import com.capstone.foodify.shipper.R; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; +import com.google.firebase.FirebaseApp; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.GetTokenResult; +import com.google.firebase.auth.SignInMethodQueryResult; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; public class SignInActivity extends AppCompatActivity { - Button btn_sign_in; + private FirebaseAuth mAuth; + TextInputLayout textInput_email, textInput_password; + TextInputEditText edt_email, edt_password; + ConstraintLayout progressLayout; + String email, password = null; + MaterialButton btn_sign_in; + private FirebaseUser user; + + @Override + public void onStart() { + super.onStart(); + + //Get user from Paper +// user = Paper.book().read("user"); + + // Check if user is signed in (non-null) and update UI accordingly. + user = mAuth.getCurrentUser(); + + if (user != null && Common.CURRENT_USER == null) { + progressLayout.setVisibility(View.VISIBLE); + user.getIdToken(true) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Common.TOKEN = task.getResult().getToken(); + + //Get user from database + FoodApiToken.apiService.getUserFromEmail(user.getEmail()).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + User userData = response.body(); + if (userData != null) { + Common.CURRENT_USER = userData; + startActivity(new Intent(SignInActivity.this, MainActivity.class)); + + progressLayout.setVisibility(View.GONE); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + } + }); + } else { + Toast.makeText(SignInActivity.this, "Error when taking token!", Toast.LENGTH_SHORT).show(); + } + } + }); + } + } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SplashScreen.installSplashScreen(this); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + + //Init firebase app + FirebaseApp.initializeApp(SignInActivity.this); setContentView(R.layout.activity_sign_in); + // Initialize Firebase Auth + mAuth = FirebaseAuth.getInstance(); + //Init Component - btn_sign_in = findViewById(R.id.btn_sign_in); + initComponent(); + setFontUI(); + + if(Common.CURRENT_USER != null) + startActivity(new Intent(this, MainActivity.class)); btn_sign_in.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startActivity(new Intent(SignInActivity.this, MainActivity.class)); + initData(); + + if(validData()){ + signIn(); + } + } + }); + + + edt_password.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + textInput_password.setErrorEnabled(false); + } + + @Override + public void afterTextChanged(Editable s) { + } }); } + + private void signIn(){ + progressLayout.setVisibility(View.VISIBLE); + + mAuth.setLanguageCode("vi"); + + mAuth.fetchSignInMethodsForEmail(email) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + + boolean isNewUser = task.getResult().getSignInMethods().isEmpty(); + + if (isNewUser) { + Toast.makeText(SignInActivity.this, "Tài khoản chưa được đăng ký! Vui lòng đăng ký để tiếp tục sử dụng!", Toast.LENGTH_SHORT).show(); + progressLayout.setVisibility(View.GONE); + } else { + signInMethod(); + } + + } + }); + } + + private void signInMethod(){ + mAuth.signInWithEmailAndPassword(email, password) + .addOnCompleteListener(SignInActivity.this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + // Sign in success, update UI with the signed-in user's information + FirebaseUser user = mAuth.getCurrentUser(); + + //Save user +// Paper.book().write("user", user); + + user.getIdToken(true) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if(task.isSuccessful()){ + Common.TOKEN = task.getResult().getToken(); + + //Get user from database + FoodApiToken.apiService.getUserFromEmail(user.getEmail()).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.code() == 200){ + + User userData = response.body(); + if(userData != null){ + + //Check user is lock or not + if(!userData.isLocked()){ + + //Check role account + if(userData.getRole().getRoleName().equals("ROLE_USER")){ + Common.CURRENT_USER = userData; + + //Dismiss progress bar + progressLayout.setVisibility(View.GONE); + + startActivity(new Intent(SignInActivity.this, MainActivity.class)); + finish(); + } else { + Toast.makeText(SignInActivity.this, "Tài khoản không hợp lệ! Vui lòng kiểm tra lại!", Toast.LENGTH_SHORT).show(); + FirebaseAuth.getInstance().signOut(); + + //Dismiss progress bar + progressLayout.setVisibility(View.GONE); + } + } else { + Toast.makeText(SignInActivity.this, "Tài khoản của bạn đã bị khoá!", Toast.LENGTH_SHORT).show(); + FirebaseAuth.getInstance().signOut(); + + //Dismiss progress bar + progressLayout.setVisibility(View.GONE); + } + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + System.out.println("ERROR: " + t); + Common.showErrorServerNotification(SignInActivity.this, "Không thể đăng nhập tài khoản! Vui lòng thử lại sau!"); + } + }); + } else { + Toast.makeText(SignInActivity.this, "Error when taking token!", Toast.LENGTH_SHORT).show(); + } + } + }); + } else { + // If sign in fails, display a message to the user. + Toast.makeText(SignInActivity.this, "Thông tin đăng nhập không đúng! Vui lòng kiểm tra và thử lại!", + Toast.LENGTH_SHORT).show(); + + //Dismiss progress bar + progressLayout.setVisibility(View.GONE); + } + } + }); + } + + private void initData(){ + email = edt_email.getText().toString(); + password = edt_password.getText().toString(); + } + + private void initComponent(){ + btn_sign_in = findViewById(R.id.sign_in_button); + textInput_email = findViewById(R.id.textInput_email); + textInput_password = findViewById(R.id.textInput_password); + + edt_email = findViewById(R.id.edt_email); + edt_password = findViewById(R.id.edt_password); + + progressLayout = findViewById(R.id.progress_layout); + + } + + private void setFontUI() { + textInput_email.setTypeface(Common.setFontBebas(getAssets())); + textInput_password.setTypeface(Common.setFontBebas(getAssets())); + } + + private boolean validData(){ + boolean dataHasValidate = true; + + //Check phone number + if(email.isEmpty()){ + textInput_email.setError("Email không được bỏ trống!"); + dataHasValidate = false; + } else { + + //Check email valid + Pattern patternEmail = Pattern.compile(Common.VALID_EMAIL_ADDRESS_REGEX, Pattern.CASE_INSENSITIVE); + Matcher matcherEmail = patternEmail.matcher(email); + if(!matcherEmail.matches()){ + textInput_email.setError("Địa chỉ email không đúng định dạng. Xin vui lòng kiểm tra lại!"); + dataHasValidate = false; + } else { + textInput_email.setErrorEnabled(false); + } + } + + //Check password + Pattern patternPassword = Pattern.compile(Common.PASSWORD_PATTERN); + Matcher matcherPassword = patternPassword.matcher(edt_password.getText().toString()); + + if(!matcherPassword.matches() || edt_password.getText().toString().length() < 8) { + textInput_password.setError("Mật khẩu của bạn cần tối thiểu có 8 ký tự, 1 ký tự viết hoa, 1 số và 1 ký tự đặc biệt!"); + dataHasValidate = false; + } else { + textInput_password.setErrorEnabled(false); + } + + return dataHasValidate; + } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Common.java b/app/src/main/java/com/capstone/foodify/shipper/Common.java new file mode 100644 index 0000000..618418d --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Common.java @@ -0,0 +1,51 @@ +package com.capstone.foodify.shipper; + +import android.app.Activity; +import android.content.res.AssetManager; +import android.graphics.Typeface; +import android.location.Location; + +import androidx.annotation.NonNull; + +import com.capstone.foodify.shipper.Model.User; +import com.thecode.aestheticdialogs.AestheticDialog; +import com.thecode.aestheticdialogs.DialogStyle; +import com.thecode.aestheticdialogs.DialogType; +import com.thecode.aestheticdialogs.OnDialogClickListener; + +public class Common { + public static User CURRENT_USER = null; + public static String TOKEN = null; + public static Location CURRENT_LOCATION = null; + public static final String MAP_API = "AIzaSyAY14Ic32UP26Hg6GILznOfbBihiY5BUxw"; + public static final String IS_FORGOT_PASSWORD = "isForgotPassword"; + public static final String FORMAT_DATE="dd-MM-yyyy"; + public static final String VALID_EMAIL_ADDRESS_REGEX = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$"; + public static final String PHONE_CODE = "+84"; + public static final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[@#$%^&+=!_])(?=\\S+$).{4,}$"; + public static final String PHONE_PATTERN = "^0[98753]{1}\\d{8}$"; + + public static Typeface setFontBebas(AssetManager assetManager){ + return Typeface.createFromAsset(assetManager, "font/bebas.ttf"); + } + + public static Typeface setFontOpenSans(AssetManager assetManager){ + return Typeface.createFromAsset(assetManager, "font/opensans.ttf"); + } + + public static void showErrorServerNotification(Activity activity, String message){ + new AestheticDialog.Builder(activity, DialogStyle.RAINBOW, DialogType.ERROR) + .setTitle("LỖI!") + .setMessage(message) + .setCancelable(false) + .setOnClickListener(new OnDialogClickListener() { + @Override + public void onClick(@NonNull AestheticDialog.Builder builder) { + + activity.finishAffinity(); + System.exit(0); + } + }).show(); + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/ProfileFragment.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/ProfileFragment.java index c99bccf..594a842 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Fragment/ProfileFragment.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/ProfileFragment.java @@ -1,21 +1,75 @@ package com.capstone.foodify.shipper.Fragment; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; +import android.os.CountDownTimer; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.capstone.foodify.shipper.Activity.ChangePasswordActivity; +import com.capstone.foodify.shipper.Common; import com.capstone.foodify.shipper.R; +import com.google.android.material.textfield.TextInputLayout; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; +import com.makeramen.roundedimageview.RoundedImageView; + +import java.util.Calendar; public class ProfileFragment extends Fragment { + private static final String FOLDER_DIRECTORY = "UserImages/"; + TextView txt_countdown, txt_resend_code, txt_verify_email; + EditText edt_birthday, edt_phone, edt_fullName; + Button update_image_button; + RoundedImageView profile_avatar; + private Uri imageUri; + final private StorageReference storageReference = FirebaseStorage.getInstance().getReference(); + ConstraintLayout progressLayout; + LinearLayout changePasswordLayout; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_profile, container, false); + View view = inflater.inflate(R.layout.fragment_profile, container, false); + + //Init component + initComponent(view); + initData(); + + //Set event for change password layout + changePasswordLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(getContext(), ChangePasswordActivity.class)); + } + }); + + return view; + } + + private void initData(){ + edt_phone.setText(Common.CURRENT_USER.getPhoneNumber()); + edt_birthday.setText(Common.CURRENT_USER.getDateOfBirth()); + edt_fullName.setText(Common.CURRENT_USER.getFullName()); + } + private void initComponent(View view){ + changePasswordLayout = view.findViewById(R.id.change_password); + edt_phone = view.findViewById(R.id.edt_phone); + edt_birthday = view.findViewById(R.id.edt_birthDay); + edt_fullName = view.findViewById(R.id.edt_fullName); } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/Address.java b/app/src/main/java/com/capstone/foodify/shipper/Model/Address.java new file mode 100644 index 0000000..26094e9 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/Address.java @@ -0,0 +1,50 @@ +package com.capstone.foodify.shipper.Model; + +import java.io.Serializable; + +public class Address implements Serializable{ + private int id; + private String address; + private String ward; + private String district; + + public Address(String address, String ward, String district) { + this.address = address; + this.ward = ward; + this.district = district; + } + + public Address(){} + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getWard() { + return ward; + } + + public void setWard(String ward) { + this.ward = ward; + } + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/AddressComponent.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/AddressComponent.java new file mode 100644 index 0000000..1443496 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/AddressComponent.java @@ -0,0 +1,45 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class AddressComponent { + + @SerializedName("long_name") + @Expose + private String longName; + @SerializedName("short_name") + @Expose + private String shortName; + @SerializedName("types") + @Expose + private List types; + + public String getLongName() { + return longName; + } + + public void setLongName(String longName) { + this.longName = longName; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Geometry.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Geometry.java new file mode 100644 index 0000000..7830087 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Geometry.java @@ -0,0 +1,43 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Geometry { + + @SerializedName("location") + @Expose + private Location location; + @SerializedName("location_type") + @Expose + private String locationType; + @SerializedName("viewport") + @Expose + private Viewport viewport; + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public String getLocationType() { + return locationType; + } + + public void setLocationType(String locationType) { + this.locationType = locationType; + } + + public Viewport getViewport() { + return viewport; + } + + public void setViewport(Viewport viewport) { + this.viewport = viewport; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/GoogleMapResponse.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/GoogleMapResponse.java new file mode 100644 index 0000000..fcea4f6 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/GoogleMapResponse.java @@ -0,0 +1,34 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class GoogleMapResponse { + + @SerializedName("results") + @Expose + private List results; + @SerializedName("status") + @Expose + private String status; + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Location.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Location.java new file mode 100644 index 0000000..e042d7f --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Location.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Location { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Northeast.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Northeast.java new file mode 100644 index 0000000..e11075c --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Northeast.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Northeast { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Result.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Result.java new file mode 100644 index 0000000..abd1185 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Result.java @@ -0,0 +1,67 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Result { + + @SerializedName("address_components") + @Expose + private List addressComponents; + @SerializedName("formatted_address") + @Expose + private String formattedAddress; + @SerializedName("geometry") + @Expose + private Geometry geometry; + @SerializedName("place_id") + @Expose + private String placeId; + @SerializedName("types") + @Expose + private List types; + + public List getAddressComponents() { + return addressComponents; + } + + public void setAddressComponents(List addressComponents) { + this.addressComponents = addressComponents; + } + + public String getFormattedAddress() { + return formattedAddress; + } + + public void setFormattedAddress(String formattedAddress) { + this.formattedAddress = formattedAddress; + } + + public Geometry getGeometry() { + return geometry; + } + + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + public String getPlaceId() { + return placeId; + } + + public void setPlaceId(String placeId) { + this.placeId = placeId; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Southwest.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Southwest.java new file mode 100644 index 0000000..e1da185 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Southwest.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Southwest { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Viewport.java b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Viewport.java new file mode 100644 index 0000000..3c456c3 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/GoogleMap/Viewport.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.shipper.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Viewport { + + @SerializedName("northeast") + @Expose + private Northeast northeast; + @SerializedName("southwest") + @Expose + private Southwest southwest; + + public Northeast getNortheast() { + return northeast; + } + + public void setNortheast(Northeast northeast) { + this.northeast = northeast; + } + + public Southwest getSouthwest() { + return southwest; + } + + public void setSouthwest(Southwest southwest) { + this.southwest = southwest; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/Role.java b/app/src/main/java/com/capstone/foodify/shipper/Model/Role.java new file mode 100644 index 0000000..62dca05 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/Role.java @@ -0,0 +1,22 @@ +package com.capstone.foodify.shipper.Model; + +public class Role { + private int id; + private String roleName; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/User.java b/app/src/main/java/com/capstone/foodify/shipper/Model/User.java new file mode 100644 index 0000000..9127c35 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/User.java @@ -0,0 +1,140 @@ +package com.capstone.foodify.shipper.Model; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +public class User implements Serializable { + private int id; + @SerializedName("addressDto") + private Address address; + private String dateOfBirth; + private String email; + private String fullName; + private String identifiedCode; + private String imageUrl; + private boolean isLocked; + private String phoneNumber; + private String roleName; + private Role role; + private int defaultAddress; + private List
addresses; + + public User(Address address, String dateOfBirth, String email, String fullName, String identifiedCode, String phoneNumber) { + this.address = address; + this.dateOfBirth = dateOfBirth; + this.email = email; + this.fullName = fullName; + this.identifiedCode = identifiedCode; + this.imageUrl = ""; + this.phoneNumber = phoneNumber; + this.roleName = "ROLE_USER"; + this.isLocked = false; + } + + public User(){} + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public boolean isLocked() { + return isLocked; + } + + public void setLocked(boolean locked) { + isLocked = locked; + } + + public String getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(String dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getIdentifiedCode() { + return identifiedCode; + } + + public void setIdentifiedCode(String identifiedCode) { + this.identifiedCode = identifiedCode; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + public List
getAddresses() { + return addresses; + } + + public int getDefaultAddress() { + return defaultAddress; + } + + public void setDefaultAddress(int defaultAddress) { + this.defaultAddress = defaultAddress; + } + + public void setAddresses(List
addresses) { + this.addresses = addresses; + } + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } +} diff --git a/app/src/main/res/layout/activity_change_password.xml b/app/src/main/res/layout/activity_change_password.xml new file mode 100644 index 0000000..1f08bc4 --- /dev/null +++ b/app/src/main/res/layout/activity_change_password.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_sign_in.xml b/app/src/main/res/layout/activity_sign_in.xml index c2c95e2..e517f7f 100644 --- a/app/src/main/res/layout/activity_sign_in.xml +++ b/app/src/main/res/layout/activity_sign_in.xml @@ -119,7 +119,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 2906dad..65bdb14 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -52,29 +52,6 @@ app:layout_constraintEnd_toEndOf="parent" /> - - - - - @@ -142,7 +120,7 @@ android:id="@+id/edt_birthDay" android:layout_width="match_parent" android:layout_height="match_parent" - android:clickable="false" + android:enabled="false" android:cursorVisible="false" android:focusable="false" android:focusableInTouchMode="false" @@ -157,9 +135,9 @@ android:layout_marginBottom="30dp" android:layout_marginStart="20dp" android:layout_marginEnd="20dp" - app:layout_constraintBottom_toTopOf="@id/updated_button" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" android:orientation="horizontal" > @@ -194,22 +172,6 @@ - -