to kotlit
This commit is contained in:
parent
0b29993073
commit
8051c2c4ed
|
|
@ -1,7 +1,12 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
dermy
|
||||
dermy_app
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
|
|
@ -4,14 +4,6 @@
|
|||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2024-06-04T18:01:16.272682016Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="LocalEmulator" identifier="path=/home/r0r5chach/.config/.android/avd/Pixel_8_Pro_API_30.avd" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="/usr/share/java/gradle" />
|
||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.9.0" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.jetbrains.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "xyz.r0r5chach.dermy"
|
||||
namespace = "xyz.r0r5chach.dermy_app"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "xyz.r0r5chach.dermy"
|
||||
minSdk = 22
|
||||
applicationId = "xyz.r0r5chach.dermy_app"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
|
@ -23,27 +24,33 @@ android {
|
|||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_16
|
||||
targetCompatibility = JavaVersion.VERSION_16
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(libs.appcompat)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation(libs.androidx.preference)
|
||||
implementation(libs.androidx.room.common)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
||||
// CameraX core library
|
||||
implementation(libs.camera.core)
|
||||
implementation(libs.camera.camera2)
|
||||
implementation(libs.camera.lifecycle)
|
||||
implementation(libs.camera.view)
|
||||
implementation(libs.camera.extensions)
|
||||
//FragmentX
|
||||
implementation(libs.androidx.fragment.ktx)
|
||||
|
||||
//TFLite
|
||||
implementation(libs.tensorflow.lite)
|
||||
//CameraX
|
||||
implementation(libs.androidx.camera.view)
|
||||
implementation(libs.androidx.camera.core)
|
||||
implementation(libs.androidx.camera.lifecycle)
|
||||
|
||||
//MongoDB
|
||||
implementation(libs.mongodb.driver.kotlin.sync)
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package xyz.r0r5chach.dermy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("xyz.r0r5chach.dermy", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package xyz.r0r5chach.dermy_app
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("xyz.r0r5chach.dermy_app", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,6 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--TODO: Update to more modern permissions-->
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
|
|
@ -13,17 +10,14 @@
|
|||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Dermy"
|
||||
tools:targetApi="31" >
|
||||
|
||||
android:theme="@style/Theme.Dermy_app"
|
||||
tools:targetApi="31">
|
||||
<activity android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package xyz.r0r5chach.dermy;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import xyz.r0r5chach.dermy.fragments.CameraFragment;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public static final int REQUEST_CAMERA_PERMISSION = 200;
|
||||
|
||||
public MainActivity() {
|
||||
super(R.layout.activity_main);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
startCamera();
|
||||
}
|
||||
}
|
||||
|
||||
private void startCamera() {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setReorderingAllowed(true)
|
||||
.add(R.id.fragment_container, CameraFragment.class, null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { //FIXME: deprecated listener fir request permissions
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
startCamera();
|
||||
} else {
|
||||
Toast.makeText(this, "Camera permission is required", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.entities;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import xyz.r0r5chach.dermy.entities.locations.Location;
|
||||
import xyz.r0r5chach.dermy.entities.logs.LogBook;
|
||||
|
||||
public class Mole {
|
||||
private Location location;
|
||||
private LocalDateTime dateCreated;
|
||||
private LogBook logEntries;
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public LogBook getLogBook() {
|
||||
return logEntries;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.entities.locations;
|
||||
|
||||
public interface Location {
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.entities.locations;
|
||||
|
||||
public enum RightSideLocation implements Location {
|
||||
Head,
|
||||
Ear,
|
||||
Cheek,
|
||||
Neck,
|
||||
Shoulder,
|
||||
UpperArm,
|
||||
Elbow,
|
||||
LowerArm,
|
||||
Wrist,
|
||||
Hand,
|
||||
UpperTorso,
|
||||
LowerTorso,
|
||||
Hip,
|
||||
UpperLeg,
|
||||
Knee,
|
||||
LowerLeg,
|
||||
Ankle,
|
||||
Foot
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.entities.logs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LogBook {
|
||||
private final List<LogEntry> logEntries;
|
||||
|
||||
public LogBook() {
|
||||
logEntries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addEntry(LogEntry entry) {
|
||||
logEntries.add(entry);
|
||||
} //TODO: Add to db
|
||||
|
||||
//TODO: Remove Entry
|
||||
|
||||
//TODO: Update Entry
|
||||
|
||||
private LogBook getEntriesBy(Object obj) {
|
||||
LogBook results = new LogBook();
|
||||
|
||||
for (LogEntry entry: logEntries) {
|
||||
if (entry.getDateCreated().equals(obj) || entry.getNotes().contains((CharSequence) obj)) {
|
||||
results.addEntry(entry);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public LogBook getEntriesByDate(LocalDateTime dateCreated) {
|
||||
return getEntriesBy(dateCreated);
|
||||
}
|
||||
|
||||
public LogBook getEntriesByNote(String noteFragment) {
|
||||
return getEntriesBy(noteFragment);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.entities.logs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class LogEntry {
|
||||
private LocalDateTime dateCreated;
|
||||
private String imagePath, notes;
|
||||
|
||||
public LocalDateTime getDateCreated() {
|
||||
return dateCreated;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.fragments;
|
||||
|
||||
import static xyz.r0r5chach.dermy.MainActivity.REQUEST_CAMERA_PERMISSION;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.camera.core.CameraSelector;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.core.ImageCaptureException;
|
||||
import androidx.camera.core.Preview;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.camera.view.PreviewView;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import xyz.r0r5chach.dermy.R;
|
||||
import xyz.r0r5chach.dermy.models.Model;
|
||||
import xyz.r0r5chach.dermy.models.binary_classifiers.BinaryMobileNetV2;
|
||||
|
||||
public class CameraFragment extends Fragment {
|
||||
private PreviewView previewView;
|
||||
private ImageCapture imageCapture;
|
||||
private ExecutorService cameraExecutor;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_camera, container, false);
|
||||
previewView = view.findViewById(R.id.camera_preview);
|
||||
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
|
||||
startCamera();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
|
||||
}
|
||||
|
||||
previewView.setOnClickListener(v -> takePhoto());
|
||||
|
||||
cameraExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void startCamera() {
|
||||
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext());
|
||||
|
||||
cameraProviderFuture.addListener(() -> {
|
||||
try {
|
||||
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
|
||||
bindPreview(cameraProvider);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); //TODO: Replace with better logging
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(requireContext()));
|
||||
}
|
||||
|
||||
private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
|
||||
Preview preview = new Preview.Builder().build();
|
||||
preview.setSurfaceProvider(previewView.getSurfaceProvider());
|
||||
|
||||
imageCapture = new ImageCapture.Builder().build();
|
||||
|
||||
CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
|
||||
|
||||
cameraProvider.unbindAll();
|
||||
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);
|
||||
}
|
||||
|
||||
private void takePhoto() {
|
||||
File photoFile = new File(requireContext().getExternalFilesDir(null), System.currentTimeMillis() + ".jpg");
|
||||
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();
|
||||
imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(requireContext()), new ImageCapture.OnImageSavedCallback() {
|
||||
@Override
|
||||
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
|
||||
Bitmap photo = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
|
||||
try {
|
||||
//TODO: Change Model based on preference
|
||||
Model model = new BinaryMobileNetV2(getResources());
|
||||
|
||||
float[] results = model.runInference(photo, 2);
|
||||
Toast.makeText(requireContext(), "Results = " + Arrays.toString(results), Toast.LENGTH_LONG).show();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull ImageCaptureException exception) {
|
||||
exception.printStackTrace(); //TODO: Replace with better logging
|
||||
Toast.makeText(requireContext(), "Error saving photo: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
cameraExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.fragments;
|
||||
|
||||
public class MapFragment {
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.fragments;
|
||||
|
||||
public class NearbyFragment {
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.fragments;
|
||||
|
||||
public class PreferencesFragment {
|
||||
//TODO: Disclaimers
|
||||
//TODO: Useful Links
|
||||
//TODO: Export File
|
||||
//TODO: Backup data
|
||||
//TODO: Recover Account
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.models;
|
||||
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.tensorflow.lite.Interpreter;
|
||||
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
|
||||
import xyz.r0r5chach.dermy.R;
|
||||
|
||||
public class Model {
|
||||
protected final Interpreter modelInterpreter;
|
||||
|
||||
public Model(Resources resources, int modelId) throws IOException {
|
||||
modelInterpreter = new Interpreter(loadModel(resources, modelId));
|
||||
}
|
||||
|
||||
public float[] runInference(Bitmap image, int classes) {
|
||||
ByteBuffer inputBuffer = preprocessImage(image);
|
||||
float[][] output = new float[1][classes];
|
||||
modelInterpreter.run(inputBuffer, output);
|
||||
|
||||
return output[0];
|
||||
}
|
||||
|
||||
public MappedByteBuffer loadModel(Resources resources, int modelId) throws IOException {
|
||||
AssetFileDescriptor fileDescriptor = resources.openRawResourceFd(modelId);
|
||||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor()); //FIXME: add try-with-resources
|
||||
|
||||
FileChannel fileChannel = inputStream.getChannel();
|
||||
long startOffset = fileDescriptor.getStartOffset();
|
||||
long declaredLength = fileDescriptor.getDeclaredLength();
|
||||
|
||||
return fileChannel.map(MapMode.READ_ONLY, startOffset, declaredLength);
|
||||
}
|
||||
|
||||
public static ByteBuffer preprocessImage(Bitmap image) {
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(4 * 280 * 280 * 3);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
int[] intValues = new int[280 * 280];
|
||||
|
||||
image.getPixels(intValues, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
|
||||
|
||||
int pixel = 0;
|
||||
for (int i = 0; i < 280; ++i) {
|
||||
for (int j = 0; j < 280; ++j) {
|
||||
int val = intValues[pixel++];
|
||||
buffer.putFloat((((val >> 16) & 0xFF) - 127) / 128.0f);
|
||||
buffer.putFloat((((val >> 8) & 0xFF) - 127) / 128.0f);
|
||||
buffer.putFloat(((val & 0xFF) - 127) / 128.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.models.binary_classifiers;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import xyz.r0r5chach.dermy.R;
|
||||
import xyz.r0r5chach.dermy.models.Model;
|
||||
|
||||
public class BinaryEfficientNetLite3 extends Model {
|
||||
|
||||
public BinaryEfficientNetLite3(Resources resources) throws IOException {
|
||||
super(resources, R.raw.binary_efficientnet_lite3);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.models.binary_classifiers;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import xyz.r0r5chach.dermy.R;
|
||||
import xyz.r0r5chach.dermy.models.Model;
|
||||
|
||||
public class BinaryEfficientNetLite4 extends Model {
|
||||
|
||||
public BinaryEfficientNetLite4(Resources resources) throws IOException {
|
||||
super(resources, R.raw.binary_efficientnet_lite4);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package xyz.r0r5chach.dermy.models.binary_classifiers;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import xyz.r0r5chach.dermy.R;
|
||||
import xyz.r0r5chach.dermy.models.Model;
|
||||
|
||||
public class BinaryMobileNetV2 extends Model {
|
||||
|
||||
public BinaryMobileNetV2(Resources resources) throws IOException {
|
||||
super(resources, R.raw.binary_mobilenet_v2);
|
||||
}
|
||||
|
||||
//TODO: Add runInference method that runs super but transforms output into usable format
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package xyz.r0r5chach.dermy_app
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.add
|
||||
import androidx.fragment.app.commit
|
||||
import xyz.r0r5chach.dermy_app.fragments.HomeFragment
|
||||
|
||||
class MainActivity: AppCompatActivity(R.layout.activity_main) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager.commit {
|
||||
setReorderingAllowed(true)
|
||||
add<HomeFragment>(R.id.fragment_container, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package xyz.r0r5chach.dermy_app.db
|
||||
|
||||
import android.util.Log
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import java.time.LocalDateTime
|
||||
|
||||
interface LogDao {
|
||||
@Query("SELECT * FROM logs")
|
||||
fun getAll(): List<LogEntry>
|
||||
|
||||
@Query("SELECT * FROM logs WHERE moleId = :moleId")
|
||||
fun findMoleLogs(moleId: String?): List<LogEntry>
|
||||
|
||||
@Query("SELECT * FROM logs WHERE dateCreated = :date")
|
||||
fun findByDate(date: LocalDateTime): List<LogEntry>
|
||||
|
||||
@Insert
|
||||
fun insertOne(log: Log?)
|
||||
|
||||
@Delete
|
||||
fun deleteOne(log: Log?)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package xyz.r0r5chach.dermy_app.db
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.bson.BsonType
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
||||
import org.bson.codecs.pojo.annotations.BsonRepresentation
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(tableName = "logs")
|
||||
data class LogEntry(
|
||||
@PrimaryKey
|
||||
@BsonId
|
||||
@BsonRepresentation(BsonType.OBJECT_ID)
|
||||
val id: String,
|
||||
@BsonRepresentation(BsonType.OBJECT_ID)
|
||||
@BsonProperty("_mole_id")
|
||||
val moleId: String,
|
||||
@BsonRepresentation(BsonType.DATE_TIME)
|
||||
@BsonProperty("_date_created")
|
||||
val dateCreated: LocalDateTime,
|
||||
val contents: String
|
||||
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package xyz.r0r5chach.dermy_app.db
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.bson.BsonType
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
||||
import org.bson.codecs.pojo.annotations.BsonRepresentation
|
||||
import xyz.r0r5chach.dermy_app.db.locations.Location
|
||||
|
||||
@Entity(tableName = "moles")
|
||||
data class Mole(
|
||||
@PrimaryKey
|
||||
@BsonId
|
||||
@BsonRepresentation(BsonType.OBJECT_ID)
|
||||
val id: String,
|
||||
@BsonRepresentation(BsonType.OBJECT_ID)
|
||||
@BsonProperty("_user_id")
|
||||
val userId: String,
|
||||
@BsonRepresentation(BsonType.STRING)
|
||||
val location: Location
|
||||
)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package xyz.r0r5chach.dermy_app.db
|
||||
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import xyz.r0r5chach.dermy_app.db.locations.Location
|
||||
|
||||
interface MoleDao {
|
||||
@Query("SELECT * FROM moles")
|
||||
fun getAll(): List<Mole>
|
||||
|
||||
@Query("SELECT * FROM moles WHERE location = :location")
|
||||
fun findByLocation(location: Location): List<Mole>
|
||||
|
||||
@Insert
|
||||
fun insertOne(mole: Mole)
|
||||
|
||||
@Delete
|
||||
fun deleteOne(mole: Mole)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package xyz.r0r5chach.dermy.entities.locations;
|
||||
package xyz.r0r5chach.dermy_app.db.locations
|
||||
|
||||
public enum BackLocation implements Location {
|
||||
enum class BackLocation : Location {
|
||||
Head,
|
||||
Neck,
|
||||
LeftShoulder,
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package xyz.r0r5chach.dermy.entities.locations;
|
||||
package xyz.r0r5chach.dermy_app.db.locations
|
||||
|
||||
public enum FrontLocation implements Location {
|
||||
enum class FrontLocation : Location {
|
||||
Forehead,
|
||||
Nose,
|
||||
LeftEye,
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package xyz.r0r5chach.dermy_app.db.locations
|
||||
|
||||
interface Location
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package xyz.r0r5chach.dermy.entities.locations;
|
||||
package xyz.r0r5chach.dermy_app.db.locations
|
||||
|
||||
public enum LeftSideLocation implements Location {
|
||||
enum class SideLocation : Location {
|
||||
Head,
|
||||
Ear,
|
||||
Cheek,
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments;
|
||||
|
||||
public class AccountFragment {
|
||||
//TODO: Login if no API Key
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.camera.core.ImageCapture
|
||||
import androidx.camera.core.ImageCapture.OutputFileOptions
|
||||
import androidx.camera.core.ImageCaptureException
|
||||
import androidx.camera.core.Preview
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import xyz.r0r5chach.dermy_app.R
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class CameraFragment : Fragment(R.layout.fragment_camera) {
|
||||
private lateinit var previewView: PreviewView
|
||||
private lateinit var imageCapture: ImageCapture
|
||||
private lateinit var cameraExecutor: ExecutorService
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) {isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
startCamera()
|
||||
}
|
||||
else {
|
||||
Toast.makeText(context, "Camera permission is required", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
previewView = view?.findViewById(R.id.camera_preview)!!
|
||||
|
||||
if (context?.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
}
|
||||
else {
|
||||
startCamera()
|
||||
}
|
||||
|
||||
previewView.setOnClickListener { takePhoto() }
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> = ProcessCameraProvider.getInstance(requireContext())
|
||||
|
||||
cameraProviderFuture.addListener({
|
||||
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
|
||||
|
||||
val preview = Preview.Builder().build().also {
|
||||
it.setSurfaceProvider(previewView.surfaceProvider)
|
||||
}
|
||||
|
||||
imageCapture = ImageCapture.Builder().build()
|
||||
|
||||
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
|
||||
|
||||
try {
|
||||
cameraProvider.unbindAll()
|
||||
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
|
||||
} catch (exc: Exception) {
|
||||
exc.printStackTrace()
|
||||
}
|
||||
|
||||
}, ContextCompat.getMainExecutor(requireContext()))
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
val photoFile = File(context?.getExternalFilesDir(null), "${System.currentTimeMillis()}.jpg") //TODO: Save image as MoleId
|
||||
val outputFileOptions: OutputFileOptions = OutputFileOptions.Builder(photoFile).build()
|
||||
imageCapture.takePicture(
|
||||
outputFileOptions,
|
||||
ContextCompat.getMainExecutor(requireContext()),
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
val photo: Bitmap = BitmapFactory.decodeFile(photoFile.absolutePath)
|
||||
//TODO: redirect to next fragment
|
||||
}
|
||||
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
exception.printStackTrace() //TODO: Replace with better logging
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
"Error saving photo: ${exception.message}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor.shutdown()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.fragment.app.replace
|
||||
import xyz.r0r5chach.dermy_app.R
|
||||
|
||||
class HomeFragment : Fragment(R.layout.fragment_home) {
|
||||
private var buttons: IntArray = intArrayOf(R.id.add_mole_button, R.id.map_button, R.id.links_button, R.id.settings_button)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
for (button in buttons) {
|
||||
view.findViewById<Button>(button).setOnClickListener {
|
||||
initButton(button)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initButton(button: Int) {
|
||||
val manager = requireActivity().supportFragmentManager
|
||||
|
||||
when (button) {
|
||||
R.id.add_mole_button -> {
|
||||
manager.commit {
|
||||
setReorderingAllowed(true)
|
||||
replace<MoleFragment>(R.id.fragment_container, null)
|
||||
}
|
||||
}
|
||||
R.id.map_button -> {
|
||||
manager.commit {
|
||||
setReorderingAllowed(true)
|
||||
replace<MapFragment>(R.id.fragment_container, null)
|
||||
}
|
||||
}
|
||||
R.id.links_button -> {
|
||||
manager.commit {
|
||||
setReorderingAllowed(true)
|
||||
replace<LinksFragment>(R.id.fragment_container, null)
|
||||
}
|
||||
}
|
||||
R.id.settings_button -> {
|
||||
manager.commit {
|
||||
setReorderingAllowed(true)
|
||||
replace<SettingsFragment>(R.id.fragment_container, null)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class LinksFragment extends Fragment {
|
||||
//TODO: NHS links etc
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments;
|
||||
|
||||
public class LocationFragment {
|
||||
//TODO: Recycler View of Moles at location from last fragment
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class MapFragment extends Fragment {
|
||||
//TODO: Map of all locations
|
||||
//When pressed route to LocationFragment with specified location
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class MoleFragment extends Fragment {
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package xyz.r0r5chach.dermy_app.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import xyz.r0r5chach.dermy_app.R
|
||||
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
} //TODO: Disclaimers
|
||||
//TODO: Useful Links
|
||||
//TODO: Export File
|
||||
//TODO: Backup data
|
||||
//TODO: Recover Account
|
||||
// Login button
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_mole_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/string_add_mole"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/links_button"
|
||||
app:layout_constraintEnd_toStartOf="@+id/map_button"
|
||||
app:layout_constraintHeight_percent="0.1"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="320dp"
|
||||
app:layout_constraintWidth_percent="0.28" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/map_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/string_body_map"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/settings_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.1"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/add_mole_button"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="320dp"
|
||||
app:layout_constraintWidth_percent="0.28" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/links_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/string_links"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/settings_button"
|
||||
app:layout_constraintHeight_percent="0.1"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/add_mole_button"
|
||||
app:layout_constraintWidth_max="320dp"
|
||||
app:layout_constraintWidth_percent="0.28" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="@string/string_settings"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.1"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/links_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/map_button"
|
||||
app:layout_constraintWidth_max="320dp"
|
||||
app:layout_constraintWidth_percent="0.28" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.Dermy" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<style name="Theme.Dermy_app" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_200</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name" translatable="false">dermy</string>
|
||||
<string name="image_capture_button_text">Capture</string>
|
||||
<string name="app_name">dermy_app</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.Dermy" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<style name="Theme.Dermy_app" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package xyz.r0r5chach.dermy;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package xyz.r0r5chach.dermy_app
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
[versions]
|
||||
agp = "8.4.1"
|
||||
cameraCore = "1.3.3"
|
||||
fragmentKtx = "1.7.1"
|
||||
kotlin = "1.9.0"
|
||||
coreKtx = "1.13.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
tensorflowLite = "2.6.0"
|
||||
cameraView = "1.3.3"
|
||||
cameraCore = "1.3.3"
|
||||
cameraLifecycle = "1.3.3"
|
||||
mongodbDriverKotlinSync = "5.1.1"
|
||||
preference = "1.2.1"
|
||||
roomCommon = "2.6.1"
|
||||
|
||||
[libraries]
|
||||
camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCore" }
|
||||
camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCore" }
|
||||
camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "cameraCore" }
|
||||
camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "cameraCore" }
|
||||
camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraCore" }
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
tensorflow-lite = { module = "org.tensorflow:tensorflow-lite", version.ref = "tensorflowLite" }
|
||||
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraView" }
|
||||
androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "cameraCore" }
|
||||
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraLifecycle" }
|
||||
androidx-preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
|
||||
androidx-room-common = { group = "androidx.room", name = "room-common", version.ref = "roomCommon" }
|
||||
mongodb-driver-kotlin-sync = { module = "org.mongodb:mongodb-driver-kotlin-sync", version.ref = "mongodbDriverKotlinSync" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#Mon Jun 03 19:20:03 BST 2024
|
||||
#Wed Jun 12 12:41:18 BST 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ dependencyResolutionManagement {
|
|||
}
|
||||
}
|
||||
|
||||
rootProject.name = "dermy"
|
||||
rootProject.name = "dermy_app"
|
||||
include(":app")
|
||||
|
||||
Loading…
Reference in New Issue