Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement scanning in F-Droid build variant #1702

Merged
merged 3 commits into from Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle
Expand Up @@ -229,6 +229,9 @@ dependencies {
//open-source licenses
playStoreImplementation "com.google.android.gms:play-services-oss-licenses:${versions.play_services}"

// QR Code Scanner
fdroidImplementation 'com.github.blikoon:QRCodeScanner:0.1.2'

//Testing
androidTestImplementation('androidx.test.espresso:espresso-core:3.2.0', {
exclude group: 'com.android.support', module: 'support-annotations'
Expand Down
@@ -1,7 +1,13 @@
package com.eventyay.organizer.common.di.module.android;

import com.eventyay.organizer.core.attendee.qrscan.ScanQRActivity;

import dagger.Module;
import dagger.android.ContributesAndroidInjector;

@Module
public abstract class FlavorModule {

@ContributesAndroidInjector(modules = BarcodeFragmentBuildersModule.class)
abstract ScanQRActivity contributeScanQRActivity();
}
@@ -0,0 +1,26 @@
package com.eventyay.organizer.core.attendee;

import androidx.annotation.NonNull;

import com.eventyay.organizer.data.attendee.Attendee;

public interface ScanQRView {

boolean hasCameraPermission();

void requestCameraPermission();

void showPermissionError(String error);

void onScannedAttendee(Attendee attendee);

void showBarcodePanel(boolean show);

void showMessage(@NonNull int stringRes);

void setTint(boolean matched);

void showProgress(boolean show);

void startScan();
}
@@ -1,13 +1,16 @@
package com.eventyay.organizer.core.attendee;

import android.content.Context;
import android.widget.Toast;
import android.content.Intent;

import com.eventyay.organizer.R;
import com.eventyay.organizer.core.main.MainActivity;

public class ScanningDecider {

public void openScanQRActivity(Context context, long eventId) {
Toast.makeText(context, R.string.scanning_disabled_message, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(context, com.eventyay.organizer.core.attendee.qrscan.ScanQRActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(MainActivity.EVENT_KEY, eventId);
context.startActivity(intent);
}
}
@@ -0,0 +1,231 @@
package com.eventyay.organizer.core.attendee.qrscan;

import android.Manifest;
import android.Manifest.permission;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;

import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.blikoon.qrcodescanner.QrCodeActivity;
import com.eventyay.organizer.R;
import com.eventyay.organizer.core.attendee.ScanQRView;
import com.eventyay.organizer.core.attendee.checkin.AttendeeCheckInFragment;
import com.eventyay.organizer.core.main.MainActivity;
import com.eventyay.organizer.data.attendee.Attendee;
import com.eventyay.organizer.ui.ViewUtils;

import javax.inject.Inject;

import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.android.AndroidInjection;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;
import dagger.android.support.DaggerAppCompatActivity;
import io.reactivex.disposables.CompositeDisposable;
import timber.log.Timber;

import static com.eventyay.organizer.ui.ViewUtils.showView;

@SuppressWarnings("PMD.TooManyMethods")
public class ScanQRActivity extends DaggerAppCompatActivity implements ScanQRView, HasActivityInjector {

public static final int PERM_REQ_CODE = 123;
private static final int REQUEST_CODE_QR_SCAN = 101;

@BindView(R.id.barcodePanel)
TextView barcodePanel;

@BindView(R.id.progressBar)
ProgressBar progressBar;

@BindView(R.id.startScanningAgain)
Button startScanningAgain;

@Inject
ViewModelProvider.Factory viewModelFactory;

@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

private ScanQRViewModel scanQRViewModel;

private final CompositeDisposable compositeDisposable = new CompositeDisposable();

@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
scanQRViewModel = ViewModelProviders.of(this, viewModelFactory).get(ScanQRViewModel.class);

setContentView(R.layout.activity_scan_qr);

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

ButterKnife.bind(this);

onCameraLoaded();

startScanningAgain.setOnClickListener(v -> startScan());
}

@Override
protected void onStart() {
super.onStart();

long eventId = getIntent().getLongExtra(MainActivity.EVENT_KEY, -1);
if (eventId == -1) {
Timber.d("No Event ID provided. Exiting ...");
finish();
return;
}

scanQRViewModel.getProgress().observe(this, this::showProgress);
scanQRViewModel.getError().observe(this, this::showPermissionError);
scanQRViewModel.getMessage().observe(this, this::showMessage);
scanQRViewModel.getTint().observe(this, this::setTint);
scanQRViewModel.getShowBarcodePanelLiveData().observe(this, this::showBarcodePanel);
scanQRViewModel.getOnScannedAttendeeLiveData().observe(this, this::onScannedAttendee);
scanQRViewModel.loadAttendees();
}

@Override
protected void onPause() {
super.onPause();
}

@Override
protected void onResume() {
super.onResume();
}

@Override
protected void onDestroy() {
super.onDestroy();

compositeDisposable.dispose();
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode != PERM_REQ_CODE)
return;

// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
cameraPermissionGranted(true);
} else {
cameraPermissionGranted(false);
}
}

// View Implementation Start

@Override
public boolean hasCameraPermission() {
return ContextCompat.checkSelfPermission(this, permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
}

@Override
public void requestCameraPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERM_REQ_CODE);
}

@Override
public void showPermissionError(String error) {
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
}

@Override
public void onScannedAttendee(Attendee attendee) {
showToggleDialog(attendee.getId());
}

@Override
public void showBarcodePanel(boolean show) {
showView(barcodePanel, show);
}

@Override
public void showMessage(int stringRes) {
barcodePanel.setText(getString(stringRes));
}

@Override
public void setTint(boolean matched) {
ViewUtils.setTint(barcodePanel,
ContextCompat.getColor(this, matched ? R.color.green_a400 : R.color.red_500)
);
}

@Override
public void showProgress(boolean show) {
showView(progressBar, show);
}

public void onCameraLoaded() {
if (hasCameraPermission()) {
startScan();
} else {
requestCameraPermission();
}
}

public void cameraPermissionGranted(boolean granted) {
if (granted) {
startScan();
} else {
showProgress(false);
showPermissionError("User denied permission");
}
}

@Override
public void startScan() {
Intent i = new Intent(ScanQRActivity.this, QrCodeActivity.class);
startActivityForResult(i, REQUEST_CODE_QR_SCAN);
}

public void onActivityResult(int requestCode, int resultCode, Intent intent) {

if (requestCode == REQUEST_CODE_QR_SCAN) {
if (intent == null)
return;

scanQRViewModel.processBarcode(intent.getStringExtra
("com.blikoon.qrcodescanner.got_qr_scan_relult"));

} else {
super.onActivityResult(requestCode, resultCode, intent);
}
}

public void showToggleDialog(long attendeeId) {
AttendeeCheckInFragment bottomSheetDialogFragment = AttendeeCheckInFragment.newInstance(attendeeId);
bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
bottomSheetDialogFragment.setOnCancelListener(() -> {
ViewUtils.setTint(barcodePanel, ContextCompat.getColor(this, R.color.light_blue_a400));
showBarcodePanel(false);
startScan();
});
}

@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
51 changes: 51 additions & 0 deletions app/src/fdroid/res/layout/activity_scan_qr.xml
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_scan_qr"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.eventyay.organizer.core.attendee.qrscan.ScanQRActivity">

<TextView
android:id="@+id/barcodePanel"
style="@style/TextCapsule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:text="Barcode Value"
tools:visibility="visible" />

<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
tools:visibility="visible" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">

<ImageView
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/spacing_large"
android:src="@drawable/qrcode_scan" />

<Button
android:id="@+id/startScanningAgain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/light_blue_500"
android:padding="@dimen/spacing_medium"
android:text="@string/start_scanning_again" />

</LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />

<application
android:name="com.eventyay.organizer.OrgaApplication"
Expand Down
Expand Up @@ -110,7 +110,7 @@ public List<Attendee> getAttendees() {
return attendees;
}

private void processBarcode(String barcode) {
public void processBarcode(String barcode) {

Observable.fromIterable(attendees)
.filter(attendee -> attendee.getOrder() != null)
Expand Down Expand Up @@ -141,6 +141,7 @@ private void checkAttendee(Attendee attendee) {
toCheckOut && !attendee.isCheckedIn);

attendee.setChecking(true);
showBarcodePanelLiveData.setValue(true);

if (toCheckIn) {
message.setValue(
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/dimens.xml
Expand Up @@ -33,6 +33,7 @@

<dimen name="image_small">50dp</dimen>
<dimen name="image_medium">60dp</dimen>
<dimen name="image_large">70dp</dimen>
<dimen name="progressbar_large">80dp</dimen>

<dimen name="check_in_button_width">100dp</dimen>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Expand Up @@ -401,6 +401,7 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="my_account">My Account</string>
<string name="start_scanning_again">Start scanning again</string>

<string-array name="timezones">
<item>Africa/Abidjan</item>
Expand Down