diff --git a/.github/workflows/bintray-publish.yml b/.github/workflows/bintray-publish.yml new file mode 100644 index 0000000..f4a40f2 --- /dev/null +++ b/.github/workflows/bintray-publish.yml @@ -0,0 +1,26 @@ +name: Publish to bintray on closed PR +on: + release: + types: [released] + +jobs: + gradle: + strategy: + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + # Export properties + - name: Setup bintray credentials + env: + BINTRAY_APIKEY: ${{ secrets.BINTRAY_APIKEY }} + run: | + echo "bintray.user=queueitdevs" > ./local.properties + echo "bintray.apiKey=${BINTRAY_APIKEY}" >> ./local.properties + - uses: actions/setup-java@v1 + with: + java-version: 11 + - uses: eskatos/gradle-command-action@v1 + with: + arguments: assembleLibrary_androidx :library:assembleLibrary bintrayUpload \ No newline at end of file diff --git a/.github/workflows/gradle-build.yml b/.github/workflows/gradle-build.yml new file mode 100644 index 0000000..388a247 --- /dev/null +++ b/.github/workflows/gradle-build.yml @@ -0,0 +1,18 @@ +name: Run Gradle Build on Push +on: push +jobs: + gradle: + strategy: + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: Create local.properties + run: echo "" >> ./local.properties + - uses: actions/setup-java@v1 + with: + java-version: 11 + - uses: eskatos/gradle-command-action@v1 + with: + arguments: build \ No newline at end of file diff --git a/App integration flow.PNG b/App integration flow.PNG new file mode 100644 index 0000000..00eab46 Binary files /dev/null and b/App integration flow.PNG differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ddabc19 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Queue-it + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/android-webui-sdk.iml b/android-webui-sdk.iml new file mode 100644 index 0000000..760fee4 --- /dev/null +++ b/android-webui-sdk.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demoapp/src/library/java/com/queue_it/shopdemo/DeepActivity.java b/demoapp/src/library/java/com/queue_it/shopdemo/DeepActivity.java new file mode 100644 index 0000000..339d760 --- /dev/null +++ b/demoapp/src/library/java/com/queue_it/shopdemo/DeepActivity.java @@ -0,0 +1,29 @@ +package com.queue_it.shopdemo; + +import android.os.Bundle; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.snackbar.Snackbar; + +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; + +public class DeepActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_deep); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + 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 diff --git a/demoapp/src/library/java/com/queue_it/shopdemo/FirstFragment.java b/demoapp/src/library/java/com/queue_it/shopdemo/FirstFragment.java new file mode 100644 index 0000000..54e7b63 --- /dev/null +++ b/demoapp/src/library/java/com/queue_it/shopdemo/FirstFragment.java @@ -0,0 +1,33 @@ +package com.queue_it.shopdemo; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + + +public class FirstFragment extends Fragment { + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState + ) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_first, container, false); + } + + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { +// NavHostFragment.findNavController(FirstFragment.this) +// .navigate(R.id.action_FirstFragment_to_SecondFragment); + } + }); + } +} \ No newline at end of file diff --git a/demoapp/src/library/java/com/queue_it/shopdemo/MainActivity.java b/demoapp/src/library/java/com/queue_it/shopdemo/MainActivity.java new file mode 100644 index 0000000..2212f74 --- /dev/null +++ b/demoapp/src/library/java/com/queue_it/shopdemo/MainActivity.java @@ -0,0 +1,194 @@ +package com.queue_it.shopdemo; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.queue_it.androidsdk.*; +import com.queue_it.androidsdk.Error; + +public class MainActivity extends AppCompatActivity { + FloatingActionButton queue_button; + EditText customerIdEditText; + EditText eventIdEditText; + EditText layoutNameEditText; + EditText languageEditText; + EditText enqueueTokenEditText; + EditText enqueueKeyEditText; + RadioButton testRadioButton; + + private void runQueue(QueueITEngine queueITEngine) throws QueueITException { + String enqueueToken = enqueueTokenEditText.getText().toString(); + String enqueueKey = enqueueKeyEditText.getText().toString(); + if (enqueueToken.length() > 0) { + queueITEngine.runWithEnqueueToken(MainActivity.this, enqueueToken); + } else if (enqueueKey.length() > 0) { + queueITEngine.runWithEnqueueKey(MainActivity.this, enqueueKey); + } else { + queueITEngine.run(MainActivity.this); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + queue_button = findViewById(R.id.queue_button); + customerIdEditText = findViewById(R.id.customerid_edittext); + eventIdEditText = findViewById(R.id.eventid_edittext); + layoutNameEditText = findViewById(R.id.layoutname_edittext); + languageEditText = findViewById(R.id.language_edittext); + testRadioButton = findViewById(R.id.radio_environment_test); + customerIdEditText.addTextChangedListener(getRequiredTextValidator(customerIdEditText)); + eventIdEditText.addTextChangedListener(getRequiredTextValidator(eventIdEditText)); + enqueueTokenEditText = findViewById(R.id.enqueuetoken_edittext); + enqueueKeyEditText = findViewById(R.id.enqueuekey_edittext); + + final SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE); + String customerId = sharedPreferences.getString("customerId", ""); + String eventOrAliasId = sharedPreferences.getString("eventOrAliasId", ""); + String layoutName = sharedPreferences.getString("layoutName", ""); + String language = sharedPreferences.getString("language", ""); + String enqueueToken = sharedPreferences.getString("enqueueToken", ""); + String enqueueKey = sharedPreferences.getString("enqueueKey", ""); + + customerIdEditText.setText(customerId); + eventIdEditText.setText(eventOrAliasId); + layoutNameEditText.setText(layoutName); + languageEditText.setText(language); + enqueueTokenEditText.setText(enqueueToken); + enqueueKeyEditText.setText(enqueueKey); + + queue_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!TextUtils.isEmpty(customerIdEditText.getError()) || !TextUtils.isEmpty(eventIdEditText.getError())) { + return; + } + + queue_button.setEnabled(false); + QueueService.IsTest = testRadioButton.isChecked(); + hideKeyboard(); + + String customerId = customerIdEditText.getText().toString(); + String eventOrAliasId = eventIdEditText.getText().toString(); + String layoutName = layoutNameEditText.getText().toString(); + String language = languageEditText.getText().toString(); + String enqueueToken = enqueueTokenEditText.getText().toString(); + String enqueueKey = enqueueKeyEditText.getText().toString(); + + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString("customerId", customerId); + editor.putString("eventOrAliasId", eventOrAliasId); + editor.putString("layoutName", layoutName); + editor.putString("language", language); + editor.putString("enqueueToken", enqueueToken); + editor.putString("enqueueKey", enqueueKey); + editor.commit(); + + Toast.makeText(getApplicationContext(), "Please wait for your turn.", Toast.LENGTH_SHORT).show(); + + QueueITEngine queueITEngine = new QueueITEngine(MainActivity.this, customerId, eventOrAliasId, layoutName, language, new QueueListener() { + + @Override + public void onSessionRestart(QueueITEngine queueITEngine) { + try { + runQueue(queueITEngine); + } catch (QueueITException e) { + Toast.makeText(getApplicationContext(), "Please try again.", Toast.LENGTH_LONG).show(); + queue_button.setEnabled(true); + } + } + + @Override + public void onQueuePassed(QueuePassedInfo queuePassedInfo) { + showResultActivity("You passed the queue! Your token: " + queuePassedInfo.getQueueItToken(), true); + queue_button.setEnabled(true); + } + + @Override + public void onQueueViewWillOpen() { + Toast.makeText(getApplicationContext(), "onQueueViewWillOpen", Toast.LENGTH_SHORT).show(); + queue_button.setEnabled(true); + } + + @Override + public void onUserExited() { + Toast.makeText(getApplicationContext(), "onUserExited", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onQueueDisabled() { + showResultActivity("The queue is disabled.", false); + queue_button.setEnabled(true); + } + + @Override + public void onQueueItUnavailable() { + showResultActivity("Queue-it is unavailable", false); + queue_button.setEnabled(true); + } + + @Override + public void onError(Error error, String errorMessage) { + showResultActivity("Critical error: " + errorMessage, false); + queue_button.setEnabled(true); + } + + }); + try { + runQueue(queueITEngine); + } catch (QueueITException e) { + Toast.makeText(getApplicationContext(), "Please try again.", Toast.LENGTH_LONG).show(); + queue_button.setEnabled(true); + } + } + }); + } + + private void showResultActivity(String result, boolean success) { + Intent intent = new Intent(this, ResultActivity.class); + intent.putExtra("success", success); + intent.putExtra("result", result); + startActivity(intent); + } + + private boolean isAlphaNumeric(String s) { + String pattern = "^[a-zA-Z0-9]*$"; + return s.matches(pattern); + } + + private void hideKeyboard() { + View view = this.getCurrentFocus(); + if (view != null) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + private TextValidator getRequiredTextValidator(TextView textView) { + return new TextValidator(textView) { + @Override + public void validate(TextView textView, String text) { + if (TextUtils.isEmpty(text)) { + textView.setError("Field required"); + } else if (!isAlphaNumeric(text)) { + textView.setError("Must be alphanumeric"); + } + } + }; + } +} diff --git a/demoapp/src/library/java/com/queue_it/shopdemo/ResultActivity.java b/demoapp/src/library/java/com/queue_it/shopdemo/ResultActivity.java new file mode 100644 index 0000000..bff5f51 --- /dev/null +++ b/demoapp/src/library/java/com/queue_it/shopdemo/ResultActivity.java @@ -0,0 +1,56 @@ +package com.queue_it.shopdemo; + +import android.content.Intent; +import android.os.Bundle; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import android.support.v4.content.res.ResourcesCompat; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + + +public class ResultActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_result); + + String result; + boolean success; + if (savedInstanceState == null) { + Bundle extras = getIntent().getExtras(); + if (extras == null) { + result = null; + success = false; + } else { + result = extras.getString("result"); + success = extras.getBoolean("success"); + } + } else { + result = (String) savedInstanceState.getSerializable("result"); + success = (Boolean) savedInstanceState.getSerializable("success"); + } + + final TextView resultText = (TextView)findViewById(R.id.result_text); + final ImageView checkedImageView = (ImageView)findViewById(R.id.image_view_checked); + final FloatingActionButton retry_button = (FloatingActionButton)findViewById(R.id.retry_button); + + resultText.setText(result); + if (success){ + checkedImageView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_check_black_24dp, null)); + } else { + checkedImageView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_error_black_24dp, null)); + } + + retry_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(ResultActivity.this, MainActivity.class); + startActivity(intent); + finish(); + } + }); + } +} diff --git a/demoapp/src/library/java/com/queue_it/shopdemo/SecondFragment.java b/demoapp/src/library/java/com/queue_it/shopdemo/SecondFragment.java new file mode 100644 index 0000000..991ee41 --- /dev/null +++ b/demoapp/src/library/java/com/queue_it/shopdemo/SecondFragment.java @@ -0,0 +1,32 @@ +package com.queue_it.shopdemo; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class SecondFragment extends Fragment { + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState + ) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_second, container, false); + } + + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + view.findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { +// NavHostFragment.findNavController(SecondFragment.this) +// .navigate(R.id.action_SecondFragment_to_FirstFragment); + } + }); + } +} \ No newline at end of file diff --git a/demoapp/src/library/res/layout/activity_deep.xml b/demoapp/src/library/res/layout/activity_deep.xml new file mode 100644 index 0000000..08580ef --- /dev/null +++ b/demoapp/src/library/res/layout/activity_deep.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demoapp/src/library/res/layout/activity_main.xml b/demoapp/src/library/res/layout/activity_main.xml new file mode 100644 index 0000000..799260f --- /dev/null +++ b/demoapp/src/library/res/layout/activity_main.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demoapp/src/library/res/layout/activity_result.xml b/demoapp/src/library/res/layout/activity_result.xml new file mode 100644 index 0000000..b898426 --- /dev/null +++ b/demoapp/src/library/res/layout/activity_result.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/demoapp/src/library/res/layout/content_deep.xml b/demoapp/src/library/res/layout/content_deep.xml new file mode 100644 index 0000000..96f084d --- /dev/null +++ b/demoapp/src/library/res/layout/content_deep.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/demoapp/src/library/res/layout/fragment_first.xml b/demoapp/src/library/res/layout/fragment_first.xml new file mode 100644 index 0000000..8cf9428 --- /dev/null +++ b/demoapp/src/library/res/layout/fragment_first.xml @@ -0,0 +1,28 @@ + + + + + +