diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 848d1a1..4366cda 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,12 @@ plugins { alias(libs.plugins.androidApplication) } +//allprojects { +// repositories { +// maven ( url = "https://jitpack.io" ) +// } +//} + android { namespace = "com.astatin3.scoutingapp2025" compileSdk = 34 @@ -40,7 +46,11 @@ dependencies { implementation(libs.lifecycle.viewmodel.ktx) implementation(libs.navigation.fragment) implementation(libs.navigation.ui) +// implementation(libs.support.annotations) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) + + implementation("com.github.yuriy-budiyev:code-scanner:2.3.0") + implementation("com.github.kenglxn.QRGen:android:3.0.1") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1e39859..4024ee3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> + mText; - - public TBAViewModel() { - mText = new MutableLiveData<>(); - mText.setValue("This is dashboard fragment"); - - } - - public LiveData getText() { - return mText; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeFragment.java index df11d84..fa3beaa 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeFragment.java @@ -1,38 +1,202 @@ package com.astatin3.scoutingapp2025.ui.home; +import android.app.AlertDialog; +import android.graphics.Bitmap; +import android.graphics.Color; import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; import android.view.LayoutInflater; + import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.SeekBar; -import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import com.astatin3.scoutingapp2025.databinding.FragmentHomeBinding; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Map; + public class HomeFragment extends Fragment { private FragmentHomeBinding binding; - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - HomeViewModel homeViewModel = - new ViewModelProvider(this).get(HomeViewModel.class); + private final int maxQrCount = 256; //The max number that can be stored in a byte + + private final int maxQrSpeed = 20; + private final int minQrSpeed = 300; + + private int minQrSize = 0; + private final int maxQrSize = 600; + private int qrSize = 100; + + + private int curCodeIndex = 0; + private int qrDelay = 100; + private int qrIndex = 0; + private int qrCount = 0; + + private ArrayList qrBitmaps = new ArrayList(); + + private void alert(String title, String content) { + AlertDialog.Builder alert = new AlertDialog.Builder(getContext()); + alert.setMessage(content); + alert.setTitle(title); + alert.setPositiveButton("OK", null); + alert.setCancelable(true); + alert.create().show(); + } + + public static Bitmap generateQrCode(String myCodeText) throws WriterException { +// Hashtable hintMap = new Hashtable(); + + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + + Map hints = new EnumMap(EncodeHintType.class); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // H = 30% damage + hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */ + + int size = 200; + + BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hints); + + int width = bitMatrix.getWidth(); + int height = bitMatrix.getHeight(); + + int[] pixels = new int[width * height]; + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + pixels[offset + x] = bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE; + } + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, width, 0, 0, width, height); + + return bitmap; + } + + + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { binding = FragmentHomeBinding.inflate(inflater, container, false); View root = binding.getRoot(); - final TextView textView = binding.textHome; - homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); + binding.qrSpeedSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { +// qrDelay = progress + minQrSpeed; + } + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + @Override + public void onStopTrackingTouch(SeekBar seekBar) {} + }); + + binding.qrSpeedSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + qrDelay = maxQrSpeed - progress + 1; + } + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + @Override + public void onStopTrackingTouch(SeekBar seekBar) {} + }); + + sendData("Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, DisestablishmenjAWHRJGQWEhugQWHKJEtarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism, Disestablishmentarianism"); return root; } - @Override - public void onDestroyView() { - super.onDestroyView(); - binding = null; + private void getQr(int index){ + byte[] bytes = ByteBuffer.allocate(1).putInt(index).array(); +// new byte; } + + private void sendData(String data){ + minQrSize = Math.round(data.length()/maxQrCount); + + binding.qrSizeSlider.setMax(maxQrSize); + binding.qrSpeedSlider.setMax(maxQrSpeed-minQrSpeed); + + binding.qrSizeSlider.setProgress(qrSize-minQrSize); + binding.qrSpeedSlider.setProgress(qrDelay-minQrSpeed); + + qrCount = (data.length()/qrSize); + +// alert("ee", ""+ qrDelay + "\n" + minQrSpeed); + + for(int i=0;i<=(data.length()/qrSize);i++){ + final int start = i*qrSize; + int end = (i+1)*qrSize; + if(end > data.length()){ + end = data.length()-1; + } +// alertstr += "\n" + start + ", " + end; + try { + qrBitmaps.add(generateQrCode( + data.substring(start, end) + )); + }catch (WriterException e){ + e.printStackTrace(); + } + } + qrIndex = 0; + qrLoop(); + } + + private void updateQr(){ +// alert("qr", ""+qrIndex); + binding.qrImage.setImageBitmap(qrBitmaps.get(qrIndex)); + this.qrIndex += 1; + if(this.qrIndex >= this.qrCount+1){ + this.qrIndex = 0; + } + } + + private void qrLoop(){ + new CountDownTimer(qrDelay, 1000) { + public void onTick(long millisUntilFinished) {} + public void onFinish() { + updateQr(); + qrLoop(); + } + }.start(); + + + } + +// private void setQR(int curIndex){ +// binding.qrImage.setImageBitmap(qrBitmaps.get(curIndex)); +// final Handler handler = new Handler(); +// handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// if(qrIndex+1 > qrCount){ +// qrIndex = 0; +// } +// setQR(curIndex+1); +// } +// }, qrDelay); +// +// +// } } \ No newline at end of file diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeViewModel.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeViewModel.java deleted file mode 100644 index 3b2bdd9..0000000 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/home/HomeViewModel.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.astatin3.scoutingapp2025.ui.home; - -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -public class HomeViewModel extends ViewModel { - - private final MutableLiveData mText; - - public HomeViewModel() { - mText = new MutableLiveData<>(); - mText.setValue("Testttt"); - } - - public LiveData getText() { - return mText; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsFragment.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsFragment.java index e91cbe1..b26ae3c 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsFragment.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsFragment.java @@ -1,37 +1,58 @@ package com.astatin3.scoutingapp2025.ui.notifications; +import android.app.Activity; +import android.app.AlertDialog; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; -import com.astatin3.scoutingapp2025.databinding.FragmentNotificationsBinding; +import com.astatin3.scoutingapp2025.R; +import com.budiyev.android.codescanner.CodeScanner; +import com.budiyev.android.codescanner.CodeScannerView; +import com.budiyev.android.codescanner.DecodeCallback; +import com.budiyev.android.codescanner.ScanMode; +import com.google.zxing.Result; public class NotificationsFragment extends Fragment { + private CodeScanner mCodeScanner; - private FragmentNotificationsBinding binding; - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - NotificationsViewModel notificationsViewModel = - new ViewModelProvider(this).get(NotificationsViewModel.class); + private void alert(String title, String content) { + AlertDialog.Builder alert = new AlertDialog.Builder(getContext()); + alert.setMessage(content); + alert.setTitle(title); + alert.setPositiveButton("OK", null); + alert.setCancelable(true); + alert.create().show(); + } - binding = FragmentNotificationsBinding.inflate(inflater, container, false); - View root = binding.getRoot(); + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + final Activity activity = getActivity(); + View root = inflater.inflate(R.layout.fragment_notifications, container, false); - final TextView textView = binding.textNotifications; - notificationsViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); + CodeScannerView scannerView = root.findViewById(R.id.scanner_view); + mCodeScanner = new CodeScanner(activity, scannerView); + mCodeScanner.setScanMode(ScanMode.CONTINUOUS); + mCodeScanner.setDecodeCallback(new DecodeCallback() { + @Override + public void onDecoded(@NonNull final Result result) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + alert("QR", result.getText()); + } + }); + } + }); + mCodeScanner.startPreview(); return root; } - - @Override - public void onDestroyView() { - super.onDestroyView(); - binding = null; - } } \ No newline at end of file diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsViewModel.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsViewModel.java deleted file mode 100644 index 724724c..0000000 --- a/app/src/main/java/com/astatin3/scoutingapp2025/ui/notifications/NotificationsViewModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.astatin3.scoutingapp2025.ui.notifications; - -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -public class NotificationsViewModel extends ViewModel { - - private final MutableLiveData mText; - - public NotificationsViewModel() { - mText = new MutableLiveData<>(); - mText.setValue("This is notifications fragment"); - } - - - public LiveData getText() { - return mText; - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index eca3b2c..f8375da 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -2,6 +2,62 @@ \ No newline at end of file + android:alpha="255" + android:focusable="false" + android:focusableInTouchMode="false" + tools:context=".MainActivity"> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml index d417935..8939324 100644 --- a/app/src/main/res/layout/fragment_notifications.xml +++ b/app/src/main/res/layout/fragment_notifications.xml @@ -6,17 +6,30 @@ android:layout_height="match_parent" tools:context=".ui.notifications.NotificationsFragment"> - - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index a72efee..8a0aee5 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -13,5 +13,5 @@ + android:title="@string/title_tba" /> \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index c15cd1f..8acf355 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -24,7 +24,7 @@ ScoutingApp2025 Home - Dashboard Notifications + TBA \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2bbd2a9..9452afe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.androidApplication) apply false +} + +dependencies { + } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dac8d2c..ab8f148 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,7 @@ lifecycleLivedataKtx = "2.6.1" lifecycleViewmodelKtx = "2.6.1" navigationFragment = "2.6.0" navigationUi = "2.6.0" +supportAnnotations = "28.0.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -22,6 +23,7 @@ lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-lived lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" } navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" } +support-annotations = { group = "com.android.support", name = "support-annotations", version.ref = "supportAnnotations" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } diff --git a/settings.gradle.kts b/settings.gradle.kts index ed4524e..ee71743 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,8 +16,11 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven ( url = "https://jitpack.io" ) + jcenter() } } rootProject.name = "ScoutingApp2025" include(":app") +