Java tutorial
/** * Copyright (C) 2016 - Franois LEPAROUX * <p/> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * <p/> * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * <p/> * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package fr.bde_eseo.eseomega.events.tickets; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.InputType; import android.util.Base64; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import fr.bde_eseo.eseomega.Constants; import fr.bde_eseo.eseomega.R; import fr.bde_eseo.eseomega.events.EventItem; import fr.bde_eseo.eseomega.events.tickets.adapters.MyPresalesAdapter; import fr.bde_eseo.eseomega.events.tickets.model.SubEventItem; import fr.bde_eseo.eseomega.events.tickets.model.TicketPictItem; import fr.bde_eseo.eseomega.events.tickets.model.TicketStore; import fr.bde_eseo.eseomega.listeners.RecyclerItemClickListener; import fr.bde_eseo.eseomega.lydia.LydiaActivity; import fr.bde_eseo.eseomega.profile.UserProfile; import fr.bde_eseo.eseomega.utils.ConnexionUtils; import fr.bde_eseo.eseomega.utils.Utilities; /** * Created by Franois L. on 11/01/2016. * Liste les venements que l'utilisateur peut acheter * <p/> * vnements (liste) type de place (dialogue) Activit de choix de la navette (si il y a navette) Paiement Lydia * <p/> * vnements possibles : * - date < date_debut * - au moins un type de place de dispo * - prix >= 0.5 */ public class PresalesActivity extends AppCompatActivity { // Model private ArrayList<TicketPictItem> ticketPictItems; // Android objects private Context context; private boolean isVisible, messageNotShown; // User profile private UserProfile userProfile; // UI private TextView tvNo1, tvNo2; private ImageView imgNo; // Adapter / recycler private MyPresalesAdapter mAdapter; private RecyclerView recList; // Data private int idcmd = -1; private String eventName, eventDate, eventID, ticketName; public static final long MAX_DELAY_ORDER = 582 * 1000; @Override protected void onCreate(Bundle savedInstanceState) { // Set view / call parent super.onCreate(savedInstanceState); setContentView(R.layout.activity_presales); getSupportActionBar().setDisplayHomeAsUpEnabled(true); context = this; // Get user profile userProfile = new UserProfile(); userProfile.readProfilePromPrefs(context); // Get layout tvNo1 = (TextView) findViewById(R.id.tvListNothing); tvNo2 = (TextView) findViewById(R.id.tvListNothing2); imgNo = (ImageView) findViewById(R.id.imgNoPresale); // Get current events / tickets fillArray(); // Init views if (ticketPictItems.size() == 0) { tvNo1.setVisibility(View.VISIBLE); tvNo2.setVisibility(View.VISIBLE); imgNo.setVisibility(View.VISIBLE); } else { tvNo1.setVisibility(View.GONE); tvNo2.setVisibility(View.GONE); imgNo.setVisibility(View.GONE); } // Init adapter / recycler view mAdapter = new MyPresalesAdapter(context); recList = (RecyclerView) findViewById(R.id.recyList); recList.setHasFixedSize(true); LinearLayoutManager llm = new LinearLayoutManager(context); llm.setOrientation(LinearLayoutManager.VERTICAL); recList.setLayoutManager(llm); recList.setAdapter(mAdapter); recList.addOnItemTouchListener( new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { ArrayList<SubEventItem> subTickets = ticketPictItems.get(position).getExternalEventItem() .getSubEventItems(); final ArrayList<SubEventItem> subTicketPrintable = new ArrayList<>(); for (int i = 0; i < subTickets.size(); i++) { SubEventItem sei = subTickets.get(i); if (sei.isAvailable()) { subTicketPrintable.add(sei); } } eventName = ticketPictItems.get(position).getExternalEventItem().getName(); eventDate = ticketPictItems.get(position).getExternalEventItem() .getDayAsString(ticketPictItems.get(position).getExternalEventItem().getDate()); CharSequence items[] = new CharSequence[subTicketPrintable.size()]; for (int i = 0; i < subTicketPrintable.size(); i++) items[i] = subTicketPrintable.get(i).getTitre() + " " + subTicketPrintable.get(i).getEventPriceAsString(); // Material dialog to show list of items new MaterialDialog.Builder(context).items(items).title("Tickets disponibles") .cancelable(true) // faster for user .positiveText(R.string.dialog_choose).negativeText(R.string.dialog_cancel) .itemsCallbackSingleChoice(0, new MaterialDialog.ListCallbackSingleChoice() { @Override public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) { // Conservation des paramtres eventID = subTicketPrintable.get(which).getId(); ticketName = "" + text; /** * Si venement activ, on propose les choix, sinon, message d'erreur */ /** * Check si navette dispo pour ce ticket : * - si navette : choix navette * - sinon : payer */ if (subTicketPrintable.get(which).hasShuttles()) { Intent i = new Intent(context, ShuttleActivity.class); TicketStore.getInstance() .setSelectedTicket(subTicketPrintable.get(which)); startActivityForResult(i, Constants.RESULT_SHUTTLES_KEY); } else { // Payer directement new MaterialDialog.Builder(context).title("Confirmer l'achat") .content(eventName + "\n" + ticketName + "\n" + eventDate + "\n\n" + "Les places seront nominatives.\nVotre carte tudiante vous sera demande l'entre.\nLes CGV s'appliquent.") .positiveText(R.string.dialog_pay) .negativeText(R.string.dialog_cancel) .callback(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { super.onPositive(dialog); AsyncSendTicket asyncSendTicket = new AsyncSendTicket( context); asyncSendTicket.execute(eventID); } }).show(); } return true; } }).show(); } })); // Set data mAdapter.setPictItems(ticketPictItems); // Timeout de 10 minutes max de commande (token prim aprs) new Handler().postDelayed(new Runnable() { @Override public void run() { if (context != null && isVisible) { showPeremptedToken(); } else { messageNotShown = true; } } }, MAX_DELAY_ORDER); } /** * Permet d'ajouter les vnements visibles dans un dataset utilisable par la RecyclerView */ private void fillArray() { if (ticketPictItems == null) ticketPictItems = new ArrayList<>(); ticketPictItems.clear(); ArrayList<EventItem> eventItems = TicketStore.getInstance().getEventItems(); for (int i = 0; i < eventItems.size(); i++) { EventItem ei = eventItems.get(i); if (!ei.isHeader() && !ei.isPassed() && ei.hasSubEventChildEnabled() && ei.hasSubEventChildPriced()) { ticketPictItems.add(new TicketPictItem(ei)); } } } /** * Permet d'envoyer la commande sur les serveurs */ private class AsyncSendTicket extends AsyncTask<String, String, String> { private MaterialDialog md; private Context context; public AsyncSendTicket(Context context) { this.context = context; } @Override protected void onPreExecute() { super.onPreExecute(); md = new MaterialDialog.Builder(context).title("Rservation en cours") .content("Veuillez patienter ...").progress(true, 0).progressIndeterminateStyle(false) .cancelable(false).show(); } @Override protected void onPostExecute(String data) { super.onPostExecute(data); md.hide(); int err = 0; String errMsg = "Erreur rseau"; if (Utilities.isNetworkDataValid(data)) { try { JSONObject obj = new JSONObject(data); err = obj.getInt("status"); errMsg = obj.getString("cause"); JSONObject objData = obj.getJSONObject("data"); idcmd = objData.getInt("idcmd"); } catch (JSONException e) { e.printStackTrace(); } } if (err == 1) { // Ok ! Send order to Lydia Intent i = new Intent(context, LydiaActivity.class); i.putExtra(Constants.KEY_LYDIA_ORDER_ID, idcmd); i.putExtra(Constants.KEY_LYDIA_ORDER_TYPE, Constants.TYPE_LYDIA_EVENT); i.putExtra(Constants.KEY_LYDIA_ORDER_ASKED, false); startActivityForResult(i, Constants.RESULT_LYDIA_KEY); } else { // Error, show message new MaterialDialog.Builder(context).title("Erreur") .content(errMsg + (err == 0 ? "" : " (code : " + err + ")")) .negativeText(R.string.dialog_close).show(); } } @Override protected String doInBackground(String... sData) { try { HashMap<String, String> params = new HashMap<>(); params.put(context.getResources().getString(R.string.token), TicketStore.getInstance().getToken()); params.put(context.getResources().getString(R.string.idevent), Base64.encodeToString(sData[0].getBytes("UTF-8"), Base64.NO_WRAP)); if (sData.length > 1 && sData[1] != null && sData[1].length() > 0) { params.put(context.getResources().getString(R.string.nav), Base64.encodeToString(sData[1].getBytes("UTF-8"), Base64.NO_WRAP)); } return ConnexionUtils.postServerData(Constants.URL_API_EVENT_SEND, params, context); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } } /** * Called when called Activities (child) finished */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // From Lydia-Activity if (requestCode == Constants.RESULT_LYDIA_KEY) { if (LydiaActivity.LAST_STATUS() == 2) { new MaterialDialog.Builder(context).title("Flicitations !").content( "Votre rservation a t paye.\nEntrez ci-dessous votre email afin de recevoir votre place au format PDF.\n\nNote : vous pouvez galement accder cette fentre depuis l'historique des rservations)") .cancelable(false).inputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) .input("sterling@archer.fr", "", new MaterialDialog.InputCallback() { @Override public void onInput(MaterialDialog dialog, CharSequence input) { AsyncEventEmail asyncEmail = new AsyncEventEmail(context, "" + input, PresalesActivity.this, userProfile, idcmd); // convert charSequence into String object asyncEmail.execute(); } }).show(); } else { new MaterialDialog.Builder(context).title("chec de la rservation").content( "Le paiement n'a pas abouti.\nImpossible de valider la transaction.\n\nRessayez plus tard ou contactez un membre du BDE.") .cancelable(false).negativeText(R.string.dialog_close) .callback(new MaterialDialog.ButtonCallback() { @Override public void onNegative(MaterialDialog dialog) { super.onNegative(dialog); PresalesActivity.this.finish(); } }).show(); } // From Shuttle-Activity } else if (requestCode == Constants.RESULT_SHUTTLES_KEY && resultCode == Activity.RESULT_OK) { // Get shuttle ID final String shuttleID = String.valueOf(data.getExtras().getInt(Constants.RESULT_SHUTTLES_VALUE)); final String shuttleName = data.getExtras().getString(Constants.RESULT_SHUTTLES_NAME); // Ask for user confirmation new MaterialDialog.Builder(context).title("Confirmer l'achat").content(eventName + "\n" + ticketName + "\n" + shuttleName + "\n\n" + "Les places seront nominatives.\nVotre carte tudiante vous sera demande l'entre.\nLes CGV s'appliquent.") .positiveText(R.string.dialog_pay).negativeText(R.string.dialog_cancel) .callback(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { super.onPositive(dialog); // Send network request AsyncSendTicket asyncSendTicket = new AsyncSendTicket(context); asyncSendTicket.execute(eventID, shuttleID); } }).show(); } } /** * Menu : back button + arrow in toolbar */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_empty, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar actions click switch (item.getItemId()) { case android.R.id.home: this.onBackPressed(); return true; default: return super.onOptionsItemSelected(item); } } @Override protected void onResume() { super.onResume(); isVisible = true; if (messageNotShown) { showPeremptedToken(); } } @Override protected void onPause() { super.onPause(); isVisible = false; } private void showPeremptedToken() { new MaterialDialog.Builder(context).title("Votre rservation a expir").content( "Pour des raisons de scurit, il est impossible d'effectuer une rservation pendant plus de 10 minutes sans avoir confim l'achat.\nMerci de bien vouloir recommencer ...") .cancelable(false).negativeText(R.string.dialog_close) .callback(new MaterialDialog.ButtonCallback() { @Override public void onNegative(MaterialDialog dialog) { super.onNegative(dialog); finish(); } }).show(); } }