diff --git a/.gitignore b/.gitignore index f68d1099..0705add9 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ bin/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store +.idea/caches/ +out/ diff --git a/src/main/kotlin/ArchiveListScreen.kt b/src/main/kotlin/ArchiveListScreen.kt new file mode 100644 index 00000000..967e390b --- /dev/null +++ b/src/main/kotlin/ArchiveListScreen.kt @@ -0,0 +1,23 @@ +class ArchiveListScreen : Screen { + override fun show(repo: Repository, input: InputReader): NavCommand { + val items = mutableListOf() + items.add( + MenuItem("Создать архив") { + NavCommand.Push(CreateArchiveScreen()) + } + ) + repo.archives.forEach { archive -> + items.add( + MenuItem(archive.name) { + NavCommand.Push(NoteListScreen(archive)) + } + ) + } + items.add( + MenuItem("Выход") { + NavCommand.Exit + } + ) + return Menu("Список архивов:", items, input).run() + } +} \ No newline at end of file diff --git a/src/main/kotlin/CreateArchiveScreen.kt b/src/main/kotlin/CreateArchiveScreen.kt new file mode 100644 index 00000000..c31555c8 --- /dev/null +++ b/src/main/kotlin/CreateArchiveScreen.kt @@ -0,0 +1,19 @@ +class CreateArchiveScreen : Screen { + override fun show(repo: Repository, input: InputReader): NavCommand { + println("Создание архива") + println("Введите название архива (0 — назад)") + + while (true) { + val name = input.readLine("Название: ").trim() + if (name == "0") return NavCommand.Pop + if (name.isBlank()) { + println("Название не может быть пустым. Попробуйте ещё раз.\n") + continue + } + repo.archives.add(Archive(name)) + println("Архив \"$name\" создан.\n") + return NavCommand.Pop + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/CreateNoteScreen.kt b/src/main/kotlin/CreateNoteScreen.kt new file mode 100644 index 00000000..65199bea --- /dev/null +++ b/src/main/kotlin/CreateNoteScreen.kt @@ -0,0 +1,32 @@ +class CreateNoteScreen(private val archive: Archive):Screen{ + override fun show(repo:Repository,input:InputReader):NavCommand{ + println("Создание заметки (архив: ${archive.name})") + println("Введите название заметки (0 — назад)") + val title: String + while (true){ + val t = input.readLine("Название: ").trim() + if (t=="0")return NavCommand.Pop + if(t.isBlank()){ + println("Название не может быть пустым. Попробуйте ещё раз.\n") + continue + } + title = t + break + } + println("\nВведите текст заметки (0 — назад)") + val content:String + while(true){ + val c = input.readLine("Текст: ") + if (c.trim()=="0") return NavCommand.Pop + if (c.isBlank()){ + println("Текст не может быть пустым. Попробуйте ещё раз.\n") + continue + } + content = c + break + } + archive.notes.add(Note(title,content)) + println("\nЗаметка \"$title\" создана.\n") + return NavCommand.Pop + } +} \ No newline at end of file diff --git a/src/main/kotlin/InputReader.kt b/src/main/kotlin/InputReader.kt new file mode 100644 index 00000000..846639fd --- /dev/null +++ b/src/main/kotlin/InputReader.kt @@ -0,0 +1,10 @@ +import java.util.Scanner + +class InputReader { + private val scanner = Scanner(System.`in`) +; + fun readLine(prompt: String? = null): String { + if (prompt != null) print(prompt) + return scanner.nextLine() + } +} diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index aade54c5..90c2915d 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,3 +1,7 @@ -fun main(args: Array) { - println("Hello World!") +fun main() { + val repo = Repository() + val input = InputReader() + val navigator = Navigator(repo,input) + + navigator.start(ArchiveListScreen()) } \ No newline at end of file diff --git a/src/main/kotlin/Menu.kt b/src/main/kotlin/Menu.kt new file mode 100644 index 00000000..6c60952e --- /dev/null +++ b/src/main/kotlin/Menu.kt @@ -0,0 +1,34 @@ +data class MenuItem( + val title: String, + val action: () -> NavCommand +) + +class Menu( + private val header: String, + private val items: List, + private val input: InputReader +) { + fun run(): NavCommand { + while (true) { + if (header.isNotBlank()) println(header) + items.forEachIndexed { index, item -> + println("$index.${item.title}") + } + val raw = input.readLine("Выберите пункт:").trim() + val choice = raw.toIntOrNull() + + if (choice == null) { + println("Нужно ввести цифру. Попробуйте еще раз.\n") + continue + } + if (choice !in items.indices) { + println("Нет пункта с номером $choice. Попробуйте ещё раз.\n") + continue + } + + println() + return items[choice].action() + + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/Models.kt b/src/main/kotlin/Models.kt new file mode 100644 index 00000000..c8fd7bd0 --- /dev/null +++ b/src/main/kotlin/Models.kt @@ -0,0 +1,9 @@ +class Note( + val title: String, + val content: String +) + +class Archive( + val name: String, + val notes: MutableList = mutableListOf() +) \ No newline at end of file diff --git a/src/main/kotlin/Navigation.kt b/src/main/kotlin/Navigation.kt new file mode 100644 index 00000000..56bf39d7 --- /dev/null +++ b/src/main/kotlin/Navigation.kt @@ -0,0 +1,36 @@ +interface Screen { + fun show(repo: Repository, input: InputReader): NavCommand +} + +sealed class NavCommand { + data class Push(val screen: Screen) : NavCommand() + object Pop : NavCommand() + object Exit : NavCommand() + object Stay : NavCommand() +} + +class Navigator( + private val repo: Repository, + private val input: InputReader +) { + private val stack: MutableList = mutableListOf() + + fun start(root: Screen) { + stack.add(root) + + while (stack.isNotEmpty()) { + val current = stack.last() + + when (val cmd = current.show(repo, input)) { + is NavCommand.Push -> stack.add(cmd.screen) + + NavCommand.Pop -> { + if (stack.size > 1) stack.removeAt(stack.lastIndex) else return + } + + NavCommand.Exit -> return + NavCommand.Stay -> { } + } + } + } +} diff --git a/src/main/kotlin/NoteListScreen.kt b/src/main/kotlin/NoteListScreen.kt new file mode 100644 index 00000000..b01a11b7 --- /dev/null +++ b/src/main/kotlin/NoteListScreen.kt @@ -0,0 +1,27 @@ +class NoteListScreen(private val archive: Archive) : Screen { + override fun show(repo: Repository, input: InputReader): NavCommand { + val items = mutableListOf() + + items.add( + MenuItem("Создать заметку") { + NavCommand.Push(CreateNoteScreen(archive)) + } + ) + + archive.notes.forEach { note -> + items.add( + MenuItem(note.title) { + NavCommand.Push(NoteViewScreen(note)) + } + ) + } + + items.add( + MenuItem("Назад") { + NavCommand.Pop + } + ) + + return Menu("Архив: ${archive.name}\nСписок заметок:", items, input).run() + } +} diff --git a/src/main/kotlin/NoteViewScreen.kt b/src/main/kotlin/NoteViewScreen.kt new file mode 100644 index 00000000..611abde7 --- /dev/null +++ b/src/main/kotlin/NoteViewScreen.kt @@ -0,0 +1,14 @@ +class NoteViewScreen(private val note: Note) : Screen { + override fun show(repo: Repository, input: InputReader): NavCommand { + println("Заметка: ${note.title}") + println("------------") + println(note.content) + println("------------\n") + + val items = listOf( + MenuItem("Назад") { NavCommand.Pop } + ) + + return Menu("", items, input).run() + } +} \ No newline at end of file diff --git a/src/main/kotlin/Repository.kt b/src/main/kotlin/Repository.kt new file mode 100644 index 00000000..fe27a6e1 --- /dev/null +++ b/src/main/kotlin/Repository.kt @@ -0,0 +1,3 @@ +class Repository( + val archives: MutableList = mutableListOf() +) \ No newline at end of file