Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
fc07b8b
removal of ui-integration module
ajungg Dec 3, 2021
b2b1259
add checkout activity
ajungg Dec 8, 2021
5d5871f
move fragments to corresponding packages
ajungg Dec 8, 2021
f1e58a1
Rename .java to .kt
ajungg Dec 8, 2021
97c516a
convert fragments to kotlin
ajungg Dec 8, 2021
4ad2e3e
simplify checkout view orchestration
ajungg Dec 9, 2021
431c5bc
update kotlin sample and introduce helper method
ajungg Dec 9, 2021
cc02138
fixes material 3 theme not being applied in activities and cleanup
ajungg Dec 13, 2021
58757d2
add remaining activities
ajungg Dec 13, 2021
1e75d49
Merge branch 'master' into activity_navigation
ajungg Dec 14, 2021
e9354fe
simpler, opt-in ui api
ajungg Dec 14, 2021
8363316
show add code by default
ajungg Dec 14, 2021
1878bfa
fix kotlin sample
ajungg Dec 14, 2021
9aeb74d
update docs
ajungg Dec 14, 2021
93b61fa
simpler api, protect against activity leaks, handle go back in activi…
ajungg Dec 15, 2021
ef7e856
safeguard against misuse
ajungg Dec 15, 2021
66681c3
improve sdk api
ajungg Dec 16, 2021
1f0a40d
bugfixes for new sdk api
ajungg Dec 16, 2021
26f982f
add support for toolbar in activities
ajungg Dec 17, 2021
f4dc70e
make SEPACardInputActivity a BaseFragmentActivity child, Fix SEPACard…
ajungg Dec 17, 2021
98292f6
bump version + update changelog
ajungg Dec 17, 2021
6c1ac5a
fix lint warning
ajungg Dec 17, 2021
3ea37c8
Merge branch 'master' into activity_navigation
ajungg Jan 10, 2022
0ae8dc7
[APPS-71] add exit token expiry hint
ajungg Jan 10, 2022
8f41085
WIP routing targets
ajungg Jan 11, 2022
ffd1b55
fix handling of user aborts
ajungg Jan 13, 2022
2d56273
Merge branch 'activity_navigation' into routing_targets
ajungg Jan 13, 2022
14f5587
Merge branch 'master' into activity_navigation
ajungg Jan 13, 2022
280a267
fix merge
ajungg Jan 13, 2022
102ed20
Merge branch 'activity_navigation' into routing_targets
ajungg Jan 13, 2022
885738c
[WIP] more routing targets
ajungg Jan 13, 2022
0764154
fix qrcode offline finish
ajungg Jan 14, 2022
a4f5481
Merge branch 'master' into activity_navigation
ajungg Jan 14, 2022
6c97b32
Merge branch 'activity_navigation' into routing_targets
ajungg Jan 14, 2022
cc134b0
[wip] more routing target improvements
ajungg Jan 14, 2022
f3dbb13
use handoverInformation
ajungg Jan 14, 2022
81d2873
bugfixes for routing targets
ajungg Jan 17, 2022
322f0ad
update version + changelog
ajungg Jan 17, 2022
48a6f57
show small selector when only credentials payment are available
ajungg Jan 17, 2022
5e8dad1
allow 0 cost carts
ajungg Jan 17, 2022
2ac965d
lots of minor changes
ajungg Jan 19, 2022
57a5365
clean up CheckoutBar state handling
ajungg Jan 19, 2022
ddc8fda
more minor clean up
ajungg Jan 19, 2022
e87abc1
fix payment selection
ajungg Jan 20, 2022
144f238
handle none state in checkout activity
ajungg Jan 20, 2022
de483aa
hide pay selector when cart is empty
ajungg Jan 24, 2022
3a79676
add some documentation
ajungg Jan 24, 2022
64f8dcd
always show payment status
ajungg Jan 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
# Changelog
All notable changes to this project will be documented in this file.

## [0.60.0-alpha02]

### Changes
- Add support for new Routing Targets API

## [0.60.0-alpha01]

### Breaking Changes
- Removed 'ui-integration' module and integrated it into 'ui'
- All Fragments have its package name changed due to this.
- Now supporting Activities for all screens. For example 'SelfScanningActivity' for the Scanner.
Refer to the Documentation for a list of all Activites/Fragments and View's
- Removed SnabbleUI.registerUiCallbacks in favor of SnabbleUI.setUiAction
- UI Callback are now entirely optional, and Activites will be launched if a UI Event is not implemented
by the hosting application
- Upgrading from 0.52.x requires the callbacks to be changed, but the general flow is the same if you were using Fragments
- Cleanup is done automatically, no SnabbleUI.unregisterUiCallbacks is necessary anymore!
- Checkout is now done in it's own Activity and can be started by using CheckoutActivity.startCheckoutFlow

### Notes
- Toolbar can be enabled in Activities by setting **snabbleToolbarStyle** in your Application theme

## [0.53.0]

### Changed
Expand Down
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ dependencies {

// user interface library
implementation 'io.snabble.sdk:ui:{currentVersion}'

// user interface integration library, entirely optional,
// for more seamless and easier integration in apps
implementation 'io.snabble.sdk:ui-integration:{currentVersion}'
}
```

Expand Down
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ allprojects {
}

project.ext {
sdkVersion='0.53.0'
sdkVersion='0.60.0-alpha02'
versionCode=1

compileSdkVersion=31
minSdkVersion=21
targetSdkVersion=31

buildToolsVersion='30.0.2'
okhttpVersion='4.9.1'
desugarVersion='1.1.5'

Expand Down
1 change: 0 additions & 1 deletion core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ apply plugin: 'org.jetbrains.dokka'

android {
compileSdkVersion project.compileSdkVersion
buildToolsVersion project.buildToolsVersion

defaultConfig {
minSdkVersion project.minSdkVersion
Expand Down
95 changes: 65 additions & 30 deletions core/src/main/java/io/snabble/sdk/Checkout.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,15 @@ public enum State {
*/
REQUEST_PAYMENT_AUTHORIZATION_TOKEN,
/**
* Payment was received by the backend and we are waiting for confirmation of the payment provider
* Checkout was received and we wait for confirmation by the supervisor
*/
WAIT_FOR_SUPERVISOR,
/**
* Checkout was received and we wait for confirmation by the gatekeeper
*/
WAIT_FOR_GATEKEEPER,
/**
* Payment was received by the backend and we are waiting for confirmation by the payment provider
*/
WAIT_FOR_APPROVAL,
/**
Expand Down Expand Up @@ -158,15 +166,15 @@ public void abort() {
* was cancelled
*/
public void abort(boolean error) {
cancelOutstandingCalls();

if (state != Checkout.State.PAYMENT_APPROVED
&& state != Checkout.State.DENIED_BY_PAYMENT_PROVIDER
&& state != Checkout.State.DENIED_BY_SUPERVISOR
&& checkoutProcess != null) {
checkoutApi.abort(checkoutProcess, new CheckoutApi.PaymentAbortResult() {
@Override
public void success() {
cancelOutstandingCalls();

synchronized (Checkout.this) {
if (error) {
notifyStateChanged(Checkout.State.PAYMENT_PROCESSING_ERROR);
Expand Down Expand Up @@ -236,13 +244,6 @@ public void reset() {
shop = null;
}

public void resume() {
if (lastState == Checkout.State.WAIT_FOR_APPROVAL || lastState == State.REQUEST_PAYMENT_AUTHORIZATION_TOKEN) {
notifyStateChanged(Checkout.State.WAIT_FOR_APPROVAL);
pollForResult();
}
}

public boolean isAvailable() {
return project.getCheckoutUrl() != null && project.isCheckoutAvailable();
}
Expand Down Expand Up @@ -397,22 +398,6 @@ public void success(CheckoutApi.CheckoutProcessResponse checkoutProcessResponse,
rawCheckoutProcess = rawResponse;

if (!handleProcessResponse()) {
boolean allChecksOk = areAllChecksSucceeded(checkoutProcessResponse);

if (allChecksOk) {
if (checkoutProcessResponse.paymentState == CheckoutApi.State.PROCESSING) {
Logger.d("Processing payment...");
notifyStateChanged(Checkout.State.PAYMENT_PROCESSING);
} else {
Logger.d("Waiting for approval...");
if (paymentMethod != PaymentMethod.GOOGLE_PAY) {
notifyStateChanged(Checkout.State.WAIT_FOR_APPROVAL);
}
}
} else {
notifyStateChanged(Checkout.State.WAIT_FOR_APPROVAL);
}

if (!paymentMethod.isOfflineMethod()) {
scheduleNextPoll();
}
Expand Down Expand Up @@ -457,7 +442,7 @@ private boolean areAllChecksSucceeded(CheckoutApi.CheckoutProcessResponse checko

if (checkoutProcessResponse.checks != null) {
for (CheckoutApi.Check check : checkoutProcessResponse.checks) {
if (check.state == CheckoutApi.State.FAILED) {
if (check.state != CheckoutApi.State.SUCCESSFUL) {
return false;
}

Expand Down Expand Up @@ -493,6 +478,30 @@ private boolean areAllChecksSucceeded(CheckoutApi.CheckoutProcessResponse checko
return allChecksOk;
}

private boolean hasAnyCheckFailed(CheckoutApi.CheckoutProcessResponse checkoutProcessResponse) {
if (checkoutProcessResponse.checks != null) {
for (CheckoutApi.Check check : checkoutProcessResponse.checks) {
if (check.state == CheckoutApi.State.FAILED) {
return true;
}
}
}

return false;
}

private boolean hasAnyFulfillmentAllocationFailed() {
if (checkoutProcess.fulfillments != null) {
for (CheckoutApi.Fulfillment fulfillment : checkoutProcess.fulfillments) {
if (fulfillment.state == FulfillmentState.ALLOCATION_FAILED || fulfillment.state == FulfillmentState.ALLOCATION_TIMED_OUT) {
return true;
}
}
}

return false;
}

private boolean hasStillPendingChecks(CheckoutApi.CheckoutProcessResponse checkoutProcessResponse) {
if (checkoutProcessResponse.checks != null) {
for (CheckoutApi.Check check : checkoutProcessResponse.checks) {
Expand Down Expand Up @@ -569,6 +578,8 @@ private void pollForResult() {

Logger.d("Polling for approval state...");

Logger.d("RoutingTarget = " + getRoutingTarget());

checkoutApi.updatePaymentProcess(checkoutProcess, new CheckoutApi.PaymentProcessResult() {
@Override
public void success(CheckoutApi.CheckoutProcessResponse checkoutProcessResponse, String rawResponse) {
Expand All @@ -589,6 +600,8 @@ public void error() {
});

if (state == Checkout.State.WAIT_FOR_APPROVAL
|| state == State.WAIT_FOR_GATEKEEPER
|| state == State.WAIT_FOR_SUPERVISOR
|| state == State.VERIFYING_PAYMENT_METHOD
|| state == State.REQUEST_PAYMENT_AUTHORIZATION_TOKEN
|| state == Checkout.State.PAYMENT_PROCESSING
Expand All @@ -608,6 +621,18 @@ private boolean handleProcessResponse() {
return true;
}

if (state == State.VERIFYING_PAYMENT_METHOD) {
if (checkoutProcess.routingTarget == CheckoutApi.RoutingTarget.SUPERVISOR) {
notifyStateChanged(State.WAIT_FOR_SUPERVISOR);
} else if (checkoutProcess.routingTarget == CheckoutApi.RoutingTarget.GATEKEEPER) {
notifyStateChanged(State.WAIT_FOR_GATEKEEPER);
} else {
notifyStateChanged(State.WAIT_FOR_APPROVAL);
}

return false;
}

String authorizePaymentUrl = checkoutProcess.getAuthorizePaymentLink();
if (authorizePaymentUrl != null) {
if (authorizePaymentRequestFailed) {
Expand Down Expand Up @@ -651,11 +676,12 @@ private boolean handleProcessResponse() {
return false;
}

if (hasStillPendingChecks(checkoutProcess)) {
notifyStateChanged(State.WAIT_FOR_APPROVAL);
if (hasAnyFulfillmentAllocationFailed()) {
notifyStateChanged(State.PAYMENT_ABORTED);
return true;
}

if (!areAllChecksSucceeded(checkoutProcess)) {
if (hasAnyCheckFailed(checkoutProcess)) {
Logger.d("Payment denied by supervisor");
shoppingCart.generateNewUUID();
notifyStateChanged(Checkout.State.DENIED_BY_SUPERVISOR);
Expand Down Expand Up @@ -708,6 +734,7 @@ public List<Coupon> getRedeemedCoupons() {
public void approveOfflineMethod() {
if (paymentMethod != null && paymentMethod.isOfflineMethod()
|| paymentMethod == PaymentMethod.CUSTOMERCARD_POS) {
shoppingCart.generateNewUUID();
approve();
}
}
Expand Down Expand Up @@ -787,6 +814,14 @@ public int getVerifiedOnlinePrice() {
return -1;
}

public CheckoutApi.RoutingTarget getRoutingTarget() {
if (checkoutProcess != null && checkoutProcess.routingTarget != null) {
return checkoutProcess.routingTarget;
}

return CheckoutApi.RoutingTarget.NONE;
}

public List<Product> getInvalidProducts() {
return invalidProducts;
}
Expand Down
11 changes: 11 additions & 0 deletions core/src/main/java/io/snabble/sdk/CheckoutApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ public static class PaymentInformation {
public String deviceName;
public String deviceFingerprint;
public String deviceIPAddress;
public String handoverInformation;
}

public static class CheckoutProcessRequest {
Expand Down Expand Up @@ -285,6 +286,15 @@ public String getSelfLink() {
}
}

public enum RoutingTarget {
@SerializedName("gatekeeper")
GATEKEEPER,
@SerializedName("supervisor")
SUPERVISOR,
@SerializedName("none")
NONE,
}

public static class CheckoutProcessResponse {
public Map<String, Href> links;
public Check[] checks;
Expand All @@ -298,6 +308,7 @@ public static class CheckoutProcessResponse {
public ExitToken exitToken;
public State paymentState;
public Pricing pricing;
public RoutingTarget routingTarget;
public PaymentResult paymentResult;
public Fulfillment[] fulfillments;

Expand Down
20 changes: 5 additions & 15 deletions core/src/main/java/io/snabble/sdk/Snabble.java
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ public List<Project> getProjects() {
}

public Project getProjectById(String projectId) {
if (projects == null) {
return null;
}

for (Project project : projects) {
if (project.getId().equals(projectId)) {
return project;
Expand Down Expand Up @@ -563,20 +567,6 @@ public interface OnMetadataUpdateListener {
void onMetaDataUpdated();
}

/**
* Sets the current activity context.
*
* This is an internal method and should not be called.
*/
public void _setCurrentActivity(Activity activity) {
if (currentActivity != null) {
currentActivity.clear();
currentActivity = null;
}

currentActivity = new WeakReference<>(activity);
}

private final Application.ActivityLifecycleCallbacks activityLifecycleCallbacks = new SimpleActivityLifecycleCallbacks() {

@Override
Expand Down Expand Up @@ -690,7 +680,7 @@ public Error getError() {
return error;
}

@NonNull
@NonNull
@Override
public String toString() {
return "SnabbleException{" +
Expand Down
9 changes: 2 additions & 7 deletions docs/docs/android-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
minSdkVersion = 21
compileSdkVersion = 29
java 8

androidx and a material 3 theme for ui components
androidx

### Using the snabble GitHub Repository

Expand All @@ -29,10 +28,6 @@ dependencies {

// user interface library
implementation 'io.snabble.sdk:ui:{{ extra.sdk_version }}'

// user interface integration library, entirely optional,
// for more seamless and easier integration in apps
implementation 'io.snabble.sdk:ui-integration:{{ extra.sdk_version }}'
}
```

Expand Down Expand Up @@ -83,7 +78,7 @@ snabble.setup(this, config, new Snabble.SetupCompletionListener() {
project = snabble.getProjects().get(0);

// registers this project globally for use with ui components
SnabbleUI.useProject(project);
SnabbleUI.setProject(project);

// select the first shop for demo purposes, ideally this should be done with
// geofencing or a manual user selection
Expand Down
Loading