diff --git a/.gitignore b/.gitignore
index ea83a5e..dcdc776 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,44 +1,83 @@
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+# Built application files
+*.apk
+*.ap_
+*.aab
-# User-specific stuff:
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
.idea/workspace.xml
.idea/tasks.xml
-.idea/dictionaries
-.idea/vcs.xml
-.idea/jsLibraryMappings.xml
-
-# Sensitive or high-churn files:
-.idea/dataSources.ids
-.idea/dataSources.xml
-.idea/dataSources.local.xml
-.idea/sqlDataSources.xml
-.idea/dynamic.xml
-.idea/uiDesigner.xml
-
-# Gradle:
.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
-# Mongo Explorer plugin:
-.idea/mongoSettings.xml
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
-## File-based project format:
-*.iws
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
-## Plugin-specific files:
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
-# IntelliJ
-/out/
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
-# mpeltonen/sbt-idea plugin
-.idea_modules/
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
-# JIRA plugin
-atlassian-ide-plugin.xml
+# Version control
+vcs.xml
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..681f41a
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5d19981..f63a89a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,43 +1,45 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/README.md b/README.md
index 52749b2..7a94f5e 100644
--- a/README.md
+++ b/README.md
@@ -14,24 +14,20 @@ Una vez que haya recopilado la información de un cliente, tendrá que intercamb
## Creación de Token desde un formulario personalizado
-Puede crear tokens utilizando el método utilizando el método de instancia Culqi createToken
+Puede crear tokens utilizando el método utilizando el método getToken() del API enviando un objeto Card
Pasando el número de la tarjeta, cvv, la fecha de vencimiento y un correo
-```java
-Card card = new Card(“411111111111111”, “123”, 9, 2020, “wm@wm.com”);
-
-Token token = new Token("{CODIGO COMERCIO}");
-
-token.createToken(getApplicationContext(), card, new TokenCallback() {
- @Override
- public void onSuccess(JSONObject token) {
- // get Token
- token.get("id").toString()
- }
- @Override
- public void onError(Exception error) {
- }
-});
+```Kotlin
+mTokenRestDataStore.getToken(Card(
+ card_number = etMainCardNumber.text.toString(),
+ cvv = etMainCVV.text.toString(),
+ expiration_month = "09",
+ expiration_year = 2020,
+ email = etMainEmail.text.toString()
+ )
+
+//El CODIGO DEL COMERCIO se ingresa en build.gradle dentro de la carpeta app (Se reemplaza el por el CODIGO DEL COMERCIO
+//buildConfigField('String', 'AUTHORIZATION', '"Bearer "')
```
## Usando Tokens
diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index 3bdf759..0000000
--- a/app/app.iml
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index a7f4ed3..9391055 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,27 @@
apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion 29
defaultConfig {
applicationId "com.android.culqi.culqi_android"
- minSdkVersion 15
- targetSdkVersion 25
+ minSdkVersion 16
+ targetSdkVersion 29
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ multiDexEnabled true
+
+
+ buildConfigField('String', 'URL_SERVER', '"https://secure.culqi.com/v2/"')
+ buildConfigField('String', 'AUTHORIZATION', '"Bearer "')
+ buildConfigField('String', 'CONTENT_TYPE', '"application/json; charset=utf-8"')
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
@@ -20,11 +32,33 @@ android {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
- exclude group: 'com.android.support', module: 'support-annotations'
- })
- compile 'com.android.support:appcompat-v7:25.1.0'
- compile 'com.android.volley:volley:1.0.0'
- testCompile 'junit:junit:4.12'
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+
+ //AndroidX
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
+ //Retrofit
+ implementation 'com.squareup.retrofit2:retrofit:2.6.1'
+ implementation 'com.squareup.retrofit2:converter-moshi:2.6.1'
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1'
+ implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
+ implementation "com.squareup.okhttp3:logging-interceptor:4.2.0"
+
+ //Moshi
+ kapt "com.squareup.moshi:moshi-kotlin-codegen:1.8.0"
+
+ //Rx
+ implementation 'io.reactivex.rxjava2:rxjava:2.2.10'
+ implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
+ implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
+
+ //Koin
+ implementation 'org.koin:koin-android:2.0.1'
+
+ //Test
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cfe6302..184d4e5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
@@ -9,8 +10,10 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
-
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning"
+ android:name=".CulqiApplication">
+
diff --git a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Card.java b/app/src/main/java/com/android/culqi/culqi_android/Culqi/Card.java
deleted file mode 100644
index bcff8d8..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Card.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.android.culqi.culqi_android.Culqi;
-
-/**
- * Created by culqi on 2/7/17.
- */
-
-public class Card {
-
- public Card(String card_number, String cvv, int expiration_month, int expiration_year, String email) {
- this.card_number = card_number;
- this.cvv = cvv;
- this.expiration_month = expiration_month;
- this.expiration_year = expiration_year;
- this.email = email;
- }
-
- private String card_number;
-
- private String cvv;
-
- private int expiration_month;
-
- private int expiration_year;
-
- private String email;
-
- public String getCard_number() {
- return card_number;
- }
-
- public void setCard_number(String card_number) {
- this.card_number = card_number;
- }
-
- public String getCvv() {
- return cvv;
- }
-
- public void setCvv(String cvv) {
- this.cvv = cvv;
- }
-
- public int getExpiration_month() {
- return expiration_month;
- }
-
- public void setExpiration_month(int expiration_month) {
- this.expiration_month = expiration_month;
- }
-
- public int getExpiration_year() {
- return expiration_year;
- }
-
- public void setExpiration_year(int expiration_year) {
- this.expiration_year = expiration_year;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Config.java b/app/src/main/java/com/android/culqi/culqi_android/Culqi/Config.java
deleted file mode 100644
index e3ba45d..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Config.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.android.culqi.culqi_android.Culqi;
-
-/**
- * Created by culqi on 1/19/17.
- */
-
-public class Config {
-
- public String url_base = "https://api.culqi.com/v2";
- public String url_base_secure = "https://secure.culqi.com/v2";
-
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Token.java b/app/src/main/java/com/android/culqi/culqi_android/Culqi/Token.java
deleted file mode 100644
index b80dc4e..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/Culqi/Token.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.android.culqi.culqi_android.Culqi;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.android.volley.AuthFailureError;
-import com.android.volley.DefaultRetryPolicy;
-import com.android.volley.Request;
-import com.android.volley.RequestQueue;
-import com.android.volley.Response;
-import com.android.volley.VolleyError;
-import com.android.volley.toolbox.JsonObjectRequest;
-import com.android.volley.toolbox.Volley;
-
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by culqi on 1/19/17.
- */
-
-public class Token {
-
- Config config = new Config();
-
- private static final String URL = "/tokens/";
-
- private String api_key;
-
- private TokenCallback listener;
-
- public Token(String api_key){
- this.api_key = api_key;
- this.listener = null;
- }
-
- public void createToken(Context context, Card card, final TokenCallback listener) {
-
- this.listener = listener;
-
- RequestQueue requestQueue = Volley.newRequestQueue(context);
-
- JSONObject jsonBody = new JSONObject();
- try {
- jsonBody = new JSONObject();
- jsonBody.put("card_number", card.getCard_number());
- jsonBody.put("cvv", card.getCvv());
- jsonBody.put("expiration_month", card.getExpiration_month());
- jsonBody.put("expiration_year", card.getExpiration_year());
- jsonBody.put("email", card.getEmail());
- } catch (Exception ex){
- Log.v("", "ERROR: "+ex.getMessage());
- }
-
- JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, config.url_base_secure+URL,jsonBody, new Response.Listener(){
- @Override
- public void onResponse(JSONObject response) {
- try {
- listener.onSuccess(response);
- } catch (Exception ex){
- listener.onError(ex);
- }
- }
- }, new Response.ErrorListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- listener.onError(error);
- }
- }) {
- @Override
- public Map getHeaders() throws AuthFailureError {
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json; charset=utf-8");
- headers.put("Authorization", "Bearer " + Token.this.api_key);
- return headers;
- }
-
- };
-
- jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
- 30000,
- DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
- DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
-
- requestQueue.add(jsonObjectRequest);
-
- }
-
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/Culqi/TokenCallback.java b/app/src/main/java/com/android/culqi/culqi_android/Culqi/TokenCallback.java
deleted file mode 100644
index 9c4509e..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/Culqi/TokenCallback.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.android.culqi.culqi_android.Culqi;
-
-import org.json.JSONObject;
-
-/**
- * Created by culqi on 2/7/17.
- */
-
-public interface TokenCallback {
-
- public void onSuccess(JSONObject token);
-
- public void onError(Exception error);
-
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/CulqiApplication.kt b/app/src/main/java/com/android/culqi/culqi_android/CulqiApplication.kt
new file mode 100644
index 0000000..670127e
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/CulqiApplication.kt
@@ -0,0 +1,21 @@
+package com.android.culqi.culqi_android
+
+import android.app.Application
+import com.android.culqi.culqi_android.di.modules
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.context.startKoin
+
+class CulqiApplication : Application() {
+
+
+ override fun onCreate() {
+ super.onCreate()
+
+ startKoin {
+ androidContext(this@CulqiApplication)
+ androidLogger()
+ modules(modules)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/MainActivity.java b/app/src/main/java/com/android/culqi/culqi_android/MainActivity.java
deleted file mode 100644
index 3bc2092..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/MainActivity.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.android.culqi.culqi_android;
-
-import android.app.ProgressDialog;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.TextWatcher;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.android.culqi.culqi_android.Culqi.Card;
-import com.android.culqi.culqi_android.Culqi.Token;
-import com.android.culqi.culqi_android.Culqi.TokenCallback;
-import com.android.culqi.culqi_android.Validation.Validation;
-
-import org.json.JSONObject;
-
-public class MainActivity extends AppCompatActivity {
-
- Validation validation;
-
- ProgressDialog progress;
-
- TextView txtcardnumber, txtcvv, txtmonth, txtyear, txtemail, kind_card, result;
- Button btnPay;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- validation = new Validation();
-
- progress = new ProgressDialog(this);
- progress.setMessage("Validando informacion de la tarjeta");
- progress.setCancelable(false);
- progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-
- txtcardnumber = (TextView) findViewById(R.id.txt_cardnumber);
-
- txtcvv = (TextView) findViewById(R.id.txt_cvv);
-
- txtmonth = (TextView) findViewById(R.id.txt_month);
-
- txtyear = (TextView) findViewById(R.id.txt_year);
-
- txtemail = (TextView) findViewById(R.id.txt_email);
-
- kind_card = (TextView) findViewById(R.id.kind_card);
-
- result = (TextView) findViewById(R.id.token_id);
-
- btnPay = (Button) findViewById(R.id.btn_pay);
-
- txtcvv.setEnabled(false);
-
- txtcardnumber.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) {
- if(s.length() == 0){
- txtcvv.setEnabled(true);
- }
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String text = txtcardnumber.getText().toString();
- if(s.length() == 0) {
- txtcardnumber.setBackgroundResource(R.drawable.border_error);
- }
-
- if(validation.luhn(text)) {
- txtcardnumber.setBackgroundResource(R.drawable.border_sucess);
- } else {
- txtcardnumber.setBackgroundResource(R.drawable.border_error);
- }
-
- int cvv = validation.bin(text, kind_card);
- if(cvv > 0) {
- txtcvv.setFilters(new InputFilter[]{new InputFilter.LengthFilter(cvv)});
- txtcvv.setEnabled(true);
- } else {
- txtcvv.setEnabled(false);
- txtcvv.setText("");
- }
- }
- });
-
- txtyear.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) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String text = txtyear.getText().toString();
- if(validation.year(text)){
- txtyear.setBackgroundResource(R.drawable.border_error);
- } else {
- txtyear.setBackgroundResource(R.drawable.border_sucess);
- }
- }
- });
-
- txtmonth.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) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String text = txtmonth.getText().toString();
- if(validation.month(text)){
- txtmonth.setBackgroundResource(R.drawable.border_error);
- } else {
- txtmonth.setBackgroundResource(R.drawable.border_sucess);
- }
- }
- });
-
- btnPay.setOnClickListener(new View.OnClickListener(){
- public void onClick(View v){
- progress.show();
-
- Card card = new Card(txtcardnumber.getText().toString(), txtcvv.getText().toString(), 9, 2020, txtemail.getText().toString());
-
- Token token = new Token("pk_test_vzMuTHoueOMlgUPj");
-
- token.createToken(getApplicationContext(), card, new TokenCallback() {
- @Override
- public void onSuccess(JSONObject token) {
- try {
- result.setText(token.get("id").toString());
- } catch (Exception ex){
- progress.hide();
- }
- progress.hide();
- }
-
- @Override
- public void onError(Exception error) {
- progress.hide();
- }
- });
-
- }
- });
-
- }
-
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/Validation/Validation.java b/app/src/main/java/com/android/culqi/culqi_android/Validation/Validation.java
deleted file mode 100644
index 83b23f5..0000000
--- a/app/src/main/java/com/android/culqi/culqi_android/Validation/Validation.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.android.culqi.culqi_android.Validation;
-
-import android.widget.TextView;
-
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * Created by culqi on 1/19/17.
- */
-
-public class Validation {
-
- public static boolean luhn(String number){
- int s1 = 0, s2 = 0;
- String reverse = new StringBuffer(number).reverse().toString();
- for(int i = 0 ;i < reverse.length();i++){
- int digit = Character.digit(reverse.charAt(i), 10);
- if(i % 2 == 0){//this is for odd digits, they are 1-indexed in the algorithm
- s1 += digit;
- }else{//add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
- s2 += 2 * digit;
- if(digit >= 5){
- s2 -= 9;
- }
- }
- }
- return (s1 + s2) % 10 == 0;
- }
-
- public int bin(String bin, final TextView kind_card) {
-
- if(bin.length() > 1) {
- if(Integer.valueOf(bin.substring(0,2)) == 41) {
- kind_card.setText("VISA");
- return 3;
- } else if (Integer.valueOf(bin.substring(0,2)) == 51) {
- kind_card.setText("MasterCard");
- return 3;
- } else {
- }
- } else {
- kind_card.setText("");
- }
-
- if(bin.length() > 1) {
- if(Integer.valueOf(bin.substring(0,2)) == 36){
- kind_card.setText("Diners Club");
- return 3;
- } else if(Integer.valueOf(bin.substring(0,2)) == 38){
- kind_card.setText("Diners Club");
- return 3;
- } else if(Integer.valueOf(bin.substring(0,2)) == 37){
- kind_card.setText("AMEX");
- return 3;
- } else {
- }
- }
-
- if(bin.length() > 2) {
- if(Integer.valueOf(bin.substring(0,3)) == 300){
- kind_card.setText("Diners Club");
- return 3;
- } else if(Integer.valueOf(bin.substring(0,3)) == 305){
- kind_card.setText("Diners Club");
- return 3;
- } else {
- }
- }
- return 0;
- }
-
- public boolean month(String month) {
- if(!month.equals("")){
- if(Integer.valueOf(""+month) > 12) {
- return true;
- }
- }
- return false;
- }
-
- public boolean year(String year){
- Date today = new Date();
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(today);
- if(!year.equals("")){
- if(Integer.valueOf("20"+year) < calendar.get(Calendar.YEAR)) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/app/src/main/java/com/android/culqi/culqi_android/activities/MainActivity.kt b/app/src/main/java/com/android/culqi/culqi_android/activities/MainActivity.kt
new file mode 100644
index 0000000..d49a100
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/activities/MainActivity.kt
@@ -0,0 +1,129 @@
+package com.android.culqi.culqi_android.activities
+
+import android.app.ProgressDialog
+import android.os.Bundle
+import android.text.Editable
+import android.text.InputFilter
+import android.text.TextWatcher
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import com.android.culqi.culqi_android.R
+import com.android.culqi.culqi_android.rest.TokenRestDataStore
+import com.android.culqi.culqi_android.model.Card
+import com.android.culqi.culqi_android.utils.Validation
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.android.synthetic.main.activity_main.*
+
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var progress:ProgressDialog
+
+ protected val disposables = CompositeDisposable()
+
+ private val mTokenRestDataStore by lazy { TokenRestDataStore() }
+
+ internal lateinit var validation: Validation
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ validation = Validation()
+
+ progress = ProgressDialog(this)
+ progress.setMessage("Validando informacion de la tarjeta")
+ progress.setCancelable(false)
+ progress.setProgressStyle(ProgressDialog.STYLE_SPINNER)
+
+ etMainCardNumber.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ if (s.isEmpty()) {
+ etMainCVV.isEnabled = true
+ }
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ val text = etMainCardNumber.text.toString()
+ if (s.length == 0) {
+ etMainCardNumber.setBackgroundResource(R.drawable.border_error)
+ }
+
+ if (validation.luhn(text)) {
+ etMainCardNumber.setBackgroundResource(R.drawable.border_sucess)
+ } else {
+ etMainCardNumber.setBackgroundResource(R.drawable.border_error)
+ }
+
+ val cvv = validation.bin(text)
+ tvMainKindCard.text = cvv.first
+ if (cvv.second > 0) {
+ etMainCVV.filters = arrayOf(InputFilter.LengthFilter(cvv.second))
+ etMainCVV.isEnabled = true
+ } else {
+ etMainCVV.isEnabled = false
+ etMainCVV.setText("")
+ }
+ }
+ })
+
+ etMainYear.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(s: Editable) {
+ val text = etMainYear.text.toString()
+ if (validation.year(text)) {
+ etMainYear.setBackgroundResource(R.drawable.border_error)
+ } else {
+ etMainYear.setBackgroundResource(R.drawable.border_sucess)
+ }
+ }
+ })
+
+ etMainMonth.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(s: Editable) {
+ val text = etMainMonth.text.toString()
+ if (validation.month(text)) {
+ etMainMonth.setBackgroundResource(R.drawable.border_error)
+ } else {
+ etMainMonth.setBackgroundResource(R.drawable.border_sucess)
+ }
+ }
+ })
+
+ btMainCreateToken.setOnClickListener {
+ progress.show()
+ disposables.add(mTokenRestDataStore.getToken(Card(
+ card_number = etMainCardNumber.text.toString(),
+ cvv = etMainCVV.text.toString(),
+ expiration_month = "09",
+ expiration_year = 2020,
+ email = etMainEmail.text.toString()
+ ))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ progress.hide()
+ tvMainTokenId.text = it.id
+ }, {
+ progress.hide()
+ Log.d("Error", "${it.message}")
+ })
+ )
+ }
+
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ disposables.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/di/modules.kt b/app/src/main/java/com/android/culqi/culqi_android/di/modules.kt
new file mode 100644
index 0000000..4a81156
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/di/modules.kt
@@ -0,0 +1,17 @@
+package com.android.culqi.culqi_android.di
+
+import com.android.culqi.culqi_android.rest.TokenRestDataStore
+import org.koin.dsl.module
+
+private val mainModule = module {
+ //region Datastore
+ single {
+ TokenRestDataStore()
+ }
+ //endregion
+}
+
+
+val modules = listOf(
+ mainModule
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/model/Card.kt b/app/src/main/java/com/android/culqi/culqi_android/model/Card.kt
new file mode 100644
index 0000000..491a2fc
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/model/Card.kt
@@ -0,0 +1,10 @@
+package com.android.culqi.culqi_android.model
+
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class Card(val card_number: String,
+ val cvv: String,
+ val expiration_month: String,
+ val expiration_year: Int,
+ val email: String)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/model/Token.kt b/app/src/main/java/com/android/culqi/culqi_android/model/Token.kt
new file mode 100644
index 0000000..55f3c35
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/model/Token.kt
@@ -0,0 +1,14 @@
+package com.android.culqi.culqi_android.model
+
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class Token(
+ val id: String?,
+ val type: String?,
+ val creation_date: Long?,
+ val email: String?,
+ val card_number: String?,
+ val last_four: String?,
+ val active: Boolean?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/rest/ApiClient.kt b/app/src/main/java/com/android/culqi/culqi_android/rest/ApiClient.kt
new file mode 100644
index 0000000..73489af
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/rest/ApiClient.kt
@@ -0,0 +1,5 @@
+package com.android.culqi.culqi_android.rest
+
+import com.android.culqi.culqi_android.rest.interfaces.ITokenApiClient
+
+object TokenApiClient: BaseApiClient(ITokenApiClient::class.java)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/rest/BaseApiClient.kt b/app/src/main/java/com/android/culqi/culqi_android/rest/BaseApiClient.kt
new file mode 100644
index 0000000..012de0d
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/rest/BaseApiClient.kt
@@ -0,0 +1,45 @@
+package com.android.culqi.culqi_android.rest
+
+import android.content.Context
+import com.android.culqi.culqi_android.BuildConfig
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.koin.core.KoinComponent
+import org.koin.core.inject
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.converter.moshi.MoshiConverterFactory
+import java.util.concurrent.TimeUnit
+
+open class BaseApiClient(private val classT: Class) : KoinComponent {
+ private val HEADER_AUTHORIZATION = "Authorization"
+ private val HEADER_AUTHORIZATION_TYPE = "Bearer "
+ private val context: Context by inject()
+
+ open fun getApiClient(
+ CONNECTION_TIMEOUT: Long = 180L,
+ READ_TIMEOUT: Long = 180L,
+ WRITE_TIMEOUT: Long = 180L
+ ): T {
+
+ val httpLoggingInterceptor = HttpLoggingInterceptor()
+ httpLoggingInterceptor.level= HttpLoggingInterceptor.Level.BODY
+
+ val okHttpClient = OkHttpClient().newBuilder()
+ .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
+ .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
+ .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
+ .addInterceptor(httpLoggingInterceptor)
+ .build()
+
+ val retrofitBuilder = Retrofit.Builder().apply {
+ baseUrl(BuildConfig.URL_SERVER)
+ client(okHttpClient)
+ addConverterFactory(MoshiConverterFactory.create())
+ addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+ }
+
+ val retrofit = retrofitBuilder.build()
+ return retrofit.create(classT)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/rest/TokenRestDataStore.kt b/app/src/main/java/com/android/culqi/culqi_android/rest/TokenRestDataStore.kt
new file mode 100644
index 0000000..56e0ce8
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/rest/TokenRestDataStore.kt
@@ -0,0 +1,12 @@
+package com.android.culqi.culqi_android.rest
+
+import com.android.culqi.culqi_android.model.Card
+import com.android.culqi.culqi_android.model.Token
+import io.reactivex.Single
+
+class TokenRestDataStore {
+
+ fun getToken(card: Card): Single {
+ return TokenApiClient.getApiClient().getToken(card = card)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/rest/interfaces/ITokenApiClient.kt b/app/src/main/java/com/android/culqi/culqi_android/rest/interfaces/ITokenApiClient.kt
new file mode 100644
index 0000000..99e9794
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/rest/interfaces/ITokenApiClient.kt
@@ -0,0 +1,18 @@
+package com.android.culqi.culqi_android.rest.interfaces
+
+import com.android.culqi.culqi_android.BuildConfig
+import com.android.culqi.culqi_android.model.Card
+import com.android.culqi.culqi_android.model.Token
+import io.reactivex.Single
+import retrofit2.http.Body
+import retrofit2.http.Header
+import retrofit2.http.POST
+
+interface ITokenApiClient {
+
+ @POST("tokens/")
+ fun getToken(@Header("Authorization") authorization: String = BuildConfig.AUTHORIZATION,
+ @Header("Content-Type") contentType:String = BuildConfig.CONTENT_TYPE,
+ @Body card: Card): Single
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/culqi/culqi_android/utils/Validation.kt b/app/src/main/java/com/android/culqi/culqi_android/utils/Validation.kt
new file mode 100644
index 0000000..ca0beee
--- /dev/null
+++ b/app/src/main/java/com/android/culqi/culqi_android/utils/Validation.kt
@@ -0,0 +1,81 @@
+package com.android.culqi.culqi_android.utils
+
+import java.util.*
+
+class Validation {
+
+ fun bin(bin: String): Pair {
+
+ if (bin.length > 1) {
+ when (Integer.valueOf(bin.substring(0, 2))) {
+ 36 -> {
+ return Pair("Diners Club",3)
+ }
+ 37 -> {
+ return Pair("Diners Club",3)
+ }
+ 38 -> {
+ return Pair("Diners Club",3)
+ }
+ 41 -> {
+ return Pair("VISA",3)
+ }
+ 51 -> {
+ return Pair("MasterCard",3)
+ }
+ }
+ }
+
+ if (bin.length > 2) {
+ when (Integer.valueOf(bin.substring(0, 3))) {
+ 300 -> {
+ return Pair("Diners Club",3)
+ }
+ 305 -> {
+ return Pair("Diners Club",3)
+ }
+ }
+ }
+ return Pair("",0)
+ }
+
+ fun month(month: String): Boolean {
+ if (month != "") {
+ if (month.toInt() > 12) {
+ return true
+ }
+ }
+ return false
+ }
+
+ fun year(year: String): Boolean {
+ val today = Date()
+ val calendar = Calendar.getInstance()
+ calendar.time = today
+ if (year != "") {
+ if (Integer.valueOf("20$year") < calendar.get(Calendar.YEAR)) {
+ return true
+ }
+ }
+ return false
+ }
+
+ fun luhn(number: String): Boolean {
+ var s1 = 0
+ var s2 = 0
+ val reverse = StringBuffer(number).reverse().toString()
+ for (i in 0 until reverse.length) {
+ val digit = Character.digit(reverse[i], 10)
+ if (i % 2 == 0) {//this is for odd digits, they are 1-indexed in the algorithm
+ s1 += digit
+ } else {//add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
+ s2 += 2 * digit
+ if (digit >= 5) {
+ s2 -= 9
+ }
+ }
+ }
+ return (s1 + s2) % 10 == 0
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index cb7f5c1..9388eba 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,123 +1,123 @@
-
+ android:selectAllOnFocus="false"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+ android:layout_marginTop="19dp"
+ android:background="@drawable/border"
+ android:ems="10"
+ android:hint="@string/main_month"
+ android:inputType="number"
+ android:maxLength="2"
+ app:layout_constraintEnd_toStartOf="@+id/etMainYear"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/etMainCardNumber" />
+ android:background="@drawable/border"
+ android:ems="10"
+ android:hint="@string/main_year"
+ android:inputType="number"
+ android:maxLength="2"
+ app:layout_constraintBaseline_toBaselineOf="@+id/etMainMonth"
+ app:layout_constraintEnd_toStartOf="@+id/etMainCVV"
+ app:layout_constraintStart_toEndOf="@+id/etMainMonth" />
+
+
+ android:ems="10"
+ android:hint="@string/main_email"
+ android:inputType="textEmailAddress" />
-
-
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="30dp"
+ android:text="@string/main_create_token" />
+ app:layout_constraintTop_toBottomOf="@+id/btMainCreateToken"
+ android:layout_marginTop="24dp"
+ android:textSize="18sp" />
+ app:layout_constraintTop_toBottomOf="@+id/tvMainTokenId"
+ android:layout_marginTop="24dp"
+ android:textSize="18sp" />
-
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 00a989b..732f0e2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,11 @@
Culqi-Android
+
+ Card Number
+ Mes
+ Año
+ CVV
+ Correo electronico
+ Crear Token
+
diff --git a/build.gradle b/build.gradle
index b78a0b8..464bb36 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,11 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
+ ext.kotlin_version = '1.3.50'
repositories {
+ google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:3.5.1'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -14,7 +17,9 @@ buildscript {
allprojects {
repositories {
+ google()
jcenter()
+ maven { url 'https://jitpack.io' }
}
}
diff --git a/build/android-profile/profile-2017-05-26-06-35-24-516.rawproto b/build/android-profile/profile-2017-05-26-06-35-24-516.rawproto
deleted file mode 100644
index baac5ee..0000000
Binary files a/build/android-profile/profile-2017-05-26-06-35-24-516.rawproto and /dev/null differ
diff --git a/build/android-profile/profile-2017-05-26-06-45-22-633.rawproto b/build/android-profile/profile-2017-05-26-06-45-22-633.rawproto
deleted file mode 100644
index 975a422..0000000
Binary files a/build/android-profile/profile-2017-05-26-06-45-22-633.rawproto and /dev/null differ
diff --git a/build/android-profile/profile-2017-05-26-06-50-22-656.rawproto b/build/android-profile/profile-2017-05-26-06-50-22-656.rawproto
deleted file mode 100644
index f5614c8..0000000
Binary files a/build/android-profile/profile-2017-05-26-06-50-22-656.rawproto and /dev/null differ
diff --git a/build/android-profile/profile-2017-05-26-06-54-06-890.rawproto b/build/android-profile/profile-2017-05-26-06-54-06-890.rawproto
deleted file mode 100644
index ad802b2..0000000
Binary files a/build/android-profile/profile-2017-05-26-06-54-06-890.rawproto and /dev/null differ
diff --git a/build/generated/mockable-android-25.jar b/build/generated/mockable-android-25.jar
deleted file mode 100644
index 4b65e43..0000000
Binary files a/build/generated/mockable-android-25.jar and /dev/null differ
diff --git a/build/intermediates/dex-cache/cache.xml b/build/intermediates/dex-cache/cache.xml
deleted file mode 100644
index a58dece..0000000
--- a/build/intermediates/dex-cache/cache.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
diff --git a/culqi-android.iml b/culqi-android.iml
index 8ae6231..8cff6c1 100644
--- a/culqi-android.iml
+++ b/culqi-android.iml
@@ -8,7 +8,7 @@
-
+
@@ -16,4 +16,4 @@
-
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c8e54c6..db33a10 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/local.properties b/local.properties
deleted file mode 100644
index 2d6055d..0000000
--- a/local.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-## This file is automatically generated by Android Studio.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-#
-# Location of the SDK. This is only used by Gradle.
-# For customization when using a Version Control System, please read the
-# header note.
-#Fri May 26 06:34:04 PET 2017
-sdk.dir=/Volumes/Data/android-sdk-macosx