Commit 2714be51 authored by Alfansyah Fadlian's avatar Alfansyah Fadlian

Merge branch 'master' of https://git.mdd.co.id:44195/muhammadsuryono/meser into dashboard

parents 049a554e c6c27f3b
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
......
......@@ -20,15 +20,11 @@
android:roundIcon="@mipmap/ic_launcher_new_icon"
android:supportsRtl="true"
android:theme="@style/AppTheme.appbar">
<activity
android:name=".ListTransactions"
android:label="@string/title_activity_list_transactions"
android:theme="@style/AppTheme.appbar"></activity>
<activity android:name=".RegisterActivity" />
<activity android:name=".TransactionActivity"/>
<activity
android:name=".BottomSheets"
tools:ignore="Instantiatable" />
<activity android:name=".PaymentCreated" />
<activity
android:name=".HistoryActivity"
android:theme="@style/AppTheme.appbar" />
......@@ -37,11 +33,13 @@
android:theme="@style/AppTheme.appbar" />
<activity
android:name=".PaymentActivity"
android:theme="@style/AppTheme.appbar" />
android:theme="@style/AppTheme.appbar" >
</activity>
<activity
android:name=".CartActivity"
android:theme="@style/AppTheme.appbar" />
<activity android:name=".SplashScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......
......@@ -282,3 +282,10 @@ public class CartActivity extends AppCompatActivity {
super.onBackPressed();
}
}
/**
* Bug ketika qty kurang dari stock masih bertambah
*
*/
\ No newline at end of file
package com.yono.messeripos;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.yono.messeripos.ui.main.SectionsPagerAdapter;
public class ListTransactions extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_transactions);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
}
\ No newline at end of file
......@@ -31,10 +31,8 @@ import com.yono.messeripos.utils.Utils;
public class LoginActivity extends AppCompatActivity {
TextInputEditText username, password;
MainViewModels mainViewModels;
SharedPreferences sharedPreferences;
Utils utils = new Utils();
//State
LoginState loginState;
......@@ -42,9 +40,6 @@ public class LoginActivity extends AppCompatActivity {
MaterialButton btnSignin;
MaterialButton btnSignup, btnSignIn;
ConstraintLayout loginSheetLayout, registerSheetLayout;
int height, width;
ImageButton closeBtn;
private String TAG = "MainActivity";
......@@ -110,7 +105,6 @@ public class LoginActivity extends AppCompatActivity {
@Override
public void onClick(View view) {
registerState = new RegisterState(LoginActivity.this,mainViewModels);
registerState.setCancelable(false);
registerState.show(getSupportFragmentManager(),registerState.getTag());
}
});
......
package com.yono.messeripos;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
......@@ -18,7 +20,6 @@ import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
......@@ -30,6 +31,7 @@ import com.google.android.material.button.MaterialButton;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputEditText;
import com.yono.messeripos.models.CategoryModels;
import com.yono.messeripos.models.MainViewModels;
import com.yono.messeripos.models.UsersModels;
import com.yono.messeripos.response.DataResponse;
......@@ -50,7 +52,7 @@ public class LoginState extends BottomSheetDialogFragment {
SharedPreferences sharedPreferences;
Utils utils;
ProgressBar bar;
AlertDialog alertDialog;
AlertDialog.Builder builder;
ProgressDialog dialog;
......@@ -59,7 +61,6 @@ public class LoginState extends BottomSheetDialogFragment {
this.mainViewModels = mainViewModels;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
......@@ -93,34 +94,17 @@ public class LoginState extends BottomSheetDialogFragment {
sheetBehavior = BottomSheetBehavior.from((View) (view.getParent()));
// get Window size
int getHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
int setHeight = getHeight - (getHeight * 5) / 100;
int setHeight = utils.getWindowHeight() - (utils.getWindowHeight() * 5) / 100;
// set max height
sheetBehavior.setPeekHeight(setHeight);
loginLayout.setMinimumHeight(setHeight);
// alert dialog buat nampilin error
alertDialog = new AlertDialog.Builder(context)
.setTitle("Username dan Password Salah")
.setMessage("Oppss! Username dan Password yang kamu masukan salah!")
.setPositiveButton("Coba Lagi", null)
.setCancelable(false)
.create();
loginButton.setOnClickListener(view1 -> {
if (sheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
bar.setVisibility(View.VISIBLE);
loginButton.setText("");
sheetDialog.setCancelable(false);
loginAuth(view1);
}
});
// loginButton on click
loginButton.setOnClickListener(this::loginAuth);
// close btn is clicked
closeBtn.setOnClickListener(view12 -> {
Log.d(TAG, "onCreateDialog: "+sheetBehavior.getState());
sheetDialog.dismiss();
});
......@@ -128,7 +112,6 @@ public class LoginState extends BottomSheetDialogFragment {
}
private void loginAuth(View v) {
if (TextUtils.isEmpty(username.getText().toString()) &&
TextUtils.isEmpty(password.getText().toString())){
username.setError("This field can't empty");
......@@ -140,14 +123,12 @@ public class LoginState extends BottomSheetDialogFragment {
}else{
/**
* Jika tombol sign in ditekan
*/
// aktifkan progress bar
*
* nonaktifkan semua form */
bar.setVisibility(View.VISIBLE);
// hilangkan tulisan di button
loginButton.setText("");
sheetDialog.setCancelable(false);
// nonaktifkan semua form
username.setEnabled(false);
password.setEnabled(false);
loginButton.setEnabled(false);
......@@ -156,9 +137,7 @@ public class LoginState extends BottomSheetDialogFragment {
// buat checking login
mainViewModels.checkLogin(new UsersModels(username.getText().toString(),
password.getText().toString()))
.observe((LifecycleOwner) context, new Observer<DataResponse<UsersModels>>() {
@Override
public void onChanged(DataResponse<UsersModels> usersModelsDataResponse) {
.observe((LifecycleOwner) context, usersModelsDataResponse -> {
if (usersModelsDataResponse != null) {
......@@ -166,22 +145,23 @@ public class LoginState extends BottomSheetDialogFragment {
* Jika response atau data ada dan cocok
*/
if (usersModelsDataResponse.getStatusData()) {
// SharedPreferences.Editor editor = sharedPreferences.edit();
// editor.putBoolean(SplashScreen.SESSION, true);
// editor.commit();
// redirect ke home
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(SplashScreen.SESSION, true);
if(editor.commit()){
startActivity(new Intent(context, MainActivity.class));
}
// redirect ke home
// set progress bar jadi nonaktif
// set progress bar jadi nonaktif
bar.setVisibility(View.GONE);
// munculkan tulisan default di button sign in
// munculkan tulisan default di button sign in
loginButton.setText(DEFAULT_LOGIN_NAME);
// ubah sheet dialog jadi tidak bisa di slide atau cancel
// ubah sheet dialog jadi tidak bisa di slide atau cancel
sheetDialog.setCancelable(true);
// set form jadi enable
// set form jadi enable
username.setEnabled(true);
password.setEnabled(true);
loginButton.setEnabled(true);
......@@ -197,7 +177,17 @@ public class LoginState extends BottomSheetDialogFragment {
sheetDialog.setCancelable(true);
utils.snackBar(v, "Oppss! Wrong Username or Password!").show();
final View customLayout = getLayoutInflater()
.inflate(R.layout.alert_dialog, null);
// tampilkan alert dialog
utils = new Utils(customLayout);
utils.dialog(context, false, customLayout, "Wrong Username or Password",
"The username or password is incorrect. Please try again!",
"Try Again")
.show();
utils.setListener(Dialog::dismiss);
username.setEnabled(true);
password.setEnabled(true);
loginButton.setEnabled(true);
......@@ -208,8 +198,8 @@ public class LoginState extends BottomSheetDialogFragment {
utils.snackBar(v, "Oppss! ログイン中にエラーが発生しました。しばらくしてからもう一度お試しください").show();
}
}
});
}
loginButton.setText(DEFAULT_LOGIN_NAME);
}
}
......@@ -177,7 +177,7 @@ public class MainActivity extends AppCompatActivity {
}else if (id == R.id.create) {
startActivity(new Intent(getApplicationContext(), FormProductActivity.class));
}else if (id == R.id.allTransaction){
startActivity(new Intent(getApplicationContext(), HistoryActivity.class));
startActivity(new Intent(getApplicationContext(), TransactionActivity.class));
}
return true;
}
......
......@@ -81,8 +81,7 @@ public class RegisterState extends BottomSheetDialogFragment {
sheetBehavior2 = BottomSheetBehavior.from((View) (view.getParent()));
// get Window size
int getHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
int setHeight = getHeight - (getHeight * 5) / 100;
int setHeight = utils.getWindowHeight() - (utils.getWindowHeight() * 5) / 100;
// set max height
sheetBehavior2.setPeekHeight(setHeight);
......
package com.yono.messeripos;
import android.os.Bundle;
import android.os.PersistableBundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.tabs.TabLayout;
import com.yono.messeripos.adapter.TabAdapterTransaction;
import com.yono.messeripos.transactiontab.TransactionSuccess;
import java.util.Objects;
public class TransactionActivity extends AppCompatActivity {
private TabAdapterTransaction adapter;
private TabLayout tabLayout;
private ViewPager viewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_transaction);
viewPager = findViewById(R.id.viewPager);
tabLayout = findViewById(R.id.tabLayout);
MaterialToolbar toolbars = findViewById(R.id.toolbar);
setSupportActionBar(toolbars);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setTitle("All Transaction");
toolbars.setNavigationOnClickListener(view -> onBackPressed());
adapter = new TabAdapterTransaction(getSupportFragmentManager());
adapter.addFragment(new TransactionSuccess(), "Transaction Success");
adapter.addFragment(new TransactionSuccess(), "Transaction Pending");
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
}
}
package com.yono.messeripos.adapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import java.util.ArrayList;
import java.util.List;
public class TabAdapterTransaction extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public TabAdapterTransaction(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
}
......@@ -81,6 +81,7 @@ public class TransactionAdapter extends RecyclerView.Adapter<TransactionAdapter.
itemHistoryBinding.setTransaction(paymentsModels);
itemHistoryBinding.setDate(utils.convertDate(paymentsModels.getUpdatedAt()));
itemHistoryBinding.cvHistory.setOnClickListener(view -> listener.onShowDetail(paymentsModels));
itemHistoryBinding.setGrossAmount(utils.convertPrice("Rp. ", paymentsModels.getGrossAmount()));
if (paymentsModels.getTransactionStatus().equals("Settlement".toLowerCase())) {
......
package com.yono.messeripos.daos;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import com.yono.messeripos.models.PaymentPending;
import com.yono.messeripos.models.ProductCartModels;
import java.util.List;
@Dao
public interface PaymentPendingDaos {
@Query("SELECT * FROM paymentPending ORDER BY id DESC")
public LiveData<List<PaymentPending>> getAll();
@Query("SELECT * FROM paymentPending WHERE id_orders = :idOrders")
public LiveData<List<PaymentPending>> getPaymentByIdOrder(String idOrders);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public void insertPaymentPending(PaymentPending paymentPending);
@Query("UPDATE paymentPending SET id_nfc = :idNfc WHERE id = :id")
public void updateNfc (String idNfc, long id);
}
......@@ -11,6 +11,7 @@ import androidx.room.RoomDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import com.yono.messeripos.daos.CartDaos;
import com.yono.messeripos.daos.PaymentPendingDaos;
import com.yono.messeripos.models.ProductCartModels;
import java.util.concurrent.ExecutorService;
......@@ -20,6 +21,7 @@ import java.util.concurrent.Executors;
public abstract class LocalDatabase extends RoomDatabase {
public abstract CartDaos cartDaos();
public abstract PaymentPendingDaos paymentPendingDaos();
private static volatile LocalDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 407;
......@@ -32,7 +34,7 @@ public abstract class LocalDatabase extends RoomDatabase {
synchronized (LocalDatabase.class){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
LocalDatabase.class, "db_new").build();
LocalDatabase.class, "db_messer").build();
}
}
}
......
package com.yono.messeripos.models;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
import com.google.gson.annotations.SerializedName;
@Entity(tableName = "paymentPending")
public class PaymentPending implements Parcelable {
@PrimaryKey(autoGenerate = true)
@SerializedName("id")
private long id;
@SerializedName("id_orders")
private String id_orders;
@SerializedName("transaction_time")
private String transaction_time;
@SerializedName("transaction_status")
private String transaction_status;
@SerializedName("payment_methode")
private String payment_methode;
@SerializedName("id_nfc")
private String id_nfc;
@SerializedName("gross_amount")
private double gross_amount;
public PaymentPending() {
}
public PaymentPending(long id,
String id_orders,
String transaction_time,
String transaction_status,
String payment_methode,
String id_nfc,
double gross_amount) {
this.id = id;
this.id_orders = id_orders;
this.transaction_time = transaction_time;
this.transaction_status = transaction_status;
this.payment_methode = payment_methode;
this.id_nfc = id_nfc;
this.gross_amount = gross_amount;
}
protected PaymentPending(Parcel in) {
id = in.readLong();
id_orders = in.readString();
transaction_time = in.readString();
transaction_status = in.readString();
payment_methode = in.readString();
id_nfc = in.readString();
gross_amount = in.readInt();
}
public static final Creator<PaymentPending> CREATOR = new Creator<PaymentPending>() {
@Override
public PaymentPending createFromParcel(Parcel in) {
return new PaymentPending(in);
}
@Override
public PaymentPending[] newArray(int size) {
return new PaymentPending[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeLong(id);
parcel.writeString(id_orders);
parcel.writeString(transaction_time);
parcel.writeString(transaction_status);
parcel.writeString(payment_methode);
parcel.writeString(id_nfc);
parcel.writeDouble(gross_amount);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getId_orders() {
return id_orders;
}
public void setId_orders(String id_orders) {
this.id_orders = id_orders;
}
public String getTransaction_time() {
return transaction_time;
}
public void setTransaction_time(String transaction_time) {
this.transaction_time = transaction_time;
}
public String getTransaction_status() {
return transaction_status;
}
public void setTransaction_status(String transaction_status) {
this.transaction_status = transaction_status;
}
public String getPayment_methode() {
return payment_methode;
}
public void setPayment_methode(String payment_methode) {
this.payment_methode = payment_methode;
}
public String getId_nfc() {
return id_nfc;
}
public void setId_nfc(String id_nfc) {
this.id_nfc = id_nfc;
}
public double getGross_amount() {
return gross_amount;
}
public void setGross_amount(double gross_amount) {
this.gross_amount = gross_amount;
}
}
package com.yono.messeripos.repositories;
import android.app.Application;
import androidx.lifecycle.LiveData;
import com.yono.messeripos.daos.PaymentPendingDaos;
import com.yono.messeripos.database.LocalDatabase;
import com.yono.messeripos.models.PaymentPending;
import com.yono.messeripos.models.ProductCartModels;
import java.util.List;
public class PaymentPendingRepositories {
private PaymentPendingDaos daos;
private LiveData<List<PaymentPending>> paymentPending;
public PaymentPendingRepositories(Application application) {
LocalDatabase db = LocalDatabase.geDatabase(application);
daos = db.paymentPendingDaos();
paymentPending = daos.getAll();
}
public void insert(PaymentPending paymentPending){
LocalDatabase.databaseWriterExecutor.execute(() -> daos.insertPaymentPending(paymentPending));
}
// public void delete(ProductCartModels productCartModels){
// LocalDatabase.databaseWriterExecutor.execute(() -> daos.del(productCartModels));
// }
public void updateIdNfc(String idNfc, long id){
LocalDatabase.databaseWriterExecutor.execute(() ->daos.updateNfc(idNfc, id));
}
public LiveData<List<PaymentPending>> getPaymentByOrderId(String idOrders){
return daos.getPaymentByIdOrder(idOrders);
}
}
package com.yono.messeripos.transactiontab;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.yono.messeripos.R;
public class TransactionSuccess extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_history, container, false);
}
}
package com.yono.messeripos.ui.main;
import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
public class PageViewModel extends ViewModel {
private MutableLiveData<Integer> mIndex = new MutableLiveData<>();
private LiveData<String> mText = Transformations.map(mIndex, new Function<Integer, String>() {
@Override
public String apply(Integer input) {
return "Hello world from section: " + input;
}
});
public void setIndex(int index) {
mIndex.setValue(index);
}
public LiveData<String> getText() {
return mText;
}
}
\ No newline at end of file
package com.yono.messeripos.ui.main;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.yono.messeripos.R;
/**
* A placeholder fragment containing a simple view.
*/
public class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private PageViewModel pageViewModel;
public static PlaceholderFragment newInstance(int index) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putInt(ARG_SECTION_NUMBER, index);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = ViewModelProviders.of(this).get(PageViewModel.class);
int index = 1;
if (getArguments() != null) {
index = getArguments().getInt(ARG_SECTION_NUMBER);
}
pageViewModel.setIndex(index);
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_list_transactions, container, false);
final TextView textView = root.findViewById(R.id.section_label);
pageViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
return root;
}
}
\ No newline at end of file
package com.yono.messeripos.ui.main;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import com.yono.messeripos.R;
/**
* A [FragmentPagerAdapter] that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
@StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2};
private final Context mContext;
public SectionsPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
@Override
public int getCount() {
// Show 2 total pages.
return 2;
}
}
\ No newline at end of file
package com.yono.messeripos.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
......@@ -8,14 +9,20 @@ import android.os.Build;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.DividerItemDecoration;
import com.bumptech.glide.load.engine.Resource;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
import com.yono.messeripos.R;
import com.yono.messeripos.adapter.CategoryAdapter;
import com.yono.messeripos.models.CategoryModels;
import java.io.ByteArrayOutputStream;
import java.text.DecimalFormat;
......@@ -26,10 +33,26 @@ import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utils {
public Utils(){};
public Utils(View v){};
public long grandTotal = 0;
public static TextView btnCard;
public interface DialogListener {
void onClickDisimiss(AlertDialog alertDialog);
}
private DialogListener listener;
public void setListener(DialogListener listener) {
this.listener = listener;
}
public String convertPrice(String mataUang, int nilai ){
DecimalFormat rupiah = (DecimalFormat) DecimalFormat.getCurrencyInstance();
......@@ -105,8 +128,8 @@ public class Utils {
return encodeImage;
}
public void toastMessage(Context context, String message){
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
public Toast toastMessage(Context context, String message){
return Toast.makeText(context, message, Toast.LENGTH_LONG);
}
public String convertImageBase64Resource(Resources resource, int id){
......@@ -169,4 +192,124 @@ public class Utils {
return snackbar;
}
public boolean isValidEmail(String email) {
String regex = "^(.+)@(.+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(email);
return matcher.matches();
}
public boolean isValidPassword(String pass) {
String regex = "^(?=.*[A-Za-z-0-9])(?=.*\\d)[A-Za-z-0-9\\d]{8,}$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(pass);
return matcher.matches();
}
/**
* Alert Dialog
* @param context
* @param cancelable
* @param view
* @return
*/
public AlertDialog dialog(Context context, Boolean cancelable, View view) {
CardView btCard = view.findViewById(R.id.cvAlertOnClick);
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(cancelable)
.setView(view);
AlertDialog dialog = builder.create();
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
btnCard.setOnClickListener(view1 -> listener.onClickDisimiss(dialog));
return dialog;
}
public AlertDialog dialog(Context context, Boolean cancelable, View view, @Nullable String titles) {
TextView title = view.findViewById(R.id.alertTitles);
CardView btCard = view.findViewById(R.id.cvAlertOnClick);
// set title and message
if (titles != null){
title.setText(titles);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(cancelable)
.setView(view);
AlertDialog dialog = builder.create();
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
btnCard.setOnClickListener(view1 -> listener.onClickDisimiss(dialog));
return dialog;
}
public AlertDialog dialog(Context context, Boolean cancelable, View view, @Nullable String titles, @Nullable String messages) {
TextView title = view.findViewById(R.id.alertTitles);
TextView message = view.findViewById(R.id.alertBody);
CardView btCard = view.findViewById(R.id.cvAlertOnClick);
// set title and message
if (titles != null){
title.setText(titles);
}
if (message != null){
message.setText(messages);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(cancelable)
.setView(view);
AlertDialog dialog = builder.create();
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
btnCard.setOnClickListener(view1 -> listener.onClickDisimiss(dialog));
return dialog;
}
public AlertDialog dialog(Context context, Boolean cancelable, View view, @Nullable String titles, @Nullable String messages, @Nullable String buttons) {
TextView title = view.findViewById(R.id.alertTitles);
TextView message = view.findViewById(R.id.alertBody);
TextView button = view.findViewById(R.id.tvTextBtn);
CardView btnCard = view.findViewById(R.id.cvAlertOnClick);
// set title and message
if (titles != null){
title.setText(titles);
}
if (message != null){
message.setText(messages);
}
if (button != null){
button.setText(buttons);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(cancelable)
.setView(view);
AlertDialog dialog = builder.create();
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
btnCard.setOnClickListener(view1 -> listener.onClickDisimiss(dialog));
return dialog;
}
// get window size
public int getWindowHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public int getWindowWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:fromYDelta="0%"
android:toYDelta="100%"
android:duration="@android:integer/config_mediumAnimTime"/>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="2000"/>
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:fromYDelta="0%"
android:toYDelta="100%"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:interpolator="@android:anim/bounce_interpolator">
<scale
android:duration="1300"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotY="50%"
android:pivotX="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:interpolator="@android:anim/bounce_interpolator">
<scale
android:duration="1300"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotY="50%"
android:pivotX="50%"
android:toXScale="0.0"
android:toYScale="0.0" />
</set>
\ No newline at end of file
<vector android:height="24dp" android:tint="#B6B6B6"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
......@@ -6,9 +6,9 @@
android:layout_height="match_parent"
tools:context=".HistoryActivity">
<include
android:id="@+id/cAppBar"
layout="@layout/app_bar" />
<!-- <include-->
<!-- android:id="@+id/cAppBar"-->
<!-- layout="@layout/app_bar" />-->
<ProgressBar
android:id="@+id/loading"
......@@ -19,9 +19,8 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_below="@+id/cAppBar">
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvHistory"
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include android:id="@+id/toolbar" layout="@layout/app_bar"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?actionBarSize"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorGreen"
app:tabIndicatorHeight="4dp"
app:tabTextColor="@color/colorWhite"
app:tabBackground="@drawable/gradient"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:tabMode="fixed"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tabLayout"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListTransactions">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="?actionBarSize"
android:padding="@dimen/appbar_padding"
android:text="@string/app_name"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout android:layout_height="wrap_content"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.card.MaterialCardView
android:id="@+id/cvAlertDialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="0dp"
app:cardBackgroundColor="@android:color/transparent"
android:layout_marginVertical="10dp"
android:layout_marginHorizontal="20dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/divider"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/alertTitles"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/dialog_alert_title"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="10dp"
android:layout_gravity="center"/>
<TextView
android:id="@+id/alertBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your username or password wrong"
android:textSize="18sp"
android:gravity="center"
android:layout_gravity="center"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<View
android:id="@+id/divider"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="1dp"
style="@style/Divider.Horizontal"
app:layout_constraintTop_toBottomOf="@id/cvAlertDialog"/>
<com.google.android.material.card.MaterialCardView
android:id="@+id/cvAlertOnClick"
app:cardCornerRadius="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
app:layout_constraintTop_toBottomOf="@id/divider">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTextBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Coba Lagi"
android:textSize="18sp"
android:paddingVertical="15dp"
android:gravity="center"/>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.PlaceholderFragment">
<TextView
android:id="@+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginBottom="@dimen/activity_vertical_margin"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -15,12 +15,19 @@
<variable
name="transactionStatus"
type="String" />
<variable
name="grossAmount"
type="String" />
</data>
<com.google.android.material.card.MaterialCardView
android:id="@+id/cvHistory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
android:layout_margin="10dp"
app:cardElevation="2dp"
tools:ignore="MissingConstraints">
<androidx.constraintlayout.widget.ConstraintLayout
......@@ -59,7 +66,7 @@
android:layout_height="wrap_content"
android:fontFamily="@font/roboto"
android:textSize="16sp"
android:text="@{transaction.orderId}"
android:text="@{transaction.nomorPembayaranGet}"
tools:text="#6821739123"
app:layout_constraintStart_toStartOf="@id/tvDate"
app:layout_constraintTop_toBottomOf="@+id/tvDate" />
......@@ -79,7 +86,7 @@
android:id="@+id/tvVA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{transaction.nomorPembayaranGet}"
android:text="@{grossAmount}"
android:textAllCaps="true"
android:textColor="#000"
android:textStyle="bold"
......
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="transaction"
type="com.yono.messeripos.models.PaymentsModels" />
<variable
name="date"
type="String" />
<variable
name="transactionStatus"
type="String" />
<variable
name="grossAmount"
type="String" />
</data>
<com.google.android.material.card.MaterialCardView
android:id="@+id/cvHistory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
android:layout_margin="10dp"
app:cardElevation="2dp"
tools:ignore="MissingConstraints">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvPay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
android:textColor="@android:color/black"
android:textStyle="bold"
android:textAllCaps="true"
tools:text="@string/hint_pay"
android:text="@{transaction.paymentType}"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto"
android:textSize="16sp"
tools:text="@tools:sample/date/ddmmyy"
android:text="@{date}"
app:layout_constraintStart_toStartOf="@id/tvPay"
app:layout_constraintTop_toBottomOf="@+id/tvPay" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvOrder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto"
android:textSize="16sp"
android:text="@{transaction.nomorPembayaranGet}"
tools:text="#6821739123"
app:layout_constraintStart_toStartOf="@id/tvDate"
app:layout_constraintTop_toBottomOf="@+id/tvDate" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvVA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{grossAmount}"
android:textAllCaps="true"
android:textColor="#000"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
tools:text="@tools:sample/first_names" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</layout>
\ No newline at end of file
......@@ -26,14 +26,24 @@
android:scaleType="centerInside"
android:src="@drawable/ic_close" />
<ScrollView
android:layout_below="@id/closeBtnLogin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/messerLogoInLogin"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_below="@id/closeBtnLogin"
android:layout_width="wrap_content"
android:layout_height="213dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:src="@drawable/ic_messer_primary" />
android:layout_marginBottom="40dp"
android:src="@drawable/login_image" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvLogin"
......@@ -59,6 +69,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:textColor="@color/colorPrimary"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
......@@ -77,25 +88,18 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone|actionGo"
android:textColor="@color/colorPrimary"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<CheckBox
android:id="@+id/CBRememberMe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/FormPasswordLogin"
android:layout_marginVertical="10dp"
android:text="Remember Me"
android:textColor="@color/colorPrimary"
app:useMaterialThemeColors="true" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintBtn"
android:layout_below="@id/CBRememberMe"
android:layout_below="@id/FormPasswordLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/SignInButtonInLogin"
......@@ -133,6 +137,8 @@
android:textColor="@color/colorPrimary"/>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
......
......@@ -25,12 +25,22 @@
/>
<ScrollView
android:layout_below="@id/ivclose"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/ivMeserRegister"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/ic_messer_primary"
android:layout_below="@+id/ivclose"
android:layout_width="match_parent"
android:layout_height="213dp"
android:src="@drawable/register_image"
android:layout_marginTop="20dp"
android:layout_marginBottom="40dp"
android:layout_centerHorizontal="true" />
<com.google.android.material.textview.MaterialTextView
......@@ -45,8 +55,6 @@
android:paddingLeft="12dp"
/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/formUsernameReg"
android:layout_width="match_parent"
......@@ -141,6 +149,11 @@
android:text="Create Account"
android:layout_below="@id/cbAgree"
android:padding="20dp"/>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
......
......@@ -26,4 +26,10 @@
android:title="All Transaction"
app:showAsAction="never" />
<item
android:id="@+id/logout"
android:orderInCategory="100"
android:title="Logout"
app:showAsAction="never" />
</menu>
\ No newline at end of file
......@@ -25,7 +25,6 @@
<item name="android:fontFamily">@font/roboto</item>
<item name="actionBarStyle">@style/ThemeActionBar</item>
<item name="bottomSheetDialogTheme">@style/ThemeOverlay.Rounded.BottomSheetDialog</item>
</style>
<style name="AppTheme.my.a" parent="Theme.MaterialComponents.Light.NoActionBar">
......@@ -98,4 +97,23 @@
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="Divider">
<item name="android:background">#36333333</item> //you can give your color here. that will change all divider color in your app.
</style>
<style name="Divider.Horizontal" parent="Divider">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1dp</item> // You can change thickness here.
</style>
<style name="Divider.Vertical" parent="Divider">
<item name="android:layout_width">1dp</item>
<item name="android:layout_height">match_parent</item>
</style>
<style name="DialogAnimation">
<item name="android:windowEnterAnimation">@anim/zoom_in_bounce</item>
<item name="android:windowExitAnimation">@anim/zoom_out_bounce</item>
</style>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment