diff --git a/app/src/main/java/one/nem/lacerta/MainActivity.java b/app/src/main/java/one/nem/lacerta/MainActivity.java index a43cbf4d..725c1063 100644 --- a/app/src/main/java/one/nem/lacerta/MainActivity.java +++ b/app/src/main/java/one/nem/lacerta/MainActivity.java @@ -5,12 +5,16 @@ import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; import androidx.navigation.NavController; import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.ui.NavigationUI; +import android.graphics.Color; import android.os.Bundle; import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.widget.Toast; import one.nem.lacerta.model.FragmentNavigation; @@ -21,6 +25,8 @@ import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.bottomnavigation.BottomNavigationView; +import java.io.NotActiveException; + import dagger.hilt.android.AndroidEntryPoint; import one.nem.lacerta.utils.repository.SharedPrefUtils; @@ -68,37 +74,7 @@ public class MainActivity extends AppCompatActivity implements FragmentNavigatio // Set status bar color getWindow().setStatusBarColor(ContextCompat.getColor(this, one.nem.lacerta.shared.ui.R.color.colorSurface)); - // Set app bar color - AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout); - appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { - @Override - public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { - if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) { - // Collapsed - getWindow().setStatusBarColor(ContextCompat.getColor(getApplicationContext(), one.nem.lacerta.shared.ui.R.color.colorSecondaryContainer)); - } else if (verticalOffset == 0) { - // Expanded - getWindow().setStatusBarColor(ContextCompat.getColor(getApplicationContext(), one.nem.lacerta.shared.ui.R.color.colorSurface)); - } else { - // Somewhere in between - // Here you can add a color transition if you want - } - } - }); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); } - - // Public - public void setActionBarTitle(String title) { - getSupportActionBar().setTitle(title); - } - - public void setActionBarBackButton(boolean isEnabled) { - getSupportActionBar().setDisplayHomeAsUpEnabled(isEnabled); - } - private void initializeApp() { Log.d("Init", "Initializing app"); // Set feature switch override to default value @@ -121,4 +97,61 @@ public class MainActivity extends AppCompatActivity implements FragmentNavigatio .addToBackStack(null) .commit(); } + + @Override + public void navigateToFragment(Fragment fragment, boolean addToBackStack) { + if (addToBackStack) { + getSupportFragmentManager().beginTransaction() + .replace(R.id.nav_host_fragment, fragment) + .addToBackStack(null) + .commit(); + } else { + getSupportFragmentManager().beginTransaction() + .replace(R.id.nav_host_fragment, fragment) + .commit(); + } + } + + @Override + public void navigateToFragment(Fragment fragment, boolean addToBackStack, boolean clearBackStack) { + if (clearBackStack) { + getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + if (addToBackStack) { + getSupportFragmentManager().beginTransaction() + .replace(R.id.nav_host_fragment, fragment) + .addToBackStack(null) + .commit(); + } else { + getSupportFragmentManager().beginTransaction() + .replace(R.id.nav_host_fragment, fragment) + .commit(); + } + } + + public void navigateToFragmentAlternate(Fragment fragment, boolean addToBackStack) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + // get the current fragment + Fragment currentFragment = getSupportFragmentManager().getPrimaryNavigationFragment(); + + // hide the current fragment + if (currentFragment != null) { + transaction.hide(currentFragment); + } + + // Add the new fragment + transaction.add(R.id.nav_host_fragment, fragment); + + // Add the transaction to the back stack if needed + if (addToBackStack) { + transaction.addToBackStack(null); + } + + // Commit the transaction + transaction.commit(); + + // Update the primary navigation fragment + getSupportFragmentManager().beginTransaction().setPrimaryNavigationFragment(fragment).commit(); + } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 262b305b..59d77a93 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,61 +1,24 @@ + + android:theme="@style/Theme.Lacerta" + tools:context=".MainActivity"> - - - - - - - - - - - - - - - + app:layout_constraintTop_toTopOf="parent" + app:navGraph="@navigation/main_nav" + tools:layout="@layout/fragment_home_top" /> > getRecentDocument(int limit); CompletableFuture> getRecentDocument(int limit, int offset); - // Get Library page - CompletableFuture getLibraryPage(int limit); - CompletableFuture getLibraryPage(int limit, int offset); + // Get Library Page CompletableFuture getLibraryPage(String pageId, int limit); CompletableFuture getLibraryPage(String pageId, int limit, int offset); // Create Folder - CompletableFuture createFolder(String path, String name); + CompletableFuture createFolder(String parentId, String name); + + // Get Public Path + CompletableFuture getPublicPath(String itemId, ListItemType itemType); } 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 index 47f8e9a2..888a47f6 100644 --- a/data/src/main/java/one/nem/lacerta/data/impl/DocumentImpl.java +++ b/data/src/main/java/one/nem/lacerta/data/impl/DocumentImpl.java @@ -79,7 +79,7 @@ public class DocumentImpl implements Document { documentEntity.defaultBranch = meta.getDefaultBranch(); documentEntity.updatedAt = meta.getUpdatedAt(); documentEntity.createdAt = meta.getCreatedAt(); - documentEntity.publicPath = meta.getPath().getStringPath(); + documentEntity.parentId = meta.getParentId(); documentEntity.tagIds = meta.getTagIds(); database.documentDao().insert(documentEntity); @@ -104,7 +104,7 @@ public class DocumentImpl implements Document { meta.setDefaultBranch("master"); meta.setUpdatedAt(new Date()); meta.setCreatedAt(new Date()); - meta.setPath(new PublicPath().getRoot()); // TODO-rca: 2回インスタンスを生成していて無駄なのでなんとかする + meta.setParentId(null); meta.setTags(new ArrayList<>()); return createDocument(meta); } @@ -138,7 +138,7 @@ public class DocumentImpl implements Document { meta.setDefaultBranch(documentEntity.defaultBranch); meta.setUpdatedAt(documentEntity.updatedAt); meta.setCreatedAt(documentEntity.createdAt); - meta.setPath(new PublicPath().resolve(documentEntity.publicPath)); + meta.setParentId(documentEntity.parentId); meta.setTags(new ArrayList<>()); // TODO-rca: タグを取得する DocumentDetail detail = new DocumentDetail(); diff --git a/data/src/main/java/one/nem/lacerta/data/impl/LacertaLibraryImpl.java b/data/src/main/java/one/nem/lacerta/data/impl/LacertaLibraryImpl.java index f1897557..2d5d1f93 100644 --- a/data/src/main/java/one/nem/lacerta/data/impl/LacertaLibraryImpl.java +++ b/data/src/main/java/one/nem/lacerta/data/impl/LacertaLibraryImpl.java @@ -4,6 +4,7 @@ import java.text.DateFormat; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -20,6 +21,7 @@ import one.nem.lacerta.source.database.LacertaDatabase; import one.nem.lacerta.source.database.common.DateTypeConverter; import one.nem.lacerta.source.database.entity.DocumentEntity; import one.nem.lacerta.source.database.entity.FolderEntity; +import one.nem.lacerta.utils.FeatureSwitch; import one.nem.lacerta.utils.LacertaLogger; public class LacertaLibraryImpl implements LacertaLibrary { @@ -64,95 +66,35 @@ public class LacertaLibraryImpl implements LacertaLibrary { return null; // TODO-rca: Implement } - // Internal - private CompletableFuture> getFolderEntitiesByPublicPath(String publicPath) { - return CompletableFuture.supplyAsync(() -> { - return database.folderDao().findByPublicPathWithLimit(publicPath, 10); // TODO-rca: ハードコーディングやめる - }); - } - - private CompletableFuture> getDocumentEntitiesByPublicPath(String publicPath) { - return CompletableFuture.supplyAsync(() -> { - return database.documentDao().findByPublicPathWithLimit(publicPath, 10); // TODO-rca: ハードコーディングやめる - }); - } - - @Override - public CompletableFuture getLibraryPage(int limit) { - return CompletableFuture.supplyAsync(() -> { - - // 5秒フリーズさせる - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - LibraryItemPage libraryItemPage = new LibraryItemPage(); - - List folderEntities = getFolderEntitiesByPublicPath("/").join(); - logger.debug("LacertaLibraryImpl", "folderEntities.size(): " + folderEntities.size()); - List documentEntities = getDocumentEntitiesByPublicPath("/").join(); - logger.debug("LacertaLibraryImpl", "documentEntities.size(): " + documentEntities.size()); - - ArrayList listItems = new ArrayList<>(); - for (FolderEntity folderEntity : folderEntities) { - logger.debug("LacertaLibraryImpl", "folderEntity.name: " + folderEntity.name); - ListItem listItem = new ListItem(); - listItem.setItemType(ListItemType.ITEM_TYPE_FOLDER); - listItem.setTitle(folderEntity.name); - listItem.setDescription("フォルダ"); // TODO-rca: ハードコーディングやめる - listItem.setItemId(folderEntity.id); - listItems.add(listItem); - } - for (DocumentEntity documentEntity : documentEntities) { - logger.debug("LacertaLibraryImpl", "documentEntity.title: " + documentEntity.title); - ListItem listItem = new ListItem(); - listItem.setItemType(ListItemType.ITEM_TYPE_DOCUMENT); - listItem.setTitle(documentEntity.title); -// listItem.setDescription(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm").format(documentEntity.updatedAt.toInstant())); - listItem.setItemId(documentEntity.id); - listItems.add(listItem); - } - - libraryItemPage.setPageTitle("/"); - libraryItemPage.setPageId("root"); - libraryItemPage.setListItems(listItems); - - logger.debug("LacertaLibraryImpl", "libraryItemPage.getListItems().size(): " + libraryItemPage.getListItems().size()); - - return libraryItemPage; - }); - } - - @Override - public CompletableFuture getLibraryPage(int limit, int offset) { - return CompletableFuture.supplyAsync(() -> { - return null; - }); - } - @Override public CompletableFuture getLibraryPage(String pageId, int limit) { return CompletableFuture.supplyAsync(() -> { LibraryItemPage libraryItemPage = new LibraryItemPage(); - FolderEntity folderEntity = database.folderDao().findById(pageId); - if (folderEntity == null) { - return null; + List folderEntities; + List documentEntities; + + if (pageId == null) { // When root folder + libraryItemPage.setPageTitle("ライブラリ"); + libraryItemPage.setPageId(null); + libraryItemPage.setParentId(null); + + folderEntities = database.folderDao().findRootFolders(); + documentEntities = database.documentDao().findRootDocuments(); + } else { + FolderEntity folderEntity = database.folderDao().findById(pageId); + if (folderEntity == null) { + logger.warn("LacertaLibraryImpl", pageId + " is not found."); + return null; + } + libraryItemPage.setPageTitle(folderEntity.name); + libraryItemPage.setPageId(folderEntity.id); + libraryItemPage.setParentId(folderEntity.parentId); + + folderEntities = database.folderDao().findByParentId(pageId); + documentEntities = database.documentDao().findByParentId(pageId); } - PublicPath publicPath = new PublicPath().parse(folderEntity.publicPath); - - String resolvedPublicPath = publicPath.resolve(folderEntity.name).getStringPath(); - - logger.debug("LacertaLibraryImpl", "Resolved publicPath: " + resolvedPublicPath); - - List folderEntities = getFolderEntitiesByPublicPath(resolvedPublicPath).join(); - logger.debug("LacertaLibraryImpl", "folderEntities.size(): " + folderEntities.size()); - List documentEntities = getDocumentEntitiesByPublicPath(resolvedPublicPath).join(); - logger.debug("LacertaLibraryImpl", "documentEntities.size(): " + documentEntities.size()); - ArrayList listItems = new ArrayList<>(); for (FolderEntity childFolderEntity : folderEntities) { logger.debug("LacertaLibraryImpl", "childFolderEntity.name: " + childFolderEntity.name); @@ -174,8 +116,6 @@ public class LacertaLibraryImpl implements LacertaLibrary { listItems.add(listItem); } - libraryItemPage.setPageTitle(folderEntity.name); - libraryItemPage.setPageId(folderEntity.id); libraryItemPage.setListItems(listItems); logger.debug("LacertaLibraryImpl", "libraryItemPage.getListItems().size(): " + libraryItemPage.getListItems().size()); @@ -194,21 +134,67 @@ public class LacertaLibraryImpl implements LacertaLibrary { @Override public CompletableFuture createFolder(String parentId, String name) { return CompletableFuture.supplyAsync(() -> { - - FolderEntity parentFolderEntity = database.folderDao().findById(parentId); - PublicPath publicPath; - if (parentFolderEntity == null) { - publicPath = new PublicPath().resolve("/"); - } else { - publicPath = new PublicPath().resolve(parentFolderEntity.publicPath); - } - FolderEntity folderEntity = new FolderEntity(); folderEntity.id = UUID.randomUUID().toString(); folderEntity.name = name; - folderEntity.publicPath = publicPath.getStringPath(); + folderEntity.parentId = parentId; database.folderDao().insert(folderEntity); return folderEntity.id; }); } + + @Override + public CompletableFuture getPublicPath(String itemId, ListItemType itemType) { + return CompletableFuture.supplyAsync(() -> { + if (itemType == ListItemType.ITEM_TYPE_DOCUMENT) { + DocumentEntity documentEntity = database.documentDao().findById(itemId); + if (documentEntity == null) { + logger.warn("LacertaLibraryImpl", itemId + " is not found."); + return null; + } + PublicPath publicPath = recursiveResolve(documentEntity.parentId); + publicPath.resolve(documentEntity.title); + return publicPath; + } else if (itemType == ListItemType.ITEM_TYPE_FOLDER) { + FolderEntity folderEntity = database.folderDao().findById(itemId); + if (folderEntity == null) { + return null; + } + return recursiveResolve(folderEntity.id); + } else { + logger.warn("LacertaLibraryImpl", "Unknown ListItemType: " + itemType); + return null; + } + }); + } + + /** + * 再帰的にパスを解決する + * + * @param folderId + * @return + */ + private PublicPath recursiveResolve(String folderId) { + String current = folderId; + boolean continueFlag = true; + ArrayList folderNames = new ArrayList<>(); + while (continueFlag) { + FolderEntity folderEntity = database.folderDao().findById(current); + if (folderEntity == null) { // 存在しないフォルダIDが指定された場合 + continueFlag = false; + } else { + folderNames.add(folderEntity.name); + current = folderEntity.parentId; + if (current == null) { // ルートフォルダに到達した場合 + continueFlag = false; + } + } + } + + // フォルダ名を逆順にしてListに変換 + Collections.reverse(folderNames); + List folderNamesReversed = new ArrayList<>(folderNames); + + return new PublicPath(folderNamesReversed); + } } diff --git a/feature/home/src/main/res/layout/fragment_home_top.xml b/feature/home/src/main/res/layout/fragment_home_top.xml index 73850323..3fc0b723 100644 --- a/feature/home/src/main/res/layout/fragment_home_top.xml +++ b/feature/home/src/main/res/layout/fragment_home_top.xml @@ -1,11 +1,50 @@ + android:layout_height="match_parent" + android:background="@color/colorSurface"> - + android:layout_height="match_parent"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryPageFragment.java b/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryPageFragment.java index 14baa90c..876d62e6 100644 --- a/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryPageFragment.java +++ b/feature/library/src/main/java/one/nem/lacerta/feature/library/LibraryPageFragment.java @@ -4,7 +4,11 @@ import android.app.AlertDialog; import android.os.Bundle; import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import androidx.navigation.Navigation; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -14,13 +18,28 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; import android.widget.Toast; +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + +import org.w3c.dom.Text; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +import one.nem.lacerta.data.Document; import one.nem.lacerta.data.LacertaLibrary; import one.nem.lacerta.model.FragmentNavigation; +import one.nem.lacerta.model.LibraryItemPage; +import one.nem.lacerta.model.PublicPath; import one.nem.lacerta.utils.LacertaLogger; @@ -32,8 +51,15 @@ import one.nem.lacerta.utils.LacertaLogger; @AndroidEntryPoint public class LibraryPageFragment extends Fragment { - // Param - private String folderId; + // Variables + // このインスタンスで表示されているページ + LibraryItemPage libraryItemPage; + + // Arguments + String folderId; + String title; + String parentId; + @Inject LacertaLibrary lacertaLibrary; @@ -43,15 +69,26 @@ public class LibraryPageFragment extends Fragment { ListItemAdapter listItemAdapter; - int currentTotalItemCount = 0; - public LibraryPageFragment() { // Required empty public constructor } - public static LibraryPageFragment newInstance(String folderId) { + + public static LibraryPageFragment newInstance(String folderId, String title, String parentId) { LibraryPageFragment fragment = new LibraryPageFragment(); Bundle args = new Bundle(); args.putString("folderId", folderId); + args.putString("title", title); + args.putString("publicPath", parentId); + fragment.setArguments(args); + return fragment; + } + + public static LibraryPageFragment newInstance(String folderId) { // Back action + LibraryPageFragment fragment = new LibraryPageFragment(); + Bundle args = new Bundle(); + args.putString("folderId", folderId); + args.putString("title", null); + args.putString("publicPath", null); fragment.setArguments(args); return fragment; } @@ -60,6 +97,8 @@ public class LibraryPageFragment extends Fragment { LibraryPageFragment fragment = new LibraryPageFragment(); Bundle args = new Bundle(); args.putString("folderId", null); + args.putString("title", null); + args.putString("publicPath", null); fragment.setArguments(args); return fragment; } @@ -75,8 +114,23 @@ public class LibraryPageFragment extends Fragment { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_library_top, container, false); - setHasOptionsMenu(true); - + // Set status bar color + AppBarLayout appBarLayout = view.findViewById(R.id.app_bar_layout); + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) { + // Collapsed + getActivity().getWindow().setStatusBarColor(ContextCompat.getColor(getContext(), one.nem.lacerta.shared.ui.R.color.colorSecondaryContainer)); + } else if (verticalOffset == 0) { + // Expanded + getActivity().getWindow().setStatusBarColor(ContextCompat.getColor(getContext(), one.nem.lacerta.shared.ui.R.color.colorSurface)); + } else { + // Somewhere in between + // Here you can add a color transition if you want + } + } + }); return view; } @@ -84,16 +138,42 @@ public class LibraryPageFragment extends Fragment { public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - RecyclerView recyclerView = view.findViewById(R.id.library_item_recycler_view); + if (getArguments() != null) { + this.folderId = getArguments().getString("folderId"); // Required + if (getArguments().getString("title") == null && getArguments().getString("publicPath") == null) { + this.libraryItemPage = new LibraryItemPage(); + } else { + this.title = getArguments().getString("title"); + this.parentId = getArguments().getString("publicPath"); + } + } else { + logger.debug("LibraryTopFragment", "getArguments() is null(maybe root)"); + this.libraryItemPage = new LibraryItemPage(); + } + // Toolbar Setup + toolbarSetup(view.findViewById(R.id.library_toolbar), this.folderId != null, this.title != null ? this.title : "ライブラリ"); + + // RecyclerView Setup + + RecyclerView recyclerView = view.findViewById(R.id.library_item_recycler_view); this.listItemAdapter = new ListItemAdapter(new DocumentSelectListener() { @Override public void onFolderSelected(String folderId, String folderName) { logger.debug("LibraryTopFragment", "Folder selected! folderId: " + folderId + ", folderName: " + folderName); - // 画面遷移 - FragmentNavigation fragmentNavigation = (FragmentNavigation) getActivity(); - assert fragmentNavigation != null; - fragmentNavigation.navigateToFragment(LibraryPageFragment.newInstance(folderId)); +// // 画面遷移 +// FragmentNavigation fragmentNavigation = (FragmentNavigation) getActivity(); +// // folderId: 推移先で表示するフォルダのID, folderName: 推移先で表示するフォルダの名前, parentId: このフラグメントで表示しているフォルダのID(推移先の親) +// fragmentNavigation.navigateToFragment(LibraryPageFragment.newInstance(folderId, folderName, libraryItemPage != null ? libraryItemPage.getParentId() : null), false); + Bundle bundle = new Bundle(); + bundle.putString("folderId", folderId); + bundle.putString("title", folderName); + bundle.putString("publicPath", libraryItemPage != null ? libraryItemPage.getParentId() : null); + try { + Navigation.findNavController(requireView()).navigate(R.id.action_feature_library_top_fragment_self, bundle); + } catch (IllegalStateException e) { + logger.error("LibraryTopFragment", "IllegalStateException: " + e.getMessage()); + } } @Override @@ -101,86 +181,103 @@ public class LibraryPageFragment extends Fragment { Toast.makeText(getContext(), "Document selected! documentId: " + documentId + ", documentName: " + documentName, Toast.LENGTH_SHORT).show(); } }); + recyclerView.setAdapter(listItemAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - if (getArguments() != null) { - this.folderId = getArguments().getString("folderId"); - } + // Get library page and update RecyclerView items + lacertaLibrary.getLibraryPage(this.folderId, 10).thenAccept(libraryItemPage -> { + this.libraryItemPage = libraryItemPage; - if (this.folderId == null) { // Root - lacertaLibrary.getLibraryPage(10).thenAccept(libraryItemPage -> { - logger.debug("LibraryTopFragment", "Item selected! libraryItemPage.getListItems().size(): " + libraryItemPage.getListItems().size()); - listItemAdapter.setLibraryItemPage(libraryItemPage); - getActivity().runOnUiThread(() -> { - // ActionBarのタイトルを変更する - getActivity().setTitle("ライブラリ"); - // ActionBarに戻るボタンを非表示にする -// getActivity().getActionBar().setDisplayHomeAsUpEnabled(false); - listItemAdapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size() - 1); - }); - this.currentTotalItemCount = libraryItemPage.getListItems().size(); + if (this.parentId == null) { + this.parentId = libraryItemPage.getParentId(); + } + if (this.title == null) { + this.title = libraryItemPage.getPageTitle(); + // Toolbar init again + toolbarSetup(view.findViewById(R.id.library_toolbar), this.folderId != null, this.title != null ? this.title : "ライブラリ"); + } + + logger.debug("LibraryTopFragment", "Item selected! Total item page: " + this.libraryItemPage.getListItems().size()); + getActivity().runOnUiThread(() -> { // TODO-rca: 実行条件を考える? + listItemAdapter.notifyItemRangeRemoved(0, this.libraryItemPage.getListItems().size() - 1); }); - } else { // Root以外 - lacertaLibrary.getLibraryPage(this.folderId, 10).thenAccept(libraryItemPage -> { - logger.debug("LibraryTopFragment", "Item selected! libraryItemPage.getListItems().size(): " + libraryItemPage.getListItems().size()); - listItemAdapter.setLibraryItemPage(libraryItemPage); - getActivity().runOnUiThread(() -> { - // ActionBarのタイトルを変更する - getActivity().setTitle(libraryItemPage.getPageTitle()); - // ActionBarに戻るボタンを表示する -// getActivity().getActionBar().setDisplayHomeAsUpEnabled(true); - listItemAdapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size() - 1); - }); - this.currentTotalItemCount = libraryItemPage.getListItems().size(); + listItemAdapter.setLibraryItemPage(this.libraryItemPage); + getActivity().runOnUiThread(() -> { + listItemAdapter.notifyItemRangeInserted(0, this.libraryItemPage.getListItems().size() - 1); }); - } + }); } - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.dir_menu, menu); - super.onCreateOptionsMenu(menu, inflater); - } - - // Selected - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.menu_item_create_new_folder) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle("フォルダの作成"); - builder.setMessage("フォルダ名を入力してください"); - final android.widget.EditText input = new android.widget.EditText(getContext()); - input.setText("フォルダ名"); - builder.setView(input); - builder.setPositiveButton("作成", (dialog, which) -> { - lacertaLibrary.createFolder(null, input.getText().toString()).thenAccept(folderId -> { - logger.debug("LibraryTopFragment", "folderId: " + folderId); - }); + /** + * Currentにフォルダを作成する + */ + private void createFolder(String pageId) { + // TODO-rca: デザインをMaterial Design 3に合わせたカスタムダイアログにする + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle("フォルダの作成"); + builder.setMessage("フォルダ名を入力してください"); + final android.widget.EditText input = new android.widget.EditText(getContext()); + input.setText("フォルダ名"); + builder.setView(input); + builder.setPositiveButton("作成", (dialog, which) -> { + lacertaLibrary.createFolder(pageId, input.getText().toString()).thenAccept(folderId -> { // Refresh - updateItem(); + updateItem(pageId); }); - builder.setNegativeButton("キャンセル", (dialog, which) -> { - dialog.cancel(); - }); - builder.show(); - return true; - } else { - return super.onOptionsItemSelected(item); - } + }); + builder.setNegativeButton("キャンセル", (dialog, which) -> { + dialog.cancel(); + }); + builder.show(); } - private void updateItem() { - lacertaLibrary.getLibraryPage(10).thenAccept(libraryItemPage -> { + /** + * RecyclerViewのアイテムを更新する + */ + private void updateItem(String pageId) { + lacertaLibrary.getLibraryPage(pageId, 10).thenAccept(libraryItemPage -> { + this.libraryItemPage = libraryItemPage; logger.debug("LibraryTopFragment", "Item selected! libraryItemPage.getListItems().size(): " + libraryItemPage.getListItems().size()); getActivity().runOnUiThread(() -> { - listItemAdapter.notifyItemRangeRemoved(0, this.currentTotalItemCount - 1); + listItemAdapter.notifyItemRangeRemoved(0, libraryItemPage.getListItems().size() - 1); }); listItemAdapter.setLibraryItemPage(libraryItemPage); getActivity().runOnUiThread(() -> { listItemAdapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size() - 1); }); - this.currentTotalItemCount = libraryItemPage.getListItems().size(); + }); + } + + /** + * ToolbarをInitする + * + * @param toolbar Toolbar + * @param showBackButton 戻るボタンを表示するか + * @param title タイトル + */ + private void toolbarSetup(Toolbar toolbar, boolean showBackButton, String title) { + getActivity().runOnUiThread(() -> { + if (showBackButton) { + toolbar.setNavigationIcon(one.nem.lacerta.shared.ui.R.drawable.arrow_back_24px); + toolbar.setNavigationOnClickListener(v -> { + //this.libraryItemPage = lacertaLibrary.getLibraryPage(this.libraryItemPage.getParentId(), 10).join(); + // Back + Navigation.findNavController(requireView()).popBackStack(); + }); + } else { + toolbar.setNavigationIcon(null); + } + toolbar.setTitle(title); + toolbar.inflateMenu(R.menu.dir_menu); + toolbar.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.menu_item_create_new_folder) { + createFolder(this.folderId); + return true; + } else { + return false; + } + }); }); } } diff --git a/feature/library/src/main/res/layout/fragment_library_top.xml b/feature/library/src/main/res/layout/fragment_library_top.xml index 06e32e35..f9d53d56 100644 --- a/feature/library/src/main/res/layout/fragment_library_top.xml +++ b/feature/library/src/main/res/layout/fragment_library_top.xml @@ -1,11 +1,50 @@ + android:layout_height="match_parent" + android:background="@color/colorSurface"> - + android:layout_height="match_parent"> + + + + + + + + + + + + + + \ 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 index 136b7b98..3a5dcd14 100644 --- a/feature/library/src/main/res/navigation/feature_library_navigation.xml +++ b/feature/library/src/main/res/navigation/feature_library_navigation.xml @@ -8,5 +8,15 @@ android:id="@+id/feature_library_top_fragment" android:name="one.nem.lacerta.feature.library.LibraryPageFragment" android:label="fragment_library_top" - tools:layout="@layout/fragment_library_top" /> + tools:layout="@layout/fragment_library_top" > + + \ No newline at end of file diff --git a/feature/setting/src/main/res/layout/fragment_setting_top.xml b/feature/setting/src/main/res/layout/fragment_setting_top.xml index 032d6463..ee8463ca 100644 --- a/feature/setting/src/main/res/layout/fragment_setting_top.xml +++ b/feature/setting/src/main/res/layout/fragment_setting_top.xml @@ -1,11 +1,50 @@ + android:layout_height="match_parent" + android:background="@color/colorSurface"> - + android:layout_height="match_parent"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/model/src/main/java/one/nem/lacerta/model/FragmentNavigation.java b/model/src/main/java/one/nem/lacerta/model/FragmentNavigation.java index f7cddea6..d9e4326c 100644 --- a/model/src/main/java/one/nem/lacerta/model/FragmentNavigation.java +++ b/model/src/main/java/one/nem/lacerta/model/FragmentNavigation.java @@ -4,4 +4,10 @@ import androidx.fragment.app.Fragment; public interface FragmentNavigation { void navigateToFragment(Fragment fragment); + + void navigateToFragment(Fragment fragment, boolean addToBackStack); + + void navigateToFragment(Fragment fragment, boolean addToBackStack, boolean clearBackStack); + + void navigateToFragmentAlternate(Fragment fragment, boolean addToBackStack); } diff --git a/model/src/main/java/one/nem/lacerta/model/LibraryItemPage.java b/model/src/main/java/one/nem/lacerta/model/LibraryItemPage.java index 825c2396..42933640 100644 --- a/model/src/main/java/one/nem/lacerta/model/LibraryItemPage.java +++ b/model/src/main/java/one/nem/lacerta/model/LibraryItemPage.java @@ -6,10 +6,18 @@ public class LibraryItemPage { String pageTitle; String pageId; + String parentId; ArrayList listItems; // Constructor + public LibraryItemPage(String pageTitle, String pageId, ArrayList listItems, String parentId) { + this.pageTitle = pageTitle; + this.pageId = pageId; + this.listItems = listItems; + this.parentId = parentId; + } + public LibraryItemPage(String pageTitle, String pageId, ArrayList listItems) { this.pageTitle = pageTitle; this.pageId = pageId; @@ -30,6 +38,10 @@ public class LibraryItemPage { return pageId; } + public String getParentId() { + return parentId; + } + public ArrayList getListItems() { return listItems; } @@ -44,6 +56,10 @@ public class LibraryItemPage { this.pageId = pageId; } + public void setParentId(String parentId) { + this.parentId = parentId; + } + public void setListItems(ArrayList listItems) { this.listItems = listItems; } diff --git a/model/src/main/java/one/nem/lacerta/model/PublicPath.java b/model/src/main/java/one/nem/lacerta/model/PublicPath.java index ccd902cb..d1639a7d 100644 --- a/model/src/main/java/one/nem/lacerta/model/PublicPath.java +++ b/model/src/main/java/one/nem/lacerta/model/PublicPath.java @@ -39,14 +39,19 @@ public class PublicPath { } public PublicPath parse(String path) { - if (path.startsWith("/")) { + if (path == null) { this.path.clear(); - path = path.substring(1); - } - String[] pathArray = path.split("/"); - for (String p : pathArray) { - Log.d("PublicPath", "parse: " + p); - resolveInternal(p); + this.path.add("/"); + } else { + if (path.startsWith("/")) { + this.path.clear(); + path = path.substring(1); + } + String[] pathArray = path.split("/"); + for (String p : pathArray) { + Log.d("PublicPath", "parse: " + p); + resolveInternal(p); + } } return this; } 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 index 2fc0f4bc..1093188e 100644 --- a/model/src/main/java/one/nem/lacerta/model/document/DocumentMeta.java +++ b/model/src/main/java/one/nem/lacerta/model/document/DocumentMeta.java @@ -37,7 +37,7 @@ public class DocumentMeta { // TODO-rca: JavaDoc対応 */ List tags; - PublicPath path; + String parentId; String author; @@ -54,7 +54,7 @@ public class DocumentMeta { // TODO-rca: JavaDoc対応 this.tags = new ArrayList<>(); this.author = ""; // TODO-rca: 作者のデフォルト値を設定できるようにする this.defaultBranch = "main"; // TODO-rca: デフォルトブランチのデフォルト値を設定できるようにする - this.path = new PublicPath().getRoot(); + this.parentId = null; this.updatedAt = new Date(); this.createdAt = new Date(); } @@ -85,13 +85,13 @@ public class DocumentMeta { // TODO-rca: JavaDoc対応 this.defaultBranch = defaultBranch; } - public DocumentMeta(String id, String title, Date updatedAt, Date createdAt, List tags, PublicPath path, String author, String defaultBranch) { + public DocumentMeta(String id, String title, Date updatedAt, Date createdAt, List tags, String parentId, String author, String defaultBranch) { this.id = id; this.title = title; this.updatedAt = updatedAt; this.createdAt = createdAt; this.tags = tags; - this.path = path; + this.parentId = parentId; this.author = author; this.defaultBranch = defaultBranch; } @@ -145,10 +145,10 @@ public class DocumentMeta { // TODO-rca: JavaDoc対応 } /** - * PublicPathを取得する + * ドキュメントの親フォルダのID(String)を取得する */ - public PublicPath getPath() { - return path; + public String getParentId() { + return parentId; } /** @@ -208,11 +208,11 @@ public class DocumentMeta { // TODO-rca: JavaDoc対応 } /** - * PublicPathを設定する - * @param path PublicPath + * ドキュメントの親フォルダのID(String)を設定する + * @param parentId ドキュメントの親フォルダのID */ - public void setPath(PublicPath path) { - this.path = path; + public void setParentId(String parentId) { + this.parentId = parentId; } /** 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 index 47e0e4bb..e3d6a6b9 100644 --- a/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabase.java +++ b/source/src/main/java/one/nem/lacerta/source/database/LacertaDatabase.java @@ -19,7 +19,7 @@ import one.nem.lacerta.source.database.dao.LibraryDao; import one.nem.lacerta.source.database.dao.VcsRevDao; import one.nem.lacerta.source.database.dao.VcsLogDao; -@Database(entities = {TagEntity.class, DocumentEntity.class, LibraryEntity.class, VcsRevEntity.class, VcsLogEntity.class, FolderEntity.class}, version = 4) +@Database(entities = {TagEntity.class, DocumentEntity.class, LibraryEntity.class, VcsRevEntity.class, VcsLogEntity.class, FolderEntity.class}, version = 5) public abstract class LacertaDatabase extends RoomDatabase { public abstract TagDao tagDao(); public abstract DocumentDao documentDao(); 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 index f5f1eb61..21e1cc2e 100644 --- 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 @@ -29,8 +29,11 @@ public interface DocumentDao { @Query("SELECT * FROM Document WHERE id IN (:ids)") List findByIds(List ids); - @Query("SELECT * FROM Document WHERE public_path = :publicPath LIMIT :limit") - List findByPublicPathWithLimit(String publicPath, int limit); + @Query("SELECT * FROM Document WHERE parent_id = :parentId") + List findByParentId(String parentId); + + @Query("SELECT * FROM Document WHERE parent_id IS NULL") + List findRootDocuments(); @Query("SELECT * FROM Document ORDER BY created_at DESC LIMIT :limit") List getRecentDocument(int limit); diff --git a/source/src/main/java/one/nem/lacerta/source/database/dao/FolderDao.java b/source/src/main/java/one/nem/lacerta/source/database/dao/FolderDao.java index 451854e5..404b53f8 100644 --- a/source/src/main/java/one/nem/lacerta/source/database/dao/FolderDao.java +++ b/source/src/main/java/one/nem/lacerta/source/database/dao/FolderDao.java @@ -15,11 +15,11 @@ public interface FolderDao { @Query("SELECT * FROM Folder WHERE id = :id") FolderEntity findById(String id); - @Query("SELECT * FROM Folder WHERE public_path = :publicPath") - FolderEntity findByPublicPath(String publicPath); + @Query("SELECT * FROM Folder WHERE parent_id = :parentId") + List findByParentId(String parentId); - @Query("SELECT * FROM Folder WHERE public_path = :publicPath LIMIT :limit") - List findByPublicPathWithLimit(String publicPath, int limit); + @Query("SELECT * FROM Folder WHERE parent_id IS NULL") + List findRootFolders(); @Insert void insert(FolderEntity folderEntity); 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 index 90a17b1d..2c4e03ab 100644 --- 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 @@ -40,6 +40,6 @@ public class DocumentEntity { @ColumnInfo(name = "tag_ids") public List tagIds; // タグ - @ColumnInfo(name = "public_path") - public String publicPath; // 公開パス + @ColumnInfo(name = "parent_id") + public String parentId; // 親フォルダID } diff --git a/source/src/main/java/one/nem/lacerta/source/database/entity/FolderEntity.java b/source/src/main/java/one/nem/lacerta/source/database/entity/FolderEntity.java index f3a9091d..8b745e39 100644 --- a/source/src/main/java/one/nem/lacerta/source/database/entity/FolderEntity.java +++ b/source/src/main/java/one/nem/lacerta/source/database/entity/FolderEntity.java @@ -16,7 +16,7 @@ public class FolderEntity { @ColumnInfo(name = "title") public String name; // フォルダ名 - @ColumnInfo(name = "public_path") - public String publicPath; // 公開パス + @ColumnInfo(name = "parent_id") + public String parentId; // 親フォルダID }