diff --git a/.github/ISSUE_TEMPLATE/新機能用テンプレート.md b/.github/ISSUE_TEMPLATE/新機能用テンプレート.md
new file mode 100644
index 00000000..5518f596
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/新機能用テンプレート.md
@@ -0,0 +1,10 @@
+---
+name: 新機能用テンプレート
+about: 新規開発Issue用テンプレート
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+WIP
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..aa724b77
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000..86eae3b4
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Lacerta
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 00000000..b589d56e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 00000000..0c0c3383
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 00000000..29b2542d
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 00000000..0c622ae3
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 00000000..f8051a6f
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..8978d23d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..94a25f7f
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index ea8ca76d..8f9e28fc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,17 @@
# Lacerta
WIP
+## モジュール設計
+
+![Untitled Diagram(2)](https://github.com/lacerta-doc/Lacerta/assets/66072112/9daabaca-5cdc-49f8-ac66-196c588a47c9)
+
+## メモ
+- アイコン: Google Material Icons https://fonts.google.com/icons (Weight:300, Grade:0, Optical size: 24px)
+
+## コーディング規則/推奨(WIP)
+### 規則
+- `// TODO`コメントには任意のsuffixを付ける
+ - 全員が同じ`// TODO:`を使っていると検索がむずかしくなるため
+ - (例: `// TODO-rca:`)
+### 推奨
+- マジックナンバーは控える(必要な場合もあるので)
+
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 00000000..2538a406
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,90 @@
+plugins {
+ id 'com.android.application'
+ id 'com.google.dagger.hilt.android'
+}
+
+android {
+ namespace 'one.nem.lacerta'
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "one.nem.lacerta"
+ minSdk 26
+ targetSdk 33
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ debug { // 開発メンバー用
+ debuggable true
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+
+ applicationIdSuffix ".debug"
+ matchingFallbacks = ['release']
+ }
+ beta_release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+
+ applicationIdSuffix ".beta"
+ matchingFallbacks = ['release']
+ }
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ implementation libs.androidx.constraintlayout
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // 内部モジュール
+ // Feature
+ implementation project(':feature:home')
+ implementation project(':feature:search')
+ implementation project(':feature:library')
+ implementation project(':feature:scan')
+ implementation project(':feature:debug') // デバッグメニュー
+
+// // Component
+// implementation project(':component:common')
+// implementation project(':component:scanner')
+// implementation project(':component:viewer')
+
+// // Data
+// implementation project(':data:repository')
+//
+// // Source
+// implementation project(':data:source:database')
+// implementation project(':data:source:preference')
+//
+ implementation project(':data')
+
+ implementation project(':shared:ui')
+
+ implementation project(':shared:icon')
+
+ // Hilt (DI)
+ implementation libs.com.google.dagger.hilt.android
+ annotationProcessor libs.com.google.dagger.hilt.compiler
+
+ // Navigation
+ implementation libs.navigation.fragment
+ implementation libs.navigation.ui
+ implementation libs.navigation.dynamic.features.fragment
+
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/androidTest/java/one/nem/lacerta/ExampleInstrumentedTest.java b/app/src/androidTest/java/one/nem/lacerta/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..be866444
--- /dev/null
+++ b/app/src/androidTest/java/one/nem/lacerta/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..6ad838c8
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/one/nem/lacerta/LacertaApplication.java b/app/src/main/java/one/nem/lacerta/LacertaApplication.java
new file mode 100644
index 00000000..d2d838af
--- /dev/null
+++ b/app/src/main/java/one/nem/lacerta/LacertaApplication.java
@@ -0,0 +1,18 @@
+package one.nem.lacerta;
+
+import android.app.Application;
+
+import com.google.android.material.color.DynamicColors;
+
+import dagger.hilt.android.HiltAndroidApp;
+
+@HiltAndroidApp
+public class LacertaApplication extends Application {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ // DynamicColorを有効化
+ DynamicColors.applyToActivitiesIfAvailable(this);
+ }
+}
diff --git a/app/src/main/java/one/nem/lacerta/MainActivity.java b/app/src/main/java/one/nem/lacerta/MainActivity.java
new file mode 100644
index 00000000..404debd0
--- /dev/null
+++ b/app/src/main/java/one/nem/lacerta/MainActivity.java
@@ -0,0 +1,40 @@
+package one.nem.lacerta;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.navigation.NavController;
+import androidx.navigation.fragment.NavHostFragment;
+import androidx.navigation.ui.NavigationUI;
+
+import android.os.Bundle;
+import android.widget.Toast;
+
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+
+
+
+
+import dagger.hilt.android.AndroidEntryPoint;
+import javax.inject.Inject;
+
+@AndroidEntryPoint
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Debug
+ FragmentManager supportFragmentManager = getSupportFragmentManager();
+
+ NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
+ NavController navController = navHostFragment.getNavController();
+ BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_nav);
+
+ NavigationUI.setupWithNavController(bottomNavigationView, navController);
+
+ Toast.makeText(this, "testMessage", Toast.LENGTH_SHORT).show();
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..07d5da9c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 00000000..2b068d11
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..2117b2e1
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
new file mode 100644
index 00000000..9742222d
--- /dev/null
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 00000000..6f3b755b
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 00000000..6f3b755b
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 00000000..c209e78e
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..b2dfe3d1
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 00000000..4f0f1d64
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..62b611da
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 00000000..948a3070
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..1b9a6956
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..28d4b77f
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9287f508
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..aa7d6427
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9126ae37
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/navigation/main_nav.xml b/app/src/main/res/navigation/main_nav.xml
new file mode 100644
index 00000000..c1e9ce8c
--- /dev/null
+++ b/app/src/main/res/navigation/main_nav.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..b3b9e87e
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Lacerta
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 00000000..fa0f996d
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 00000000..9ee9997b
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/one/nem/lacerta/ExampleUnitTest.java b/app/src/test/java/one/nem/lacerta/ExampleUnitTest.java
new file mode 100644
index 00000000..db946740
--- /dev/null
+++ b/app/src/test/java/one/nem/lacerta/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..e06cad1c
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,6 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id 'com.android.application' version '8.0.2' apply false
+ id 'com.google.dagger.hilt.android' version '2.44' apply false
+ id 'com.android.library' version '8.0.2' apply false
+}
\ No newline at end of file
diff --git a/component/common/.gitignore b/component/common/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/component/common/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/component/common/build.gradle b/component/common/build.gradle
new file mode 100644
index 00000000..5ffcc098
--- /dev/null
+++ b/component/common/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.component.common'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/component/common/consumer-rules.pro b/component/common/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/component/common/proguard-rules.pro b/component/common/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/component/common/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/component/common/src/androidTest/java/one/nem/lacerta/component/common/ExampleInstrumentedTest.java b/component/common/src/androidTest/java/one/nem/lacerta/component/common/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..8ff3b10c
--- /dev/null
+++ b/component/common/src/androidTest/java/one/nem/lacerta/component/common/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.component.common;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.component.common.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/component/common/src/main/AndroidManifest.xml b/component/common/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/component/common/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/component/common/src/test/java/one/nem/lacerta/component/common/ExampleUnitTest.java b/component/common/src/test/java/one/nem/lacerta/component/common/ExampleUnitTest.java
new file mode 100644
index 00000000..d01b441e
--- /dev/null
+++ b/component/common/src/test/java/one/nem/lacerta/component/common/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.component.common;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/component/scanner/.gitignore b/component/scanner/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/component/scanner/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/component/scanner/build.gradle b/component/scanner/build.gradle
new file mode 100644
index 00000000..ee9a16a8
--- /dev/null
+++ b/component/scanner/build.gradle
@@ -0,0 +1,37 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.component.scanner'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ implementation 'com.websitebeaver:documentscanner:1.0.0'
+}
\ No newline at end of file
diff --git a/component/scanner/consumer-rules.pro b/component/scanner/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/component/scanner/proguard-rules.pro b/component/scanner/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/component/scanner/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/component/scanner/src/androidTest/java/one/nem/lacerta/component/scanner/ExampleInstrumentedTest.java b/component/scanner/src/androidTest/java/one/nem/lacerta/component/scanner/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..0fd35155
--- /dev/null
+++ b/component/scanner/src/androidTest/java/one/nem/lacerta/component/scanner/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.component.scanner;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.component.scanner.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/component/scanner/src/main/AndroidManifest.xml b/component/scanner/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/component/scanner/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanFragment.java b/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanFragment.java
new file mode 100644
index 00000000..54ba513e
--- /dev/null
+++ b/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanFragment.java
@@ -0,0 +1,75 @@
+package one.nem.lacerta.component.scanner;
+
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+
+import androidx.constraintlayout.utils.widget.ImageFilterView;
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.websitebeaver.documentscanner.DocumentScanner;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link ScannerScanFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class ScannerScanFragment extends Fragment {
+
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+// private static final String MAX_SCAN_COUNT = "max_scan_count"; // 規定値
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+
+
+ public ScannerScanFragment() {
+ // Required empty public constructor
+ }
+
+ public static ScannerScanFragment newInstance(String param1) {
+ ScannerScanFragment fragment = new ScannerScanFragment();
+ Bundle args = new Bundle();
+// args.putString(MAX_SCAN_COUNT, param1);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+// mParam1 = getArguments().getString(MAX_SCAN_COUNT);
+// scan(Integer.parseInt(mParam1));
+ }
+ }
+
+
+ public DocumentScanner getDocumentScanner() {
+ return new DocumentScanner(
+ this,
+ (croppedImageResults) -> {
+ // display the first cropped image
+ croppedImageView.setImageBitmap(
+ BitmapFactory.decodeFile(croppedImageResults.get(0))
+ );
+ return null;
+ },
+ (errorMessage) -> {
+ // an error happened
+ return null;
+ },
+ () -> {
+ // user canceled document scan
+ return null;
+ },
+ null,
+ null,
+ null
+ );
+ }
+}
\ No newline at end of file
diff --git a/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanResultFragment.java b/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanResultFragment.java
new file mode 100644
index 00000000..beffe3d0
--- /dev/null
+++ b/component/scanner/src/main/java/one/nem/lacerta/component/scanner/ScannerScanResultFragment.java
@@ -0,0 +1,64 @@
+package one.nem.lacerta.component.scanner;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link ScannerScanResultFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class ScannerScanResultFragment extends Fragment {
+
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ public ScannerScanResultFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment ScannerScanResultFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static ScannerScanResultFragment newInstance(String param1, String param2) {
+ ScannerScanResultFragment fragment = new ScannerScanResultFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_scanner_scan_result, container, false);
+ }
+}
\ No newline at end of file
diff --git a/component/scanner/src/main/res/layout/fragment_scanner_scan.xml b/component/scanner/src/main/res/layout/fragment_scanner_scan.xml
new file mode 100644
index 00000000..cf20c76f
--- /dev/null
+++ b/component/scanner/src/main/res/layout/fragment_scanner_scan.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/component/scanner/src/main/res/layout/fragment_scanner_scan_result.xml b/component/scanner/src/main/res/layout/fragment_scanner_scan_result.xml
new file mode 100644
index 00000000..2ecaf967
--- /dev/null
+++ b/component/scanner/src/main/res/layout/fragment_scanner_scan_result.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/component/scanner/src/main/res/values/strings.xml b/component/scanner/src/main/res/values/strings.xml
new file mode 100644
index 00000000..6048840e
--- /dev/null
+++ b/component/scanner/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Hello blank fragment
+
\ No newline at end of file
diff --git a/component/scanner/src/test/java/one/nem/lacerta/component/scanner/ExampleUnitTest.java b/component/scanner/src/test/java/one/nem/lacerta/component/scanner/ExampleUnitTest.java
new file mode 100644
index 00000000..4293d085
--- /dev/null
+++ b/component/scanner/src/test/java/one/nem/lacerta/component/scanner/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.component.scanner;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/component/viewer/.gitignore b/component/viewer/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/component/viewer/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/component/viewer/build.gradle b/component/viewer/build.gradle
new file mode 100644
index 00000000..847135ba
--- /dev/null
+++ b/component/viewer/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.component.viewer'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/component/viewer/consumer-rules.pro b/component/viewer/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/component/viewer/proguard-rules.pro b/component/viewer/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/component/viewer/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/component/viewer/src/androidTest/java/one/nem/lacerta/component/viewer/ExampleInstrumentedTest.java b/component/viewer/src/androidTest/java/one/nem/lacerta/component/viewer/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..5e6435ce
--- /dev/null
+++ b/component/viewer/src/androidTest/java/one/nem/lacerta/component/viewer/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.component.viewer;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.component.viewer.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/component/viewer/src/main/AndroidManifest.xml b/component/viewer/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/component/viewer/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/component/viewer/src/test/java/one/nem/lacerta/component/viewer/ExampleUnitTest.java b/component/viewer/src/test/java/one/nem/lacerta/component/viewer/ExampleUnitTest.java
new file mode 100644
index 00000000..6c78313c
--- /dev/null
+++ b/component/viewer/src/test/java/one/nem/lacerta/component/viewer/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.component.viewer;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/data/.gitignore b/data/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/data/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/data/build.gradle b/data/build.gradle
new file mode 100644
index 00000000..10a00015
--- /dev/null
+++ b/data/build.gradle
@@ -0,0 +1,56 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+ id 'com.google.dagger.hilt.android'
+}
+
+android {
+ namespace 'one.nem.lacerta.data'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // Hilt (DI)
+ implementation libs.com.google.dagger.hilt.android
+ annotationProcessor libs.com.google.dagger.hilt.compiler
+
+ // JGit
+ implementation 'org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r'
+
+ // Room
+ implementation libs.androidx.room.runtime
+ annotationProcessor libs.androidx.room.compiler
+
+ // Utilsモジュール
+ implementation project(':utils')
+
+ // 型モジュール
+ implementation project(':model')
+
+ // データソースモジュール
+ implementation project(':source')
+}
\ No newline at end of file
diff --git a/data/consumer-rules.pro b/data/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/data/proguard-rules.pro b/data/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/data/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/data/src/androidTest/java/one/nem/lacerta/data/ExampleInstrumentedTest.java b/data/src/androidTest/java/one/nem/lacerta/data/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..20b7a66e
--- /dev/null
+++ b/data/src/androidTest/java/one/nem/lacerta/data/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.data;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.data.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/data/src/main/AndroidManifest.xml b/data/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/data/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/data/src/main/java/one/nem/lacerta/data/Document.java b/data/src/main/java/one/nem/lacerta/data/Document.java
new file mode 100644
index 00000000..78293c85
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/Document.java
@@ -0,0 +1,46 @@
+package one.nem.lacerta.data;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+
+import one.nem.lacerta.model.document.DocumentMeta;
+import one.nem.lacerta.model.document.DocumentDetail;
+import one.nem.lacerta.model.document.path.DocumentPath;
+import one.nem.lacerta.model.document.tag.DocumentTag;
+
+/**
+ * ドキュメントのデータを取得する
+ */
+public interface Document {
+
+ ArrayList getAllDocumentMetas(int limit);
+
+ ArrayList getAllDocumentMetas(int limit, int offset);
+
+ /**
+ * 更新の新しいドキュメントから順に並べてlimit件取得する
+ * @param limit 取得する上限数
+ */
+ ArrayList getRecentDocumentMetas(int limit);
+
+ /**
+ * 更新の新しいドキュメントから順に並べてoffset位置からlimit件取得する
+ * @param limit 取得する上限数
+ * @param offset 取得するオフセット
+ */
+ ArrayList getRecentDocumentMetas(int limit, int offset);
+
+ /**
+ * ドキュメントIDからDocumentDetailを取得する
+ * @param id ドキュメントID
+ */
+ DocumentDetail getDocumentDetail(String id);
+
+ /**
+ * DocumentMetaからDocumentDetailを取得する
+ * @param meta DocumentMeta
+ */
+ DocumentDetail getDocumentDetailByMeta(DocumentMeta meta); // 簡単に使えるように
+
+ DocumentDetail createDocumentByMeta(DocumentMeta meta);
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/DocumentDebug.java b/data/src/main/java/one/nem/lacerta/data/DocumentDebug.java
new file mode 100644
index 00000000..94ae5b42
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/DocumentDebug.java
@@ -0,0 +1,12 @@
+package one.nem.lacerta.data;
+
+import one.nem.lacerta.model.document.DocumentMeta;
+import one.nem.lacerta.model.document.DocumentDetail;
+import one.nem.lacerta.model.document.path.DocumentPath;
+import one.nem.lacerta.model.document.tag.DocumentTag;
+
+public interface DocumentDebug {
+
+ void insertDocument(DocumentMeta meta, DocumentDetail detail);
+
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/impl/DocumentDebugImpl.java b/data/src/main/java/one/nem/lacerta/data/impl/DocumentDebugImpl.java
new file mode 100644
index 00000000..0985436f
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/impl/DocumentDebugImpl.java
@@ -0,0 +1,47 @@
+package one.nem.lacerta.data.impl;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import one.nem.lacerta.data.DocumentDebug;
+import one.nem.lacerta.model.document.DocumentDetail;
+import one.nem.lacerta.model.document.DocumentMeta;
+
+import one.nem.lacerta.source.database.entity.DocumentEntity;
+import one.nem.lacerta.source.database.entity.LibraryEntity;
+import one.nem.lacerta.source.database.entity.TagEntity;
+
+import one.nem.lacerta.source.database.LacertaDatabase;
+
+public class DocumentDebugImpl implements DocumentDebug{
+
+ @Inject
+ LacertaDatabase database;
+
+ @Inject
+ public DocumentDebugImpl() {
+ }
+
+
+ public void insertDocument(DocumentMeta meta, DocumentDetail detail) {
+ DocumentEntity documentEntity = new DocumentEntity();
+ LibraryEntity libraryEntity = new LibraryEntity();
+
+ documentEntity.id = meta.getId();
+ documentEntity.title = meta.getTitle();
+ documentEntity.createdAt = meta.getCreatedAt();
+ documentEntity.updatedAt = meta.getUpdatedAt();
+ documentEntity.author = detail.getAuthor();
+ documentEntity.defaultBranch = detail.getDefaultBranch();
+ // ArrayListからListに変換
+ documentEntity.tagIds = meta.getTagIds();
+
+ libraryEntity.id = meta.getId();
+ libraryEntity.path = "Placeholder";
+ libraryEntity.rootPath = "Placeholder";
+
+ database.documentDao().insert(documentEntity);
+ database.libraryDao().insert(libraryEntity);
+ }
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/impl/DocumentImpl.java b/data/src/main/java/one/nem/lacerta/data/impl/DocumentImpl.java
new file mode 100644
index 00000000..0be30724
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/impl/DocumentImpl.java
@@ -0,0 +1,141 @@
+package one.nem.lacerta.data.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import one.nem.lacerta.data.Document;
+
+import one.nem.lacerta.model.document.DocumentMeta;
+import one.nem.lacerta.model.document.DocumentDetail;
+
+import one.nem.lacerta.model.document.path.DocumentPath;
+import one.nem.lacerta.model.document.tag.DocumentTag;
+import one.nem.lacerta.source.database.LacertaDatabase;
+
+import one.nem.lacerta.source.database.entity.DocumentEntity;
+import one.nem.lacerta.source.database.entity.LibraryEntity;
+import one.nem.lacerta.source.database.entity.TagEntity;
+
+import one.nem.lacerta.source.jgit.JGitRepository;
+import one.nem.lacerta.utils.repository.DeviceInfoUtils;
+
+
+public class DocumentImpl implements Document{
+
+ private LacertaDatabase database;
+
+ @Inject
+ public DocumentImpl(LacertaDatabase database) {
+ this.database = database;
+ }
+
+ @Inject
+ JGitRepository jGitRepository;
+
+ @Inject
+ DeviceInfoUtils deviceInfoUtils;
+
+ @Override
+ public ArrayList getAllDocumentMetas(int limit) {
+ ArrayList documentMetas = new ArrayList<>();
+ List documentEntities = database.documentDao().getAllWithLimit(limit);
+
+ for (DocumentEntity documentEntity : documentEntities) {
+ // タグ取得
+ // TODO-rca: 切り出すべきかも?
+ List tagEntities = database.tagDao().findByIds(documentEntity.tagIds);
+ ArrayList documentTags = new ArrayList<>();
+ for (TagEntity tagEntity : tagEntities) {
+ documentTags.add(new DocumentTag(tagEntity.id, tagEntity.tagName, tagEntity.color));
+ }
+
+ // 組み立て処理
+ // 可読性が終わるのでコンストラクタはつかわないほうがいいかも?
+ DocumentMeta documentMeta = new DocumentMeta();
+ documentMeta.setId(documentEntity.id);
+ documentMeta.setTitle(documentEntity.title);
+ documentMeta.setCreatedAt(documentEntity.createdAt);
+ documentMeta.setUpdatedAt(documentEntity.updatedAt);
+ documentMeta.setTags(documentTags);
+
+ documentMetas.add(documentMeta);
+ }
+
+ return documentMetas;
+ }
+
+ @Override
+ public ArrayList getAllDocumentMetas(int limit, int offset) {
+ return null; // TODO-rca: 実装する
+ }
+
+ @Override
+ public ArrayList getRecentDocumentMetas(int limit) {
+// ArrayList documentMetas = new ArrayList<>();
+// database.documentDao().
+ // TODO-rca: 履歴取得するDao実装する
+ return null;
+ }
+
+ @Override
+ public ArrayList getRecentDocumentMetas(int limit, int offset) {
+ return null;
+ }
+
+ @Override
+ public DocumentDetail getDocumentDetail(String id) {
+ DocumentDetail documentDetail = new DocumentDetail();
+ DocumentEntity documentEntity = database.documentDao().findById(id);
+
+ // タグ取得
+ // TODO-rca: 切り出すべきかも?
+ List tagEntities = database.tagDao().findByIds(documentEntity.tagIds);
+ ArrayList documentTags = new ArrayList<>();
+ for (TagEntity tagEntity : tagEntities) {
+ documentTags.add(new DocumentTag(tagEntity.id, tagEntity.tagName, tagEntity.color));
+ }
+
+ // パス取得
+ // TODO-rca: 切り出すべきかも?
+ LibraryEntity libraryEntity = database.libraryDao().findById(id);
+ DocumentPath documentPath = new DocumentPath(libraryEntity.rootPath, libraryEntity.path);
+
+ // リポジトリ取得
+ documentDetail.setRepository(jGitRepository.getRepository(id)); // TODO-rca: エラーハンドリング
+
+ // 組み立て処理
+ // 可読性が終わるのでコンストラクタはつかわないほうがいいかも?
+ DocumentMeta documentMeta = new DocumentMeta();
+ documentMeta.setId(documentEntity.id);
+ documentMeta.setTitle(documentEntity.title);
+ documentMeta.setCreatedAt(documentEntity.createdAt);
+ documentMeta.setUpdatedAt(documentEntity.updatedAt);
+ documentMeta.setTags(documentTags);
+
+ documentDetail.setMeta(documentMeta);
+ documentDetail.setAuthor(documentEntity.author);
+ documentDetail.setPath(documentPath);
+ documentDetail.setDefaultBranch(documentEntity.defaultBranch);
+
+ return documentDetail;
+ }
+
+ @Override
+ public DocumentDetail getDocumentDetailByMeta(DocumentMeta meta) {
+ return getDocumentDetail(meta.getId()); // TODO-rca: 効率悪いのでMetaはもらった物を使うようにする(処理を切り分ける?)
+ }
+
+ @Override
+ public DocumentDetail createDocumentByMeta(DocumentMeta meta) {
+ DocumentDetail documentDetail = new DocumentDetail();
+
+ documentDetail.setMeta(meta);
+ documentDetail.setAuthor("author"); // TODO-rca: SharedPrefを扱う機能を作ってそこから取得するようにする or Gitの設定を参照するようにする
+ documentDetail.setPath(new DocumentPath(deviceInfoUtils.getExternalStorageDirectoryString(), meta.getId()));
+ documentDetail.setDefaultBranch("master"); // TODO-rca: SharedPrefを扱う機能を作ってそこから取得するようにする?
+
+ return documentDetail;
+ }
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/module/DocumentDebugModule.java b/data/src/main/java/one/nem/lacerta/data/module/DocumentDebugModule.java
new file mode 100644
index 00000000..bcf5c7c5
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/module/DocumentDebugModule.java
@@ -0,0 +1,16 @@
+package one.nem.lacerta.data.module;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+import one.nem.lacerta.data.DocumentDebug;
+import one.nem.lacerta.data.impl.DocumentDebugImpl;
+
+@Module
+@InstallIn(SingletonComponent.class) // TODO-rca: Singletonでいいのか検討する
+abstract public class DocumentDebugModule {
+
+ @Binds
+ public abstract DocumentDebug bindDocumentDebug(DocumentDebugImpl documentDebugImpl);
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/module/DocumentModule.java b/data/src/main/java/one/nem/lacerta/data/module/DocumentModule.java
new file mode 100644
index 00000000..63f45043
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/module/DocumentModule.java
@@ -0,0 +1,20 @@
+package one.nem.lacerta.data.module;
+
+import android.content.Context;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+
+import one.nem.lacerta.data.Document;
+import one.nem.lacerta.data.impl.DocumentImpl;
+
+@Module
+@InstallIn(SingletonComponent.class) // TODO-rca: Singletonであるべきか考える
+abstract public class DocumentModule {
+
+ @Binds
+ public abstract Document bindDocument(DocumentImpl documentImpl);
+
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/processor/DocumentProcessor.java b/data/src/main/java/one/nem/lacerta/data/processor/DocumentProcessor.java
new file mode 100644
index 00000000..73838c8f
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/processor/DocumentProcessor.java
@@ -0,0 +1,13 @@
+package one.nem.lacerta.data.processor;
+
+import org.eclipse.jgit.lib.Repository;
+
+import one.nem.lacerta.model.document.DocumentDetail;
+
+public interface DocumentProcessor {
+ // TODO-rca: Initをここでやるべきか検討する?, Documentモデルを作るべきか検討する?
+
+ void setDocumentDetail(DocumentDetail documentDetail);
+
+
+}
diff --git a/data/src/main/java/one/nem/lacerta/data/processor/impl/DocumentProcessorImpl.java b/data/src/main/java/one/nem/lacerta/data/processor/impl/DocumentProcessorImpl.java
new file mode 100644
index 00000000..2994f9fe
--- /dev/null
+++ b/data/src/main/java/one/nem/lacerta/data/processor/impl/DocumentProcessorImpl.java
@@ -0,0 +1,4 @@
+package one.nem.lacerta.data.processor.impl;
+
+public class DocumentProcessorImpl {
+}
diff --git a/data/src/test/java/one/nem/lacerta/data/ExampleUnitTest.java b/data/src/test/java/one/nem/lacerta/data/ExampleUnitTest.java
new file mode 100644
index 00000000..2dfc33a8
--- /dev/null
+++ b/data/src/test/java/one/nem/lacerta/data/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.data;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/common/.gitignore b/feature/common/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/common/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/common/build.gradle b/feature/common/build.gradle
new file mode 100644
index 00000000..ee10993e
--- /dev/null
+++ b/feature/common/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.common'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/feature/common/consumer-rules.pro b/feature/common/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/common/proguard-rules.pro b/feature/common/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/common/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/common/src/androidTest/java/one/nem/lacerta/feature/common/ExampleInstrumentedTest.java b/feature/common/src/androidTest/java/one/nem/lacerta/feature/common/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..72609253
--- /dev/null
+++ b/feature/common/src/androidTest/java/one/nem/lacerta/feature/common/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.common;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.common.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/common/src/main/AndroidManifest.xml b/feature/common/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/common/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/common/src/test/java/one/nem/lacerta/feature/common/ExampleUnitTest.java b/feature/common/src/test/java/one/nem/lacerta/feature/common/ExampleUnitTest.java
new file mode 100644
index 00000000..7a3d7736
--- /dev/null
+++ b/feature/common/src/test/java/one/nem/lacerta/feature/common/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.common;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/.gitignore b/feature/debug/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/debug/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/debug/build.gradle b/feature/debug/build.gradle
new file mode 100644
index 00000000..54afd119
--- /dev/null
+++ b/feature/debug/build.gradle
@@ -0,0 +1,65 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+ id 'com.google.dagger.hilt.android'
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.debug'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ implementation libs.androidx.activity
+ implementation libs.androidx.constraintlayout
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // Navigation
+ implementation libs.navigation.fragment
+ implementation libs.navigation.ui
+ implementation libs.navigation.dynamic.features.fragment
+
+ // Hilt (DI)
+ implementation libs.com.google.dagger.hilt.android
+ annotationProcessor libs.com.google.dagger.hilt.compiler
+
+ // JGit
+ implementation 'org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r'
+
+ // 内部モジュール
+ // data
+ implementation project(':data')
+
+ // Debug
+ implementation project(':source')
+ implementation project(':utils')
+
+ // 型
+ implementation project(':model')
+
+ // Shared
+ implementation project(':shared:ui')
+
+}
\ No newline at end of file
diff --git a/feature/debug/consumer-rules.pro b/feature/debug/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/debug/proguard-rules.pro b/feature/debug/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/debug/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/debug/src/androidTest/java/one/nem/lacerta/feature/debug/ExampleInstrumentedTest.java b/feature/debug/src/androidTest/java/one/nem/lacerta/feature/debug/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..97a0523b
--- /dev/null
+++ b/feature/debug/src/androidTest/java/one/nem/lacerta/feature/debug/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.debug;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.debug.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/AndroidManifest.xml b/feature/debug/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..4ae26da0
--- /dev/null
+++ b/feature/debug/src/main/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuContainerFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuContainerFragment.java
new file mode 100644
index 00000000..b714b9a3
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuContainerFragment.java
@@ -0,0 +1,67 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import dagger.hilt.android.AndroidEntryPoint;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuContainerFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+@AndroidEntryPoint
+public class DebugMenuContainerFragment extends Fragment {
+
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ public DebugMenuContainerFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment DebugMenuSubContainerFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static DebugMenuContainerFragment newInstance(String param1, String param2) {
+ DebugMenuContainerFragment fragment = new DebugMenuContainerFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_debug_menu_container, container, false);
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterListFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterListFragment.java
new file mode 100644
index 00000000..a0d57399
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterListFragment.java
@@ -0,0 +1,81 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.AndroidEntryPoint;
+import one.nem.lacerta.data.Document;
+import one.nem.lacerta.feature.debug.common.adapter.DebugMenuDocumentListItemAdapter;
+import one.nem.lacerta.feature.debug.common.model.DebugMenuDocumentListItem;
+import one.nem.lacerta.model.document.DocumentMeta;
+import one.nem.lacerta.utils.LacertaLogger;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuDocumentTesterListFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+
+@AndroidEntryPoint
+public class DebugMenuDocumentTesterListFragment extends Fragment {
+
+ @Inject
+ Document document;
+
+ @Inject
+ LacertaLogger logger;
+
+ public DebugMenuDocumentTesterListFragment() {
+ // Required empty public constructor
+ }
+
+ public static DebugMenuDocumentTesterListFragment newInstance() {
+ DebugMenuDocumentTesterListFragment fragment = new DebugMenuDocumentTesterListFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_debug_menu_document_tester_list, container, false);
+
+ RecyclerView recyclerView = view.findViewById(R.id.recycler_view_document_list);
+ recyclerView.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(getContext()));
+
+ ArrayList documentMetas = document.getAllDocumentMetas(100);
+
+ logger.debug("Debug/DocList", "Document count: " + documentMetas.size());
+
+ List debugMenuDocumentListItems = new ArrayList<>();
+
+ for (DocumentMeta documentMeta : documentMetas) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ debugMenuDocumentListItems.add(new DebugMenuDocumentListItem(documentMeta.getTitle(), "Internal Id: " + documentMeta.getId(), simpleDateFormat.format(documentMeta.getUpdatedAt())));
+ }
+
+ DebugMenuDocumentListItemAdapter adapter = new DebugMenuDocumentListItemAdapter(debugMenuDocumentListItems);
+ recyclerView.setAdapter(adapter);
+
+ return view;
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterManageFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterManageFragment.java
new file mode 100644
index 00000000..b46ee40d
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterManageFragment.java
@@ -0,0 +1,72 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.google.android.material.textfield.TextInputEditText;
+
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.AndroidEntryPoint;
+import dagger.multibindings.IntKey;
+import one.nem.lacerta.data.DocumentDebug;
+
+import one.nem.lacerta.model.document.DocumentMeta;
+import one.nem.lacerta.model.document.DocumentDetail;
+
+import one.nem.lacerta.model.document.path.DocumentPath;
+import one.nem.lacerta.model.document.tag.DocumentTag;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuDocumentTesterManageFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+@AndroidEntryPoint
+public class DebugMenuDocumentTesterManageFragment extends Fragment {
+
+ @Inject
+ DocumentDebug documentDebug;
+
+ public DebugMenuDocumentTesterManageFragment() {
+ // Required empty public constructor
+ }
+
+ public static DebugMenuDocumentTesterManageFragment newInstance() {
+ DebugMenuDocumentTesterManageFragment fragment = new DebugMenuDocumentTesterManageFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_debug_menu_document_tester_manage, container, false);
+
+ TextInputEditText editTextDocumentTitle = view.findViewById(R.id.edit_text_document_title);
+ view.findViewById(R.id.button_insert_test_data).setOnClickListener( v -> {
+
+ DocumentMeta meta = new DocumentMeta(editTextDocumentTitle != null ? editTextDocumentTitle.getText().toString() : "empty title"); // TODO-rca: Nullable
+ DocumentPath path = new DocumentPath("root", "test_path");
+ DocumentDetail detail = new DocumentDetail(meta, path, "test_author", "test_default_branch");
+
+ documentDebug.insertDocument(meta, detail);
+ });
+
+ return view;
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterTopFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterTopFragment.java
new file mode 100644
index 00000000..6d9bbe3e
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuDocumentTesterTopFragment.java
@@ -0,0 +1,59 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import one.nem.lacerta.feature.debug.common.adapter.DebugMenuListItemAdapter;
+import one.nem.lacerta.feature.debug.common.model.DebugMenuListItem;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuDocumentTesterTopFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class DebugMenuDocumentTesterTopFragment extends Fragment {
+ public DebugMenuDocumentTesterTopFragment() {
+ // Required empty public constructor
+ }
+ public static DebugMenuDocumentTesterTopFragment newInstance() {
+ DebugMenuDocumentTesterTopFragment fragment = new DebugMenuDocumentTesterTopFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_debug_menu_document_tester_top, container, false);
+
+ RecyclerView recyclerView = view.findViewById(R.id.debug_menu_document_tester_recycler_view);
+ recyclerView.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(getContext()));
+
+ List debugMenuDocTesterListItems = new ArrayList<>();
+
+ debugMenuDocTesterListItems.add(new DebugMenuListItem("DocumentListFragment", "DocumentListFragment", R.id.action_debugMenuDocumentTesterTopFragment_to_debugMenuDocumentTesterListFragment, true));
+ debugMenuDocTesterListItems.add(new DebugMenuListItem("DocumentManagerFragment", "DocumentManagerFragment", R.id.action_debugMenuDocumentTesterTopFragment_to_debugMenuDocumentTesterManageFragment, true));
+
+
+ DebugMenuListItemAdapter adapter = new DebugMenuListItemAdapter(debugMenuDocTesterListItems);
+ recyclerView.setAdapter(adapter);
+ return view;
+
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuMetaDataFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuMetaDataFragment.java
new file mode 100644
index 00000000..6427a262
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuMetaDataFragment.java
@@ -0,0 +1,39 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuMetaDataFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class DebugMenuMetaDataFragment extends Fragment {
+ public DebugMenuMetaDataFragment() {
+ // Required empty public constructor
+ }
+
+ public static DebugMenuMetaDataFragment newInstance() {
+ DebugMenuMetaDataFragment fragment = new DebugMenuMetaDataFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_debug_menu_meta_data, container, false);
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuTopFragment.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuTopFragment.java
new file mode 100644
index 00000000..26cb3c3b
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/DebugMenuTopFragment.java
@@ -0,0 +1,56 @@
+package one.nem.lacerta.feature.debug;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import one.nem.lacerta.feature.debug.common.adapter.DebugMenuListItemAdapter;
+import one.nem.lacerta.feature.debug.common.model.DebugMenuListItem;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link DebugMenuTopFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class DebugMenuTopFragment extends Fragment {
+ public DebugMenuTopFragment() {
+ // Required empty public constructor
+ }
+ public static DebugMenuTopFragment newInstance() {
+ DebugMenuTopFragment fragment = new DebugMenuTopFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_debug_menu_top, container, false);
+
+ RecyclerView recyclerView = view.findViewById(R.id.debug_menu_recycler_view);
+ recyclerView.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(getContext()));
+ List debugMenuListItems = new ArrayList<>();
+
+ debugMenuListItems.add(new DebugMenuListItem("Meta Data", "View meta data", R.id.action_debugMenuTopFragment_to_debugMenuMetaDataFragment, true));
+ debugMenuListItems.add(new DebugMenuListItem("Document Tester", "placeholder", R.id.action_debugMenuTopFragment_to_debugMenuDocumentTesterTopFragment, true));
+
+ DebugMenuListItemAdapter adapter = new DebugMenuListItemAdapter(debugMenuListItems);
+ recyclerView.setAdapter(adapter);
+ return view;
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuDocumentListItemAdapter.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuDocumentListItemAdapter.java
new file mode 100644
index 00000000..7ccaa4a0
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuDocumentListItemAdapter.java
@@ -0,0 +1,67 @@
+package one.nem.lacerta.feature.debug.common.adapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+import one.nem.lacerta.feature.debug.R;
+import one.nem.lacerta.feature.debug.common.model.DebugMenuDocumentListItem;
+
+public class DebugMenuDocumentListItemAdapter extends RecyclerView.Adapter {
+
+ private List debugMenuDocumentListItems;
+
+ public DebugMenuDocumentListItemAdapter(List debugMenuDocumentListItems) {
+ this.debugMenuDocumentListItems = debugMenuDocumentListItems;
+ }
+
+ @NonNull
+ @Override
+ public DebugMenuDocumentListItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_debug_menu_document, parent, false);
+ return new DebugMenuDocumentListItemViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull DebugMenuDocumentListItemViewHolder holder, int position) {
+ DebugMenuDocumentListItem item = debugMenuDocumentListItems.get(position);
+
+ // Set title
+ holder.title.setText(item.getTitle());
+ // Set description
+ holder.description.setText(item.getDescription());
+ // Set updated at
+ holder.updatedAt.setText("Updated at: " + item.getUpdatedAt());
+
+ holder.itemView.setOnClickListener(v -> {
+ Toast.makeText(v.getContext(), "Clicked on " + item.getTitle(), Toast.LENGTH_SHORT).show(); // Debug
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return debugMenuDocumentListItems.size();
+ }
+
+ public class DebugMenuDocumentListItemViewHolder extends RecyclerView.ViewHolder {
+
+ TextView title;
+ TextView description;
+ TextView updatedAt;
+ public DebugMenuDocumentListItemViewHolder(@NonNull View itemView) {
+ super(itemView);
+
+ title = itemView.findViewById(R.id.document_list_item_title);
+ description = itemView.findViewById(R.id.document_list_item_description);
+ updatedAt = itemView.findViewById(R.id.document_list_item_updated_at);
+
+ }
+ }
+}
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuListItemAdapter.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuListItemAdapter.java
new file mode 100644
index 00000000..a4f01642
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/adapter/DebugMenuListItemAdapter.java
@@ -0,0 +1,63 @@
+package one.nem.lacerta.feature.debug.common.adapter;
+
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.navigation.Navigation;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+import one.nem.lacerta.feature.debug.R;
+import one.nem.lacerta.feature.debug.common.model.DebugMenuListItem;
+import one.nem.lacerta.utils.LacertaLogger;
+
+public class DebugMenuListItemAdapter extends RecyclerView.Adapter {
+ private List debugMenuListItems;
+
+ public DebugMenuListItemAdapter(List debugMenuListItems) {
+ this.debugMenuListItems = debugMenuListItems;
+ }
+
+ @NonNull
+ @Override
+ public DebugMenuListItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_debug_menu, parent, false);
+ return new DebugMenuListItemViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull DebugMenuListItemViewHolder holder, int position) {
+ DebugMenuListItem item = debugMenuListItems.get(position);
+ // Set title
+ holder.title.setText(item.getTitle());
+ // Set description
+ holder.description.setText(item.getDescription());
+
+ holder.itemView.setOnClickListener( v -> {
+ Navigation.findNavController(v).navigate(item.getDestinationId());
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return debugMenuListItems.size();
+ }
+
+ static class DebugMenuListItemViewHolder extends RecyclerView.ViewHolder {
+ TextView title;
+ TextView description;
+
+ public DebugMenuListItemViewHolder(@NonNull View itemView) {
+ super(itemView);
+
+ // Get ref to views
+ title = itemView.findViewById(R.id.debug_menu_item_title);
+ description = itemView.findViewById(R.id.debug_menu_item_description);
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuDocumentListItem.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuDocumentListItem.java
new file mode 100644
index 00000000..d03d0884
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuDocumentListItem.java
@@ -0,0 +1,27 @@
+package one.nem.lacerta.feature.debug.common.model;
+
+public class DebugMenuDocumentListItem {
+
+ private String title;
+ private String description;
+ private String updatedAt;
+
+ public DebugMenuDocumentListItem(String title, String description, String updatedAt) {
+ this.title = title;
+ this.description = description;
+ this.updatedAt = updatedAt;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getUpdatedAt() {
+ return updatedAt;
+ }
+
+}
diff --git a/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuListItem.java b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuListItem.java
new file mode 100644
index 00000000..8af4833e
--- /dev/null
+++ b/feature/debug/src/main/java/one/nem/lacerta/feature/debug/common/model/DebugMenuListItem.java
@@ -0,0 +1,38 @@
+package one.nem.lacerta.feature.debug.common.model;
+
+public class DebugMenuListItem {
+
+ private String title;
+ private String description;
+ private int destinationId; // Navigation destination ID
+ private boolean enabled;
+
+ public DebugMenuListItem(String title, String description, int destinationId, boolean enabled) {
+ this.title = title;
+ this.description = description;
+ this.destinationId = destinationId;
+ this.enabled = enabled;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getDestinationId() {
+ return destinationId;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+
+}
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_container.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_container.xml
new file mode 100644
index 00000000..1726352e
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_container.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_list.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_list.xml
new file mode 100644
index 00000000..65642307
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_list.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_manage.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_manage.xml
new file mode 100644
index 00000000..e4b8b046
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_manage.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_top.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_top.xml
new file mode 100644
index 00000000..439c5528
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_document_tester_top.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_meta_data.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_meta_data.xml
new file mode 100644
index 00000000..b79c51dc
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_meta_data.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/fragment_debug_menu_top.xml b/feature/debug/src/main/res/layout/fragment_debug_menu_top.xml
new file mode 100644
index 00000000..0b198159
--- /dev/null
+++ b/feature/debug/src/main/res/layout/fragment_debug_menu_top.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/list_item_debug_menu.xml b/feature/debug/src/main/res/layout/list_item_debug_menu.xml
new file mode 100644
index 00000000..277da422
--- /dev/null
+++ b/feature/debug/src/main/res/layout/list_item_debug_menu.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/layout/list_item_debug_menu_document.xml b/feature/debug/src/main/res/layout/list_item_debug_menu_document.xml
new file mode 100644
index 00000000..3e452e8a
--- /dev/null
+++ b/feature/debug/src/main/res/layout/list_item_debug_menu_document.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/navigation/feature_debug_internal_navigation.xml b/feature/debug/src/main/res/navigation/feature_debug_internal_navigation.xml
new file mode 100644
index 00000000..0a784b2b
--- /dev/null
+++ b/feature/debug/src/main/res/navigation/feature_debug_internal_navigation.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/navigation/feature_debug_navigation.xml b/feature/debug/src/main/res/navigation/feature_debug_navigation.xml
new file mode 100644
index 00000000..ec3f8c0a
--- /dev/null
+++ b/feature/debug/src/main/res/navigation/feature_debug_navigation.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/debug/src/main/res/values/strings.xml b/feature/debug/src/main/res/values/strings.xml
new file mode 100644
index 00000000..6048840e
--- /dev/null
+++ b/feature/debug/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Hello blank fragment
+
\ No newline at end of file
diff --git a/feature/debug/src/test/java/one/nem/lacerta/feature/debug/ExampleUnitTest.java b/feature/debug/src/test/java/one/nem/lacerta/feature/debug/ExampleUnitTest.java
new file mode 100644
index 00000000..c41829fb
--- /dev/null
+++ b/feature/debug/src/test/java/one/nem/lacerta/feature/debug/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.debug;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/home/.gitignore b/feature/home/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/home/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/home/build.gradle b/feature/home/build.gradle
new file mode 100644
index 00000000..ecc92c12
--- /dev/null
+++ b/feature/home/build.gradle
@@ -0,0 +1,43 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.home'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // Navigation
+ implementation libs.navigation.fragment
+ implementation libs.navigation.ui
+ implementation libs.navigation.dynamic.features.fragment
+
+ // shared
+ implementation project(':shared:ui')
+}
\ No newline at end of file
diff --git a/feature/home/consumer-rules.pro b/feature/home/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/home/proguard-rules.pro b/feature/home/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/home/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/home/src/androidTest/java/one/nem/lacerta/feature/home/ExampleInstrumentedTest.java b/feature/home/src/androidTest/java/one/nem/lacerta/feature/home/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..19b502d9
--- /dev/null
+++ b/feature/home/src/androidTest/java/one/nem/lacerta/feature/home/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.home;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.home.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/home/src/main/AndroidManifest.xml b/feature/home/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/home/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/home/src/main/java/one/nem/lacerta/feature/home/HomeTopFragment.java b/feature/home/src/main/java/one/nem/lacerta/feature/home/HomeTopFragment.java
new file mode 100644
index 00000000..4bc07490
--- /dev/null
+++ b/feature/home/src/main/java/one/nem/lacerta/feature/home/HomeTopFragment.java
@@ -0,0 +1,64 @@
+package one.nem.lacerta.feature.home;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link HomeTopFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class HomeTopFragment extends Fragment {
+
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ public HomeTopFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment HomeTopFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static HomeTopFragment newInstance(String param1, String param2) {
+ HomeTopFragment fragment = new HomeTopFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_home_top, container, false);
+ }
+}
\ No newline at end of file
diff --git a/feature/home/src/main/res/layout/fragment_home_top.xml b/feature/home/src/main/res/layout/fragment_home_top.xml
new file mode 100644
index 00000000..09030c8f
--- /dev/null
+++ b/feature/home/src/main/res/layout/fragment_home_top.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/home/src/main/res/navigation/feature_home_navigation.xml b/feature/home/src/main/res/navigation/feature_home_navigation.xml
new file mode 100644
index 00000000..e95b3a69
--- /dev/null
+++ b/feature/home/src/main/res/navigation/feature_home_navigation.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/home/src/main/res/values/strings.xml b/feature/home/src/main/res/values/strings.xml
new file mode 100644
index 00000000..6048840e
--- /dev/null
+++ b/feature/home/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Hello blank fragment
+
\ No newline at end of file
diff --git a/feature/home/src/test/java/one/nem/lacerta/feature/home/ExampleUnitTest.java b/feature/home/src/test/java/one/nem/lacerta/feature/home/ExampleUnitTest.java
new file mode 100644
index 00000000..27f2f2aa
--- /dev/null
+++ b/feature/home/src/test/java/one/nem/lacerta/feature/home/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.home;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/library/.gitignore b/feature/library/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/library/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/library/build.gradle b/feature/library/build.gradle
new file mode 100644
index 00000000..8b5b1dcc
--- /dev/null
+++ b/feature/library/build.gradle
@@ -0,0 +1,41 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.library'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // Navigation
+ implementation libs.navigation.fragment
+ implementation libs.navigation.ui
+ implementation libs.navigation.dynamic.features.fragment
+
+}
\ No newline at end of file
diff --git a/feature/library/consumer-rules.pro b/feature/library/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/library/proguard-rules.pro b/feature/library/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/library/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/library/src/androidTest/java/one/nem/lacerta/feature/library/ExampleInstrumentedTest.java b/feature/library/src/androidTest/java/one/nem/lacerta/feature/library/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..02dd6b72
--- /dev/null
+++ b/feature/library/src/androidTest/java/one/nem/lacerta/feature/library/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.library;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.library.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/library/src/main/AndroidManifest.xml b/feature/library/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/library/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryTopFragment.java b/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryTopFragment.java
new file mode 100644
index 00000000..495b235d
--- /dev/null
+++ b/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryTopFragment.java
@@ -0,0 +1,64 @@
+package one.nem.lacerta.feature.library;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Use the {@link LibraryTopFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class LibraryTopFragment extends Fragment {
+
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+ public LibraryTopFragment() {
+ // Required empty public constructor
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment LibraryTopFragment.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static LibraryTopFragment newInstance(String param1, String param2) {
+ LibraryTopFragment fragment = new LibraryTopFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_library_top, container, false);
+ }
+}
\ No newline at end of file
diff --git a/feature/library/src/main/res/layout/fragment_library_top.xml b/feature/library/src/main/res/layout/fragment_library_top.xml
new file mode 100644
index 00000000..46a6e596
--- /dev/null
+++ b/feature/library/src/main/res/layout/fragment_library_top.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature/library/src/main/res/navigation/feature_library_navigation.xml b/feature/library/src/main/res/navigation/feature_library_navigation.xml
new file mode 100644
index 00000000..9f25086b
--- /dev/null
+++ b/feature/library/src/main/res/navigation/feature_library_navigation.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/library/src/main/res/values/strings.xml b/feature/library/src/main/res/values/strings.xml
new file mode 100644
index 00000000..6048840e
--- /dev/null
+++ b/feature/library/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Hello blank fragment
+
\ No newline at end of file
diff --git a/feature/library/src/test/java/one/nem/lacerta/feature/library/ExampleUnitTest.java b/feature/library/src/test/java/one/nem/lacerta/feature/library/ExampleUnitTest.java
new file mode 100644
index 00000000..c3a8e0a5
--- /dev/null
+++ b/feature/library/src/test/java/one/nem/lacerta/feature/library/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.library;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/scan/.gitignore b/feature/scan/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/scan/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/scan/build.gradle b/feature/scan/build.gradle
new file mode 100644
index 00000000..d803c294
--- /dev/null
+++ b/feature/scan/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.scan'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.10.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+}
\ No newline at end of file
diff --git a/feature/scan/consumer-rules.pro b/feature/scan/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/scan/proguard-rules.pro b/feature/scan/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/scan/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/scan/src/androidTest/java/one/nem/lacerta/feature/scan/ExampleInstrumentedTest.java b/feature/scan/src/androidTest/java/one/nem/lacerta/feature/scan/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..053ede50
--- /dev/null
+++ b/feature/scan/src/androidTest/java/one/nem/lacerta/feature/scan/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.scan;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.scan.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/scan/src/main/AndroidManifest.xml b/feature/scan/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/scan/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/scan/src/test/java/one/nem/lacerta/feature/scan/ExampleUnitTest.java b/feature/scan/src/test/java/one/nem/lacerta/feature/scan/ExampleUnitTest.java
new file mode 100644
index 00000000..6a4d8a8c
--- /dev/null
+++ b/feature/scan/src/test/java/one/nem/lacerta/feature/scan/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.scan;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/feature/search/.gitignore b/feature/search/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/feature/search/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/search/build.gradle b/feature/search/build.gradle
new file mode 100644
index 00000000..b92bd0d5
--- /dev/null
+++ b/feature/search/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ namespace 'one.nem.lacerta.feature.search'
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.10.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+}
\ No newline at end of file
diff --git a/feature/search/consumer-rules.pro b/feature/search/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/feature/search/proguard-rules.pro b/feature/search/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/feature/search/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/search/src/androidTest/java/one/nem/lacerta/feature/search/ExampleInstrumentedTest.java b/feature/search/src/androidTest/java/one/nem/lacerta/feature/search/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..abd9c277
--- /dev/null
+++ b/feature/search/src/androidTest/java/one/nem/lacerta/feature/search/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.feature.search;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.feature.search.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/feature/search/src/main/AndroidManifest.xml b/feature/search/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/feature/search/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/search/src/test/java/one/nem/lacerta/feature/search/ExampleUnitTest.java b/feature/search/src/test/java/one/nem/lacerta/feature/search/ExampleUnitTest.java
new file mode 100644
index 00000000..ea6772fe
--- /dev/null
+++ b/feature/search/src/test/java/one/nem/lacerta/feature/search/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.feature.search;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..3e927b11
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# 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
+# 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
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 00000000..cd6712ad
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,28 @@
+[versions]
+nav = "2.7.5"
+agp = "8.0.2"
+activity = "1.8.0"
+room = "2.5.0"
+
+[libraries]
+navigation-fragment = { group="androidx.navigation", name="navigation-fragment", version.ref="nav"}
+navigation-ui = { group="androidx.navigation", name="navigation-ui", version.ref="nav"}
+navigation-dynamic-features-fragment = { group="androidx.navigation", name="navigation-dynamic-features-fragment", version.ref="nav"}
+
+androidx-constraintlayout = { group="androidx.constraintlayout", name="constraintlayout", version="2.1.4" }
+com-google-android-material = { group="com.google.android.material", name="material", version="1.10.0" }
+androidx-appcompat = { group="androidx.appcompat", name="appcompat", version="1.6.1" }
+junit = { group="junit", name="junit", version="4.13.2" }
+
+androidx-test-ext-junit = { group="androidx.test.ext", name="junit", version="1.1.5" }
+androidx-test-espresso-core = { group="androidx.test.espresso", name="espresso-core", version="3.5.1" }
+
+com-google-dagger-hilt-android = { group="com.google.dagger", name="hilt-android", version="2.44" }
+com-google-dagger-hilt-compiler = { group="com.google.dagger", name="hilt-compiler", version="2.44" }
+androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+
+androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
+androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
+
+[plugins]
+com-android-library = { id = "com.android.library", version.ref = "agp" }
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..e708b1c0
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..4ed162d3
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Dec 06 11:47:08 JST 2023
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 00000000..4f906e0c
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..107acd32
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/model/.gitignore b/model/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/model/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/model/build.gradle b/model/build.gradle
new file mode 100644
index 00000000..cfd215dc
--- /dev/null
+++ b/model/build.gradle
@@ -0,0 +1,39 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.model'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // JGit
+ implementation 'org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r'
+
+}
\ No newline at end of file
diff --git a/model/consumer-rules.pro b/model/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/model/proguard-rules.pro b/model/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/model/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/model/src/androidTest/java/one/nem/lacerta/model/ExampleInstrumentedTest.java b/model/src/androidTest/java/one/nem/lacerta/model/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..d03ea65a
--- /dev/null
+++ b/model/src/androidTest/java/one/nem/lacerta/model/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.model;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.model.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/model/src/main/AndroidManifest.xml b/model/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/model/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/model/src/main/java/one/nem/lacerta/model/document/DocumentDetail.java b/model/src/main/java/one/nem/lacerta/model/document/DocumentDetail.java
new file mode 100644
index 00000000..13559491
--- /dev/null
+++ b/model/src/main/java/one/nem/lacerta/model/document/DocumentDetail.java
@@ -0,0 +1,128 @@
+package one.nem.lacerta.model.document;
+
+import org.eclipse.jgit.lib.Repository;
+
+import java.nio.file.Path;
+import java.util.Date;
+
+import one.nem.lacerta.model.document.path.DocumentPath;
+import one.nem.lacerta.model.document.DocumentMeta;
+
+/**
+ * ドキュメントの詳細データ
+ */
+public class DocumentDetail {
+
+ /**
+ * ドキュメントのメタデータ(DocumentMetaインスタンス)
+ */
+ DocumentMeta meta;
+
+ /**
+ * ドキュメントのパス(DocumentPathインスタンス)
+ */
+ DocumentPath path;
+
+ /**
+ * ドキュメントの作者(String)
+ */
+ String author;
+
+ /**
+ * ドキュメントのデフォルトブランチ(String)
+ */
+ String defaultBranch;
+
+ Repository repository;
+
+ // Constructor
+ public DocumentDetail() {
+ }
+
+ public DocumentDetail(DocumentMeta meta, DocumentPath path, String author, String defaultBranch) {
+ this.meta = meta;
+ this.path = path;
+ this.author = author;
+ this.defaultBranch = defaultBranch;
+ }
+
+ // Getter
+
+ /**
+ * ドキュメントのメタデータ(DocumentMetaインスタンス)を取得する
+ */
+ public DocumentMeta getMeta() {
+ return meta;
+ }
+
+ /**
+ * ドキュメントのパス(DocumentPathインスタンス)を取得する
+ */
+ public DocumentPath getPath() {
+ return path;
+ }
+
+ /**
+ * ドキュメントの作者(String)を取得する
+ */
+ public String getAuthor() {
+ return author;
+ }
+
+ /**
+ * ドキュメントのデフォルトブランチ(String)を取得する
+ */
+ public String getDefaultBranch() {
+ return defaultBranch;
+ }
+
+ /**
+ * ドキュメントのリポジトリを取得する
+ */
+ public Repository getRepository() {
+ return repository;
+ }
+
+
+ // Setter
+
+ /**
+ * ドキュメントのメタデータ(DocumentMetaインスタンス)を設定する
+ * @param meta DocumentMetaインスタンス
+ */
+ public void setMeta(DocumentMeta meta) {
+ this.meta = meta;
+ }
+
+ /**
+ * ドキュメントのパス(DocumentPathインスタンス)を設定する
+ * @param path DocumentPathインスタンス
+ */
+ public void setPath(DocumentPath path) {
+ this.path = path;
+ }
+
+ /**
+ * ドキュメントの作者(String)を設定する
+ * @param author ドキュメントの作者
+ */
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ /**
+ * ドキュメントのデフォルトブランチ(String)を設定する
+ * @param defaultBranch ドキュメントのデフォルトブランチ
+ */
+ public void setDefaultBranch(String defaultBranch) {
+ this.defaultBranch = defaultBranch;
+ }
+
+ /**
+ * ドキュメントのリポジトリを設定する
+ */
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
diff --git a/model/src/main/java/one/nem/lacerta/model/document/DocumentMeta.java b/model/src/main/java/one/nem/lacerta/model/document/DocumentMeta.java
new file mode 100644
index 00000000..c191fcde
--- /dev/null
+++ b/model/src/main/java/one/nem/lacerta/model/document/DocumentMeta.java
@@ -0,0 +1,179 @@
+package one.nem.lacerta.model.document;
+
+import java.util.ArrayList;
+import one.nem.lacerta.model.document.tag.DocumentTag;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * ドキュメントのメタデータ
+ */
+public class DocumentMeta {
+ /**
+ * ドキュメントのID(String)
+ */
+ String id;
+
+ /**
+ * ドキュメントのタイトル(String)
+ */
+ String title;
+
+ /**
+ * ドキュメントの更新日時(Date)
+ */
+ Date updatedAt;
+
+ /**
+ * ドキュメントの作成日時(Date)
+ */
+ Date createdAt;
+
+ /**
+ * ドキュメントのタグ(DocumentTagインスタンスのリスト)
+ */
+ List tags;
+
+ // Constructor
+ public DocumentMeta() {
+ }
+
+ public DocumentMeta(String id, String title, Date updatedAt, Date createdAt, List tags) { // With all
+ this.id = id;
+ this.title = title;
+ this.updatedAt = updatedAt;
+ this.createdAt = createdAt;
+ this.tags = tags;
+ }
+
+ public DocumentMeta(String id, String title, Date updatedAt, Date createdAt) { // Without tags
+ this.id = id;
+ this.title = title;
+ this.updatedAt = updatedAt;
+ this.createdAt = createdAt;
+ this.tags = new ArrayList<>();
+ }
+
+ public DocumentMeta(String id, String title) { // Without tags, updatedAt, createdAt
+ this.id = id;
+ this.title = title;
+ // 現在時刻を設定
+ this.updatedAt = new Date();
+ this.createdAt = new Date();
+ this.tags = new ArrayList<>();
+ }
+
+ public DocumentMeta(String title) { // title only
+ this.id = UUID.randomUUID().toString(); // 新規作成時想定なのでコンストラクタで生成してしまう(使う人が楽なので)
+ this.title = title;
+ // 現在時刻を設定
+ this.updatedAt = new Date();
+ this.createdAt = new Date();
+ this.tags = new ArrayList<>();
+ }
+
+ // Getter
+
+ /**
+ * ドキュメントのID(String)を取得する
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * ドキュメントのタイトル(String)を取得する
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * ドキュメントの更新日時(Date)を取得する
+ */
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ /**
+ * ドキュメントの作成日時(Date)を取得する
+ */
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ /**
+ * ドキュメントのタグ(DocumentTagインスタンスのリスト)を取得する
+ */
+ public List getTags() {
+ return tags;
+ }
+
+ /**
+ * ドキュメントのタグ(DocumentTagインスタンスのリスト)のID(String)を取得する
+ */
+ public List getTagIds() {
+ List tagIds = new ArrayList<>();
+ for (DocumentTag tag : tags) {
+ tagIds.add(tag.getId());
+ }
+ return tagIds;
+ }
+
+ // Setter
+
+ /**
+ * ドキュメントのID(String)を設定する
+ * @param id ドキュメントのID
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * ドキュメントのタイトル(String)を設定する
+ * @param title ドキュメントのタイトル
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * ドキュメントの更新日時(Date)を設定する
+ * @param updatedAt ドキュメントの更新日時
+ */
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ /**
+ * ドキュメントの作成日時(Date)を設定する
+ * @param createdAt ドキュメントの作成日時
+ */
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ /**
+ * ドキュメントのタグ(DocumentTagインスタンスのリスト)を設定する
+ * @param tags ドキュメントのタグ(DocumentTagインスタンスのリスト)
+ */
+ public void setTags(List tags) {
+ this.tags = tags;
+ }
+
+ /**
+ * updatedAtを現在時刻に設定する
+ */
+ public void setUpdatedAtNow() {
+ this.updatedAt = new Date();
+ }
+
+ /**
+ * createdAtを現在時刻に設定する
+ */
+ public void setCreatedAtNow() {
+ this.createdAt = new Date();
+ }
+}
diff --git a/model/src/main/java/one/nem/lacerta/model/document/path/DocumentPath.java b/model/src/main/java/one/nem/lacerta/model/document/path/DocumentPath.java
new file mode 100644
index 00000000..dc933dab
--- /dev/null
+++ b/model/src/main/java/one/nem/lacerta/model/document/path/DocumentPath.java
@@ -0,0 +1,80 @@
+package one.nem.lacerta.model.document.path;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * ドキュメントのパス
+ */
+public class DocumentPath {
+ /**
+ * ドキュメントのルートパス(String)
+ */
+ String rootPath;
+
+ /**
+ * ドキュメントのパス(String)
+ */
+ String path;
+
+ // Constructor
+
+ public DocumentPath() {
+ }
+
+ public DocumentPath(String rootPath, String path) {
+ this.rootPath = rootPath;
+ this.path = path;
+ }
+
+ // Getter
+
+ /**
+ * ドキュメントのルートパス(String)を取得する
+ */
+ public String getRootPath() {
+ return rootPath;
+ }
+
+ /**
+ * ドキュメントのパス(String)を取得する
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * ドキュメントのフルパス(Path)を取得する
+ */
+ public Path getFullPath() {
+ // rootPathとpathを結合して返す
+ return Paths.get(rootPath, path);
+ }
+
+ /**
+ * ドキュメントのフルパス(String)を取得する
+ */
+ public String getFullPathString() {
+ // rootPathとpathを結合して返す
+ return Paths.get(rootPath, path).toString();
+ }
+
+ // Setter
+
+ /**
+ * ドキュメントのルートパス(String)を設定する
+ * @param rootPath ドキュメントのルートパス
+ */
+ public void setRootPath(String rootPath) {
+ this.rootPath = rootPath;
+ }
+
+ /**
+ * ドキュメントのパス(String)を設定する
+ * @param path ドキュメントのパス
+ */
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+}
diff --git a/model/src/main/java/one/nem/lacerta/model/document/placeholder b/model/src/main/java/one/nem/lacerta/model/document/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/model/src/main/java/one/nem/lacerta/model/document/tag/DocumentTag.java b/model/src/main/java/one/nem/lacerta/model/document/tag/DocumentTag.java
new file mode 100644
index 00000000..b00b0847
--- /dev/null
+++ b/model/src/main/java/one/nem/lacerta/model/document/tag/DocumentTag.java
@@ -0,0 +1,82 @@
+package one.nem.lacerta.model.document.tag;
+
+/**
+ * ドキュメントのタグ
+ */
+public class DocumentTag {
+ /**
+ * タグのID(String)
+ */
+ String id;
+
+ /**
+ * タグの名前(String)
+ */
+ String name;
+
+ /**
+ * タグの色(String)
+ */
+ String color;
+
+ // Constructor
+ public DocumentTag() {
+ }
+
+ public DocumentTag(String id, String name, String color) {
+ this.id = id;
+ this.name = name;
+ this.color = color;
+ }
+
+ // Getter
+
+ /**
+ * タグのID(String)を取得する
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * タグの名前(String)を取得する
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * タグの色(String)を取得する
+ */
+ public String getColor() {
+ return color;
+ }
+
+ // Setter
+
+ /**
+ * タグのID(String)を設定する
+ * @param id タグのID
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * タグの名前(String)を設定する
+ * @param name タグの名前
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * タグの色(String)を設定する
+ * @param color タグの色
+ */
+ public void setColor(String color) {
+ this.color = color;
+ }
+
+
+}
diff --git a/model/src/main/java/one/nem/lacerta/model/meta/placeholder b/model/src/main/java/one/nem/lacerta/model/meta/placeholder
new file mode 100644
index 00000000..f3a5362f
--- /dev/null
+++ b/model/src/main/java/one/nem/lacerta/model/meta/placeholder
@@ -0,0 +1 @@
+Deviceのメタデータ, アプリのメタデータとかの型を書く(そのうち)
diff --git a/model/src/test/java/one/nem/lacerta/model/ExampleUnitTest.java b/model/src/test/java/one/nem/lacerta/model/ExampleUnitTest.java
new file mode 100644
index 00000000..98594712
--- /dev/null
+++ b/model/src/test/java/one/nem/lacerta/model/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.model;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/processor/.gitignore b/processor/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/processor/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/processor/build.gradle b/processor/build.gradle
new file mode 100644
index 00000000..cc9c26a7
--- /dev/null
+++ b/processor/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.processor'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/processor/consumer-rules.pro b/processor/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/processor/proguard-rules.pro b/processor/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/processor/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/processor/src/androidTest/java/one/nem/lacerta/processor/ExampleInstrumentedTest.java b/processor/src/androidTest/java/one/nem/lacerta/processor/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..9dd9c65f
--- /dev/null
+++ b/processor/src/androidTest/java/one/nem/lacerta/processor/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.processor;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.processor.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/processor/src/main/AndroidManifest.xml b/processor/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/processor/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/processor/src/test/java/one/nem/lacerta/processor/ExampleUnitTest.java b/processor/src/test/java/one/nem/lacerta/processor/ExampleUnitTest.java
new file mode 100644
index 00000000..00a1deec
--- /dev/null
+++ b/processor/src/test/java/one/nem/lacerta/processor/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.processor;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 00000000..714f8785
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,33 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "Lacerta"
+include ':app'
+include ':feature:home'
+include ':feature:search'
+include ':feature:library'
+include ':feature:scan'
+include ':feature:common'
+include ':component:scanner'
+include ':component:viewer'
+include ':component:common'
+include ':feature:debug'
+include ':data'
+include ':utils'
+include ':source'
+include ':model'
+include ':processor'
+include ':shared:ui'
+include ':shared:icon'
diff --git a/shared/icon/.gitignore b/shared/icon/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/shared/icon/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/shared/icon/build.gradle b/shared/icon/build.gradle
new file mode 100644
index 00000000..53843a1a
--- /dev/null
+++ b/shared/icon/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.shared.icon'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/shared/icon/consumer-rules.pro b/shared/icon/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/shared/icon/proguard-rules.pro b/shared/icon/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/shared/icon/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/shared/icon/src/androidTest/java/one/nem/lacerta/shared/icon/ExampleInstrumentedTest.java b/shared/icon/src/androidTest/java/one/nem/lacerta/shared/icon/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..d76c734d
--- /dev/null
+++ b/shared/icon/src/androidTest/java/one/nem/lacerta/shared/icon/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.shared.icon;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.shared.icon.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/shared/icon/src/main/AndroidManifest.xml b/shared/icon/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/shared/icon/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/shared/icon/src/main/res/drawable/outline_developer_mode_24.xml b/shared/icon/src/main/res/drawable/outline_developer_mode_24.xml
new file mode 100644
index 00000000..9e0fc99c
--- /dev/null
+++ b/shared/icon/src/main/res/drawable/outline_developer_mode_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/shared/icon/src/test/java/one/nem/lacerta/shared/icon/ExampleUnitTest.java b/shared/icon/src/test/java/one/nem/lacerta/shared/icon/ExampleUnitTest.java
new file mode 100644
index 00000000..3ca69c92
--- /dev/null
+++ b/shared/icon/src/test/java/one/nem/lacerta/shared/icon/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.shared.icon;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/shared/ui/.gitignore b/shared/ui/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/shared/ui/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/shared/ui/build.gradle b/shared/ui/build.gradle
new file mode 100644
index 00000000..4ac5c270
--- /dev/null
+++ b/shared/ui/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.shared.ui'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+}
\ No newline at end of file
diff --git a/shared/ui/consumer-rules.pro b/shared/ui/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/shared/ui/proguard-rules.pro b/shared/ui/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/shared/ui/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/shared/ui/src/androidTest/java/one/nem/lacerta/shared/ui/ExampleInstrumentedTest.java b/shared/ui/src/androidTest/java/one/nem/lacerta/shared/ui/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..13b42dc9
--- /dev/null
+++ b/shared/ui/src/androidTest/java/one/nem/lacerta/shared/ui/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.shared.ui;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.shared.ui.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/shared/ui/src/main/AndroidManifest.xml b/shared/ui/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/shared/ui/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/anim/slide_from_left.xml b/shared/ui/src/main/res/anim/slide_from_left.xml
new file mode 100644
index 00000000..35fc851e
--- /dev/null
+++ b/shared/ui/src/main/res/anim/slide_from_left.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/anim/slide_from_right.xml b/shared/ui/src/main/res/anim/slide_from_right.xml
new file mode 100644
index 00000000..289eee8b
--- /dev/null
+++ b/shared/ui/src/main/res/anim/slide_from_right.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/shared/ui/src/main/res/anim/slide_to_left.xml b/shared/ui/src/main/res/anim/slide_to_left.xml
new file mode 100644
index 00000000..9a5293ea
--- /dev/null
+++ b/shared/ui/src/main/res/anim/slide_to_left.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/shared/ui/src/main/res/anim/slide_to_right.xml b/shared/ui/src/main/res/anim/slide_to_right.xml
new file mode 100644
index 00000000..cd3f0f09
--- /dev/null
+++ b/shared/ui/src/main/res/anim/slide_to_right.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/shared/ui/src/main/res/drawable/arrow_back_24px.xml b/shared/ui/src/main/res/drawable/arrow_back_24px.xml
new file mode 100644
index 00000000..fa571fa7
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/arrow_back_24px.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/arrow_forward_24px.xml b/shared/ui/src/main/res/drawable/arrow_forward_24px.xml
new file mode 100644
index 00000000..9739859b
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/arrow_forward_24px.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/developer_mode_24px.xml b/shared/ui/src/main/res/drawable/developer_mode_24px.xml
new file mode 100644
index 00000000..d14234f1
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/developer_mode_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/done_24px.xml b/shared/ui/src/main/res/drawable/done_24px.xml
new file mode 100644
index 00000000..f6b943ea
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/done_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/download_24px.xml b/shared/ui/src/main/res/drawable/download_24px.xml
new file mode 100644
index 00000000..aa86b22d
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/download_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/folder_24px.xml b/shared/ui/src/main/res/drawable/folder_24px.xml
new file mode 100644
index 00000000..d408ae3c
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/folder_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/home_24px.xml b/shared/ui/src/main/res/drawable/home_24px.xml
new file mode 100644
index 00000000..4eb4dbec
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/home_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/menu_24px.xml b/shared/ui/src/main/res/drawable/menu_24px.xml
new file mode 100644
index 00000000..e429681d
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/menu_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/outline_developer_mode_24.xml b/shared/ui/src/main/res/drawable/outline_developer_mode_24.xml
new file mode 100644
index 00000000..7581cc7c
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/outline_developer_mode_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/shared/ui/src/main/res/drawable/outline_home_24.xml b/shared/ui/src/main/res/drawable/outline_home_24.xml
new file mode 100644
index 00000000..b4057b0b
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/outline_home_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/shared/ui/src/main/res/drawable/rounded_secondary_container.xml b/shared/ui/src/main/res/drawable/rounded_secondary_container.xml
new file mode 100644
index 00000000..df079a33
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/rounded_secondary_container.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/drawable/search_24px.xml b/shared/ui/src/main/res/drawable/search_24px.xml
new file mode 100644
index 00000000..d89b5ca2
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/search_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/settings_24px.xml b/shared/ui/src/main/res/drawable/settings_24px.xml
new file mode 100644
index 00000000..8eeb569a
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/settings_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/drawable/star_24px.xml b/shared/ui/src/main/res/drawable/star_24px.xml
new file mode 100644
index 00000000..b9eb4442
--- /dev/null
+++ b/shared/ui/src/main/res/drawable/star_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/shared/ui/src/main/res/values-night-v31/colors.xml b/shared/ui/src/main/res/values-night-v31/colors.xml
new file mode 100644
index 00000000..dfde2504
--- /dev/null
+++ b/shared/ui/src/main/res/values-night-v31/colors.xml
@@ -0,0 +1,28 @@
+
+
+
+ @color/material_dynamic_primary40
+ #FFFFFF
+ @color/material_dynamic_primary90
+ @color/material_dynamic_primary10
+ @color/material_dynamic_primary80
+ @color/material_dynamic_secondary40
+ #FFFFFF
+ @color/material_dynamic_secondary90
+ @color/material_dynamic_secondary10
+ @color/material_dynamic_tertiary40
+ #FFFFFF
+ @color/material_dynamic_tertiary90
+ @color/material_dynamic_tertiary10
+ #B3261E
+ #FFFFFF
+ #F9DEDC
+ #410E0B
+ @color/material_dynamic_neutral_variant50
+ @color/material_dynamic_neutral10
+ @color/material_dynamic_neutral95
+ @color/material_dynamic_neutral10
+ @color/material_dynamic_neutral_variant90
+ @color/material_dynamic_neutral_variant30
+ @color/material_dynamic_neutral20
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/values-night/colors.xml b/shared/ui/src/main/res/values-night/colors.xml
new file mode 100644
index 00000000..d1d52989
--- /dev/null
+++ b/shared/ui/src/main/res/values-night/colors.xml
@@ -0,0 +1,28 @@
+
+
+ #6750A4
+ #FFFFFF
+ #EADDFF
+ #21005D
+ #625B71
+ #FFFFFF
+ #E8DEF8
+ #1D192B
+ #7D5260
+ #FFFFFF
+ #FFD8E4
+ #31111D
+ #B3261E
+ #FFFFFF
+ #F9DEDC
+ #410E0B
+ #79747E
+ #1C1B1F
+ #FFFBFE
+ #1C1B1F
+ #E7E0EC
+ #49454F
+ #313033
+ #F4EFF4
+ #D0BCFF
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/values-notnight-v31/colors.xml b/shared/ui/src/main/res/values-notnight-v31/colors.xml
new file mode 100644
index 00000000..b09c84ac
--- /dev/null
+++ b/shared/ui/src/main/res/values-notnight-v31/colors.xml
@@ -0,0 +1,27 @@
+
+
+ @color/material_dynamic_primary40
+ #FFFFFF
+ @color/material_dynamic_primary90
+ @color/material_dynamic_primary10
+ @color/material_dynamic_primary80
+ @color/material_dynamic_secondary40
+ #FFFFFF
+ @color/material_dynamic_secondary90
+ @color/material_dynamic_secondary10
+ @color/material_dynamic_tertiary40
+ #FFFFFF
+ @color/material_dynamic_tertiary90
+ @color/material_dynamic_tertiary10
+ #B3261E
+ #FFFFFF
+ #F9DEDC
+ #410E0B
+ @color/material_dynamic_neutral_variant50
+ @color/material_dynamic_neutral10
+ @color/material_dynamic_neutral95
+ @color/material_dynamic_neutral10
+ @color/material_dynamic_neutral_variant90
+ @color/material_dynamic_neutral_variant30
+ @color/material_dynamic_neutral20
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/values/colors.xml b/shared/ui/src/main/res/values/colors.xml
new file mode 100644
index 00000000..2f286f0e
--- /dev/null
+++ b/shared/ui/src/main/res/values/colors.xml
@@ -0,0 +1,28 @@
+
+
+ #566500
+ #FFFFFF
+ #D3EF40
+ #181E00
+ #5D6145
+ #FFFFFF
+ #E2E5C2
+ #1A1D08
+ #3A665C
+ #FFFFFF
+ #BDECDF
+ #00201A
+ #BA1A1A
+ #FFFFFF
+ #FFDAD6
+ #410002
+ #77786A
+ #1C1C17
+ #FFFCF4
+ #1C1C17
+ #E4E3D3
+ #46483B
+ #31312B
+ #F3F1E8
+ #B8D321
+
\ No newline at end of file
diff --git a/shared/ui/src/main/res/values/themes.xml b/shared/ui/src/main/res/values/themes.xml
new file mode 100644
index 00000000..9badb88a
--- /dev/null
+++ b/shared/ui/src/main/res/values/themes.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shared/ui/src/test/java/one/nem/lacerta/shared/ui/ExampleUnitTest.java b/shared/ui/src/test/java/one/nem/lacerta/shared/ui/ExampleUnitTest.java
new file mode 100644
index 00000000..36aa4e88
--- /dev/null
+++ b/shared/ui/src/test/java/one/nem/lacerta/shared/ui/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.shared.ui;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/source/.gitignore b/source/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/source/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/source/build.gradle b/source/build.gradle
new file mode 100644
index 00000000..84bcd0a1
--- /dev/null
+++ b/source/build.gradle
@@ -0,0 +1,50 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'one.nem.lacerta.source'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // DI
+ implementation libs.com.google.dagger.hilt.android
+ annotationProcessor libs.com.google.dagger.hilt.compiler
+
+ // Room
+ implementation libs.androidx.room.runtime
+ annotationProcessor libs.androidx.room.compiler
+
+ // JGit
+ implementation 'org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r'
+
+ // Utils モジュール
+ implementation project(':utils')
+
+}
\ No newline at end of file
diff --git a/source/consumer-rules.pro b/source/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/source/proguard-rules.pro b/source/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/source/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/source/src/androidTest/java/one/nem/lacerta/source/ExampleInstrumentedTest.java b/source/src/androidTest/java/one/nem/lacerta/source/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..737c8930
--- /dev/null
+++ b/source/src/androidTest/java/one/nem/lacerta/source/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.source;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("one.nem.lacerta.source.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/source/src/main/AndroidManifest.xml b/source/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/source/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabase.java b/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabase.java
new file mode 100644
index 00000000..68aea700
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabase.java
@@ -0,0 +1,21 @@
+package one.nem.lacerta.source.database;
+
+import androidx.room.Database;
+import androidx.room.RoomDatabase;
+
+// Entities
+import one.nem.lacerta.source.database.entity.TagEntity;
+import one.nem.lacerta.source.database.entity.DocumentEntity;
+import one.nem.lacerta.source.database.entity.LibraryEntity;
+
+// Daos
+import one.nem.lacerta.source.database.dao.TagDao;
+import one.nem.lacerta.source.database.dao.DocumentDao;
+import one.nem.lacerta.source.database.dao.LibraryDao;
+
+@Database(entities = {TagEntity.class, DocumentEntity.class, LibraryEntity.class}, version = 1)
+public abstract class LacertaDatabase extends RoomDatabase {
+ public abstract TagDao tagDao();
+ public abstract DocumentDao documentDao();
+ public abstract LibraryDao libraryDao();
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabaseModule.java b/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabaseModule.java
new file mode 100644
index 00000000..f3e43f95
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabaseModule.java
@@ -0,0 +1,25 @@
+package one.nem.lacerta.source.database;
+
+import android.content.Context;
+
+import androidx.room.Room;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.hilt.InstallIn;
+import dagger.hilt.android.qualifiers.ApplicationContext;
+import dagger.hilt.components.SingletonComponent;
+
+@Module
+@InstallIn(SingletonComponent.class)
+public class LacertaDatabaseModule {
+
+ @Provides
+ public static LacertaDatabase provideLacertaDatabase(@ApplicationContext Context context) {
+ return Room.databaseBuilder(context,
+ LacertaDatabase.class,
+ "lacerta.db")
+ .allowMainThreadQueries() // Debug
+ .build();
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/common/DateTypeConverter.java b/source/src/main/java/one/nem/lacerta/source/database/common/DateTypeConverter.java
new file mode 100644
index 00000000..9d2140e2
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/common/DateTypeConverter.java
@@ -0,0 +1,16 @@
+package one.nem.lacerta.source.database.common;
+
+import androidx.room.TypeConverter;
+
+public class DateTypeConverter {
+
+ @TypeConverter
+ public static java.util.Date fromTimestamp(Long value) {
+ return value == null ? null : new java.util.Date(value);
+ }
+
+ @TypeConverter
+ public static Long dateToTimestamp(java.util.Date date) {
+ return date == null ? null : date.getTime();
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/common/TagArrayListConverter.java b/source/src/main/java/one/nem/lacerta/source/database/common/TagArrayListConverter.java
new file mode 100644
index 00000000..e9bd635b
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/common/TagArrayListConverter.java
@@ -0,0 +1,28 @@
+package one.nem.lacerta.source.database.common;
+
+import androidx.room.TypeConverter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class TagArrayListConverter {
+
+ @TypeConverter
+ public static ArrayList fromString(String value) {
+ return value == null ? null : new ArrayList(Arrays.asList(value.split(",")));
+ }
+
+ @TypeConverter
+ public static String fromArrayList(ArrayList list) {
+ if (list == null) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (String s : list) {
+ sb.append(s);
+ sb.append(",");
+ }
+ return sb.toString();
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/common/TagListConverter.java b/source/src/main/java/one/nem/lacerta/source/database/common/TagListConverter.java
new file mode 100644
index 00000000..0a738651
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/common/TagListConverter.java
@@ -0,0 +1,19 @@
+package one.nem.lacerta.source.database.common;
+
+import androidx.room.TypeConverter;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TagListConverter {
+ @TypeConverter
+ public static String fromList(List list) {
+ return list == null ? null : String.join(",", list);
+ }
+
+ @TypeConverter
+ public static List fromString(String value) {
+ return value == null ? Collections.emptyList() : Arrays.asList(value.split(","));
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/dao/DocumentDao.java b/source/src/main/java/one/nem/lacerta/source/database/dao/DocumentDao.java
new file mode 100644
index 00000000..265b20bc
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/dao/DocumentDao.java
@@ -0,0 +1,64 @@
+package one.nem.lacerta.source.database.dao;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import java.util.List;
+
+import one.nem.lacerta.source.database.entity.DocumentEntity;
+
+
+@Dao
+public interface DocumentDao {
+
+ // Select
+
+ @Query("SELECT * FROM Document WHERE id = :id")
+ DocumentEntity findById(String id);
+
+ @Query("SELECT * FROM Document")
+ List findAll();
+
+ @Query("SELECT * FROM Document LIMIT :limit")
+ List getAllWithLimit(int limit);
+
+ @Query("SELECT * FROM Document WHERE id IN (:ids)")
+ List findByIds(List ids);
+
+ // Insert
+ @Insert
+ void insert(DocumentEntity document);
+
+ @Insert
+ void insertAll(DocumentEntity... documents);
+
+ @Insert
+ void insertAll(List documents);
+
+ // Update
+
+ @Update
+ void update(DocumentEntity document);
+
+ @Update
+ void updateAll(DocumentEntity... documents);
+
+ @Update
+ void updateAll(List documents);
+
+ // Delete
+ @Delete
+ void delete(DocumentEntity document);
+
+ @Delete
+ void deleteAll(DocumentEntity... documents);
+
+ @Delete
+ void deleteAll(List documents);
+
+ @Query("DELETE FROM Document WHERE id = :id")
+ void deleteById(String id);
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/dao/LibraryDao.java b/source/src/main/java/one/nem/lacerta/source/database/dao/LibraryDao.java
new file mode 100644
index 00000000..96cb18a9
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/dao/LibraryDao.java
@@ -0,0 +1,37 @@
+package one.nem.lacerta.source.database.dao;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.Query;
+
+import java.util.List;
+
+import one.nem.lacerta.source.database.entity.LibraryEntity;
+
+@Dao
+public interface LibraryDao {
+
+ // Select
+ @Query("SELECT * FROM Library WHERE id = :id")
+ LibraryEntity findById(String id);
+
+ @Query("SELECT * FROM Library")
+ List findAll();
+
+ @Query("SELECT * FROM Library WHERE id IN (:ids)")
+ List findByIds(List ids);
+
+
+ // Insert
+ @Insert
+ void insert(LibraryEntity libraryEntity);
+
+ @Insert
+ void insertAll(LibraryEntity... libraryEntities);
+
+ @Insert
+ void insertAll(List libraryEntities);
+
+ // Update
+ // TODO-rca: 未実装
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/dao/TagDao.java b/source/src/main/java/one/nem/lacerta/source/database/dao/TagDao.java
new file mode 100644
index 00000000..3d080cb4
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/dao/TagDao.java
@@ -0,0 +1,60 @@
+package one.nem.lacerta.source.database.dao;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import one.nem.lacerta.source.database.entity.TagEntity;
+
+@Dao
+public interface TagDao {
+
+ // Select
+
+ @Query("SELECT * FROM Tag WHERE id = :id")
+ TagEntity findById(String id);
+
+ @Query("SELECT * FROM Tag")
+ List findAll();
+
+ @Query("SELECT * FROM Tag WHERE id IN (:ids)")
+ List findByIds(List ids);
+
+ // Insert
+ @Insert
+ void insert(TagEntity tag);
+
+ @Insert
+ void insertAll(TagEntity... tags);
+
+ @Insert
+ void insertAll(List tags);
+
+ // Update
+ @Update
+ void update(TagEntity tag);
+
+ @Update
+ void updateAll(TagEntity... tags);
+
+ @Update
+ void updateAll(List tags);
+
+ // Delete
+ @Delete
+ void delete(TagEntity tag);
+
+ @Delete
+ void deleteAll(TagEntity... tags);
+
+ @Delete
+ void deleteAll(List tags);
+
+ @Query("DELETE FROM Tag WHERE id = :id")
+ void deleteById(String id);
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/dao/placeholder b/source/src/main/java/one/nem/lacerta/source/database/dao/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/source/src/main/java/one/nem/lacerta/source/database/entity/DocumentEntity.java b/source/src/main/java/one/nem/lacerta/source/database/entity/DocumentEntity.java
new file mode 100644
index 00000000..9f24e42e
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/entity/DocumentEntity.java
@@ -0,0 +1,43 @@
+package one.nem.lacerta.source.database.entity;
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+import androidx.room.TypeConverter;
+import androidx.room.TypeConverters;
+
+import one.nem.lacerta.source.database.common.DateTypeConverter;
+import one.nem.lacerta.source.database.common.TagArrayListConverter;
+import one.nem.lacerta.source.database.common.TagListConverter;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Entity(tableName = "document")
+@TypeConverters({DateTypeConverter.class, TagListConverter.class})
+public class DocumentEntity {
+ @PrimaryKey
+ @ColumnInfo(name = "id")
+ @NonNull
+ public String id; // ドキュメントID
+
+ @ColumnInfo(name = "title")
+ public String title; // タイトル
+
+ @ColumnInfo(name = "created_at")
+ public Date createdAt; // 作成日時
+
+ @ColumnInfo(name = "updated_at")
+ public Date updatedAt; // 更新日時
+
+ @ColumnInfo(name = "author")
+ public String author; // 作成者
+
+ @ColumnInfo(name = "default_branch")
+ public String defaultBranch; // デフォルトブランチ
+
+ @ColumnInfo(name = "tag_ids")
+ public List tagIds; // タグ
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/entity/LibraryEntity.java b/source/src/main/java/one/nem/lacerta/source/database/entity/LibraryEntity.java
new file mode 100644
index 00000000..e8c45b09
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/entity/LibraryEntity.java
@@ -0,0 +1,25 @@
+package one.nem.lacerta.source.database.entity;
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.ForeignKey;
+import androidx.room.PrimaryKey;
+
+import java.util.ArrayList;
+
+@Entity(tableName = "library")
+public class LibraryEntity {
+
+ @PrimaryKey
+ @ColumnInfo(name = "id")
+ @NonNull
+ public String id; // ドキュメントID
+
+ @ColumnInfo(name = "root_path")
+ public String rootPath; // rootのパス
+
+ @ColumnInfo(name = "path")
+ public String path; // パス
+
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/entity/TagEntity.java b/source/src/main/java/one/nem/lacerta/source/database/entity/TagEntity.java
new file mode 100644
index 00000000..ff7e9a82
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/database/entity/TagEntity.java
@@ -0,0 +1,21 @@
+package one.nem.lacerta.source.database.entity;
+
+import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "tag")
+public class TagEntity {
+
+ @PrimaryKey
+ @ColumnInfo(name = "id")
+ @NonNull
+ public String id; // タグID
+
+ @ColumnInfo(name = "tag_name")
+ public String tagName; // タグ名
+
+ @ColumnInfo(name = "color")
+ public String color; // タグの色
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/database/utils/placeholder b/source/src/main/java/one/nem/lacerta/source/database/utils/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/source/src/main/java/one/nem/lacerta/source/file/placeholder b/source/src/main/java/one/nem/lacerta/source/file/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/ActionRepo.java b/source/src/main/java/one/nem/lacerta/source/jgit/ActionRepo.java
new file mode 100644
index 00000000..6bb6f830
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/jgit/ActionRepo.java
@@ -0,0 +1,31 @@
+package one.nem.lacerta.source.jgit;
+
+import org.eclipse.jgit.lib.Repository;
+
+public interface ActionRepo {
+
+ // リポジトリをインスタンス変数に格納
+ void setRepository(Repository repository);
+
+ // リポジトリ取得
+ Repository getRepository();
+
+ // リポジトリ名取得
+ String getRepositoryName();
+
+ // ステージングされていないファイルの一覧を取得
+ String[] getUnstagedFiles();
+
+ // ステージングされているファイルの一覧を取得
+ String[] getStagedFiles();
+
+ // ファイルをステージング
+ void stageFile(String path);
+
+ // ファイルをアンステージング
+ void unstageFile(String path);
+
+ // ステージングされているファイルをコミット
+ void commit(String message);
+
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/JGitRepository.java b/source/src/main/java/one/nem/lacerta/source/jgit/JGitRepository.java
new file mode 100644
index 00000000..09d04f17
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/jgit/JGitRepository.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.source.jgit;
+
+import org.eclipse.jgit.lib.Repository;
+
+public interface JGitRepository {
+
+ // リポジトリ取得
+ Repository getRepository(String id);
+ // リポジトリ作成
+ Repository createRepository(String id);
+ // リポジトリ削除
+ void deleteRepository(String id);
+ // リポジトリ存在確認
+ boolean repositoryExists(String id);
+
+
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/impl/ActionRepoImpl.java b/source/src/main/java/one/nem/lacerta/source/jgit/impl/ActionRepoImpl.java
new file mode 100644
index 00000000..ac94b96f
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/jgit/impl/ActionRepoImpl.java
@@ -0,0 +1,101 @@
+package one.nem.lacerta.source.jgit.impl;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Repository;
+
+import javax.inject.Inject;
+
+import one.nem.lacerta.source.jgit.ActionRepo;
+import one.nem.lacerta.utils.LacertaLogger;
+
+public class ActionRepoImpl implements ActionRepo{
+
+ @Inject // Inject logger
+ LacertaLogger logger;
+
+ private final String TAG = "ActionRepoImpl";
+
+ Repository repository;
+
+ Git git;
+
+ // Internal method
+ private Git getGit() {
+ if (this.git == null) {
+ logger.debug(TAG, "getGit: git is null. Creating new Git instance");
+ this.git = new Git(repository);
+ }
+ return this.git;
+ }
+
+ @Override
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ @Override
+ public Repository getRepository() {
+ if (repository == null) {
+ logger.warn(TAG, "getRepository: repository is null. Throwing RuntimeException");
+ throw new RuntimeException("リポジトリが設定されていません");
+ }
+ return repository;
+ }
+
+ @Override
+ public String getRepositoryName() {
+ return repository.getDirectory().getParentFile().getName();
+ }
+
+ @Override
+ public String[] getUnstagedFiles() {
+ Git git = getGit();
+ try {
+ return git.status().call().getUntracked().toArray(new String[0]);
+ } catch (Exception e) { // TODO-rca: エラーハンドリング
+ logger.error(TAG, "getUnstagedFiles: " + e.getMessage());
+ return new String[0];
+ }
+ }
+
+ @Override
+ public String[] getStagedFiles() {
+ Git git = getGit();
+ try {
+ return git.status().call().getAdded().toArray(new String[0]);
+ } catch (Exception e) { // TODO-rca: エラーハンドリング
+ logger.error(TAG, "getStagedFiles: " + e.getMessage());
+ return new String[0];
+ }
+ }
+
+ @Override
+ public void stageFile(String path) {
+ Git git = getGit();
+ try {
+ git.add().addFilepattern(path).call();
+ } catch (Exception e) { // TODO-rca: エラーハンドリング
+ logger.error(TAG, "stageFile: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public void unstageFile(String path) {
+ Git git = getGit();
+ try {
+ git.reset().addPath(path).call();
+ } catch (Exception e) { // TODO-rca: エラーハンドリング
+ logger.error(TAG, "unstageFile: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public void commit(String message) {
+ Git git = getGit();
+ try {
+ git.commit().setMessage(message).call();
+ } catch (Exception e) { // TODO-rca: エラーハンドリング
+ logger.error(TAG, "commit: " + e.getMessage());
+ }
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/impl/JGitRepositoryImpl.java b/source/src/main/java/one/nem/lacerta/source/jgit/impl/JGitRepositoryImpl.java
new file mode 100644
index 00000000..fabcb0bb
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/jgit/impl/JGitRepositoryImpl.java
@@ -0,0 +1,55 @@
+package one.nem.lacerta.source.jgit.impl;
+
+import one.nem.lacerta.source.jgit.JGitRepository;
+
+import javax.inject.Inject;
+
+import one.nem.lacerta.utils.repository.DeviceInfoUtils;
+
+import org.eclipse.jgit.lib.Repository;
+
+import org.eclipse.jgit.lib.RepositoryBuilder;
+
+public class JGitRepositoryImpl implements JGitRepository {
+
+ private final DeviceInfoUtils deviceInfoUtils;
+
+ @Inject
+ public JGitRepositoryImpl(DeviceInfoUtils deviceInfoUtils) {
+ this.deviceInfoUtils = deviceInfoUtils;
+ }
+
+ @Override
+ public Repository getRepository(String id) {
+ RepositoryBuilder repositoryBuilder = new RepositoryBuilder();
+ repositoryBuilder.setGitDir(deviceInfoUtils.getExternalStorageDirectory().resolve(id).resolve(".git").toFile());
+ repositoryBuilder.setMustExist(true);
+ try {
+ return repositoryBuilder.build();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public Repository createRepository(String id) {
+ RepositoryBuilder repositoryBuilder = new RepositoryBuilder();
+ repositoryBuilder.setGitDir(deviceInfoUtils.getExternalStorageDirectory().resolve(id).resolve(".git").toFile());
+ repositoryBuilder.setMustExist(false);
+ try {
+ return repositoryBuilder.build();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void deleteRepository(String id) {
+ // TODO-rca: 未実装
+ }
+
+ @Override
+ public boolean repositoryExists(String id) {
+ return false; // TODO-rca: 未実装
+ }
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/impl/placeholder b/source/src/main/java/one/nem/lacerta/source/jgit/impl/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/module/JGitRepositoryModule.java b/source/src/main/java/one/nem/lacerta/source/jgit/module/JGitRepositoryModule.java
new file mode 100644
index 00000000..4c9b8fde
--- /dev/null
+++ b/source/src/main/java/one/nem/lacerta/source/jgit/module/JGitRepositoryModule.java
@@ -0,0 +1,15 @@
+package one.nem.lacerta.source.jgit.module;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+import one.nem.lacerta.source.jgit.JGitRepository;
+
+@Module
+@InstallIn(SingletonComponent.class)
+abstract public class JGitRepositoryModule {
+
+ @Binds
+ public abstract JGitRepository bindManageRepo(one.nem.lacerta.source.jgit.impl.JGitRepositoryImpl manageRepoImpl);
+}
diff --git a/source/src/main/java/one/nem/lacerta/source/jgit/module/placeholder b/source/src/main/java/one/nem/lacerta/source/jgit/module/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/source/src/test/java/one/nem/lacerta/source/ExampleUnitTest.java b/source/src/test/java/one/nem/lacerta/source/ExampleUnitTest.java
new file mode 100644
index 00000000..57400c2c
--- /dev/null
+++ b/source/src/test/java/one/nem/lacerta/source/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.source;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/utils/.gitignore b/utils/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/utils/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/utils/build.gradle b/utils/build.gradle
new file mode 100644
index 00000000..db7197a6
--- /dev/null
+++ b/utils/build.gradle
@@ -0,0 +1,41 @@
+plugins {
+ alias(libs.plugins.com.android.library)
+}
+
+android {
+ namespace 'oen.nem.lacerta.utils'
+ compileSdk 34
+
+ defaultConfig {
+ minSdk 26
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation libs.androidx.appcompat
+ implementation libs.com.google.android.material
+ testImplementation libs.junit
+ androidTestImplementation libs.androidx.test.ext.junit
+ androidTestImplementation libs.androidx.test.espresso.core
+
+ // Hilt
+ implementation libs.com.google.dagger.hilt.android
+ annotationProcessor libs.com.google.dagger.hilt.compiler
+
+ //
+}
\ No newline at end of file
diff --git a/utils/consumer-rules.pro b/utils/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/utils/proguard-rules.pro b/utils/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/utils/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/utils/src/androidTest/java/one/nem/lacerta/utils/ExampleInstrumentedTest.java b/utils/src/androidTest/java/one/nem/lacerta/utils/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..12359216
--- /dev/null
+++ b/utils/src/androidTest/java/one/nem/lacerta/utils/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package one.nem.lacerta.utils;
+
+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 Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("oen.nem.lacerta.utils.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/utils/src/main/AndroidManifest.xml b/utils/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/utils/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/utils/src/main/java/one/nem/lacerta/utils/LacertaLogger.java b/utils/src/main/java/one/nem/lacerta/utils/LacertaLogger.java
new file mode 100644
index 00000000..f49da584
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/LacertaLogger.java
@@ -0,0 +1,12 @@
+package one.nem.lacerta.utils;
+
+public interface LacertaLogger {
+
+ void info(String tag, String message);
+ void warn(String tag, String message);
+ void error(String tag, String message);
+ void debug(String tag, String message);
+ void trace(String tag, String message);
+ void fatal(String tag, String message);
+
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/ModuleTODO.md b/utils/src/main/java/one/nem/lacerta/utils/ModuleTODO.md
new file mode 100644
index 00000000..33089d12
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/ModuleTODO.md
@@ -0,0 +1,2 @@
+TODO:
+- repositoryパッケージに含めるか検討する
\ No newline at end of file
diff --git a/utils/src/main/java/one/nem/lacerta/utils/impl/DeviceInfoUtilsImpl.java b/utils/src/main/java/one/nem/lacerta/utils/impl/DeviceInfoUtilsImpl.java
new file mode 100644
index 00000000..1cb5c759
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/impl/DeviceInfoUtilsImpl.java
@@ -0,0 +1,52 @@
+package one.nem.lacerta.utils.impl;
+
+import android.content.Context;
+
+import java.nio.file.Path;
+import java.util.Objects;
+
+import javax.inject.Inject;
+
+import dagger.hilt.android.qualifiers.ApplicationContext;
+import one.nem.lacerta.utils.repository.DeviceInfoUtils;
+public class DeviceInfoUtilsImpl implements DeviceInfoUtils {
+
+ private final Context applicationContext;
+
+ @Inject
+ public DeviceInfoUtilsImpl(@ApplicationContext Context applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Override
+ public Path getExternalStorageDirectory() {
+ // TODO-rca: 結果がnullだった場合の処理を追加する?
+ return Objects.requireNonNull(applicationContext.getExternalFilesDir(null)).toPath();
+ }
+
+ @Override
+ public String getExternalStorageDirectoryString() {
+ return getExternalStorageDirectory().toString();
+ }
+
+ @Override
+ public Path getExternalStorageDirectory(String type) {
+ // TODO-rca: 結果がnullだった場合の処理を追加する?
+ return Objects.requireNonNull(applicationContext.getExternalFilesDir(type)).toPath();
+ }
+
+ @Override
+ public String getExternalStorageDirectoryString(String type) {
+ return getExternalStorageDirectory(type).toString();
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return false;
+ }
+
+ @Override
+ public boolean hasPermissions(String[] permissions) {
+ return false;
+ }
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/impl/LacertaLoggerImpl.java b/utils/src/main/java/one/nem/lacerta/utils/impl/LacertaLoggerImpl.java
new file mode 100644
index 00000000..aba337d8
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/impl/LacertaLoggerImpl.java
@@ -0,0 +1,43 @@
+package one.nem.lacerta.utils.impl;
+
+import android.util.Log;
+
+import javax.inject.Inject;
+
+import one.nem.lacerta.utils.LacertaLogger;
+public class LacertaLoggerImpl implements LacertaLogger{
+
+ @Inject
+ public LacertaLoggerImpl() {
+ }
+
+ @Override
+ public void info(String tag, String message) {
+ Log.i(tag, message);
+ }
+
+ @Override
+ public void warn(String tag, String message) {
+ Log.w(tag, message);
+ }
+
+ @Override
+ public void error(String tag, String message) {
+ Log.e(tag, message);
+ }
+
+ @Override
+ public void debug(String tag, String message) {
+ Log.d(tag, message);
+ }
+
+ @Override
+ public void trace(String tag, String message) {
+ Log.v(tag, message);
+ }
+
+ @Override
+ public void fatal(String tag, String message) {
+ Log.wtf(tag, message);
+ }
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/impl/SharedPrefUtilsImpl.java b/utils/src/main/java/one/nem/lacerta/utils/impl/SharedPrefUtilsImpl.java
new file mode 100644
index 00000000..f976b46b
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/impl/SharedPrefUtilsImpl.java
@@ -0,0 +1,29 @@
+package one.nem.lacerta.utils.impl;
+
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import dagger.hilt.android.qualifiers.ApplicationContext;
+import one.nem.lacerta.utils.repository.SharedPrefUtils;
+
+public class SharedPrefUtilsImpl implements SharedPrefUtils{
+
+ private final Context applicationContext;
+
+ public SharedPrefUtilsImpl(@ApplicationContext Context applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Override
+ public SharedPreferences.Editor getEditor() {
+ // Editorの取得
+ return applicationContext.getSharedPreferences("common", Context.MODE_PRIVATE).edit(); // TODO-rca: 決め打ちやめる?
+ }
+
+ @Override
+ public SharedPreferences.Editor getEditor(String name) {
+ // Editorの取得
+ return applicationContext.getSharedPreferences(name, Context.MODE_PRIVATE).edit();
+ }
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/impl/placeholder b/utils/src/main/java/one/nem/lacerta/utils/impl/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/utils/src/main/java/one/nem/lacerta/utils/module/DeviceInfoUtilsModule.java b/utils/src/main/java/one/nem/lacerta/utils/module/DeviceInfoUtilsModule.java
new file mode 100644
index 00000000..9f47b6b9
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/module/DeviceInfoUtilsModule.java
@@ -0,0 +1,16 @@
+package one.nem.lacerta.utils.module;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+import one.nem.lacerta.utils.repository.DeviceInfoUtils;
+import one.nem.lacerta.utils.impl.DeviceInfoUtilsImpl;
+
+@Module
+@InstallIn(SingletonComponent.class) // TODO-rca: Singletonである必要があるのか検討する?
+abstract public class DeviceInfoUtilsModule {
+
+ @Binds
+ public abstract DeviceInfoUtils bindDeviceInfoUtils(DeviceInfoUtilsImpl deviceInfoUtilsImpl);
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/module/LacertaLoggerModule.java b/utils/src/main/java/one/nem/lacerta/utils/module/LacertaLoggerModule.java
new file mode 100644
index 00000000..38e0abd9
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/module/LacertaLoggerModule.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.utils.module;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+
+import one.nem.lacerta.utils.LacertaLogger;
+import one.nem.lacerta.utils.impl.LacertaLoggerImpl;
+
+@Module
+@InstallIn(SingletonComponent.class) // ログの取得であまり負荷をかけたくないので
+abstract public class LacertaLoggerModule {
+
+ @Binds
+ public abstract LacertaLogger bindLacertaLogger(LacertaLoggerImpl lacertaLoggerImpl);
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/module/SharedPrefUtilsModule.java b/utils/src/main/java/one/nem/lacerta/utils/module/SharedPrefUtilsModule.java
new file mode 100644
index 00000000..e3df3b91
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/module/SharedPrefUtilsModule.java
@@ -0,0 +1,16 @@
+package one.nem.lacerta.utils.module;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.hilt.InstallIn;
+import dagger.hilt.components.SingletonComponent;
+import one.nem.lacerta.utils.repository.SharedPrefUtils;
+import one.nem.lacerta.utils.impl.SharedPrefUtilsImpl;
+
+@Module
+@InstallIn(SingletonComponent.class) // TODO-rca: Singletonである必要があるのか検討する?
+abstract class SharedPrefUtilsModule {
+
+ @Binds
+ public abstract SharedPrefUtils bindSharedPrefUtils(SharedPrefUtilsImpl sharedPrefUtilsImpl);
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/module/placeholder b/utils/src/main/java/one/nem/lacerta/utils/module/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/utils/src/main/java/one/nem/lacerta/utils/repository/DeviceInfoUtils.java b/utils/src/main/java/one/nem/lacerta/utils/repository/DeviceInfoUtils.java
new file mode 100644
index 00000000..5a21b1ad
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/repository/DeviceInfoUtils.java
@@ -0,0 +1,21 @@
+package one.nem.lacerta.utils.repository;
+
+import java.nio.file.Path;
+
+public interface DeviceInfoUtils {
+
+ // External storage directory
+ Path getExternalStorageDirectory();
+
+ String getExternalStorageDirectoryString();
+
+ Path getExternalStorageDirectory(String type);
+
+ String getExternalStorageDirectoryString(String type);
+
+ // Permission
+ boolean hasPermission(String permission);
+
+ boolean hasPermissions(String[] permissions);
+
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/repository/SharedPrefUtils.java b/utils/src/main/java/one/nem/lacerta/utils/repository/SharedPrefUtils.java
new file mode 100644
index 00000000..68d21ae7
--- /dev/null
+++ b/utils/src/main/java/one/nem/lacerta/utils/repository/SharedPrefUtils.java
@@ -0,0 +1,13 @@
+package one.nem.lacerta.utils.repository;
+
+import android.content.SharedPreferences;
+
+public interface SharedPrefUtils {
+
+ // Shared preferences editorの取得
+ SharedPreferences.Editor getEditor();
+
+ // TODO-rca: 名称をenumで管理する?
+ SharedPreferences.Editor getEditor(String name);
+
+}
diff --git a/utils/src/main/java/one/nem/lacerta/utils/repository/placeholder b/utils/src/main/java/one/nem/lacerta/utils/repository/placeholder
new file mode 100644
index 00000000..e69de29b
diff --git a/utils/src/test/java/one/nem/lacerta/utils/ExampleUnitTest.java b/utils/src/test/java/one/nem/lacerta/utils/ExampleUnitTest.java
new file mode 100644
index 00000000..49c38293
--- /dev/null
+++ b/utils/src/test/java/one/nem/lacerta/utils/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package one.nem.lacerta.utils;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file