Compare commits

...

4 Commits
main ... Lab3

Author SHA1 Message Date
m.zargarov
93752973fc Готово 2023-12-05 23:51:25 +04:00
48d46fe9ba Лаб.3 2023-11-22 09:03:51 +04:00
9c97d63586 Папка с текстами 2023-11-21 12:21:06 +04:00
7aa7a2ffd9 Сделано 2023-11-21 12:06:54 +04:00
25 changed files with 1042 additions and 25 deletions

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\Marat\.android\avd\Pixel_5_API_30.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-12-05T17:47:31.084874500Z" />
</component>
</project>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.10" />
<option name="version" value="1.8.20" />
</component>
</project>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View File

@ -1,11 +1,12 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
}
android {
namespace = "com.example.shortbooks"
compileSdk = 33
compileSdk = 34
defaultConfig {
applicationId = "com.example.shortbooks"
@ -30,17 +31,17 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "17"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
kotlinCompilerExtensionVersion = "1.4.5"
}
packaging {
resources {
@ -48,17 +49,33 @@ android {
}
}
}
kotlin {
jvmToolchain(17)
}
dependencies {
//Core
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.8.1")
//UI
implementation("androidx.activity:activity-compose:1.7.2")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.navigation:navigation-compose:2.6.0")
implementation("io.coil-kt:coil-compose:2.4.0")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
// Room
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
//Tests
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

View File

@ -0,0 +1,125 @@
Часть I
Глава первая. Вместо введения: несколько подробностей из биографии многочтимого Степана Трофимовича Верховенского
События излагаются от лица некоего Г-ва — участника описываемых событий. Он начинает повествование с рассказа о судьбе Степана Трофимовича Верховенского, дважды вдовца. Он жил в соседстве с Варварой Николаевной Ставрогиной, знатной петербургской дамой, чьим покровительством пользовался, испытывая при этом сложные чувства к ней: «Один другого съесть хотят, всю жизнь так живут, а расстаться не могут».
Варвара Петровна даже придумала ему костюм, в котором он ходил постоянно. Это были длиннополый сюртук и мягкая шляпа, делавшие его похожим на писателя Кукольника. И Степан Трофимович пробовал «писать», но за долгие десять с лишним лет так ничего и не написал. Порой мучился мыслью, что он простой приживал, но потом утешался, пил шампанское и играл в карты.
Глава вторая. Принц Гарри. Сватовство
События получают свое развитие после возвращения домой единственного сына Варвары Петровны Николая Всеволодовича Ставрогина. Когда-то он был воспитанником Сергея Трофимовича, тихим и застенчивым подростком. Но поступив на военную службу в гвардейский полк, «вдруг закутил»: пил, играл в карты, стрелялся на дуэли, за что был разжалован в рядовые, но выслужился.
Вернувшись в родной город, произвел сначала весьма приятное впечатление: «это был самый изящный джентльмен». Но вскоре «зверь выпустил когти»: сказал невозможные дерзости старейшим членам клуба, протянул по залу за нос почтеннейшего старшину клуба, прилюдно поцеловал чужую жену, укусил за ухо Ивана Осиповича.
Все объяснилось якобы белой горячкой, от которой Nikolas лечился два с половиной месяца, после чего отбыл за границу.
Глава третья. Чужие грехи
Варвара Петровна обеспокоена вниманием сына к своей воспитаннице Дарье Шатовой, поэтому предложила Верховенскому свататься к девушке. Он старше на тридцать с лишним лет, но согласился, так как устал от роли приживала. Он готов сделать предложение.
В это время рассказчик Г-в принимал активное участие в жизни своего друга в роли конфидента. Он выслушал исповедь Верховенского, который жаловался, что долгое время страдал от своих чувств к Ставрогиной, от ее несправедливого отношения, а теперь вынужден брать на себя «чужие грехи».
Появился инженер Липутин, знавший и Петрушу Верховенского, и Николая Ставрогина. Он намекнул, что сватовство к Даше — попытка «замазать свадьбой дворянские грешки ее бесценного Nicolas».
Внезапно появилась бывшая воспитанница Степана Трофимовича Лизавета Николаевна Тушина. Она просила Г-ва передать записку Шатову, брату Дарьи Павловны. А от Варвары Петровны пришло письмо, в котором она извещала, что в воскресенье Степан Трофимович должен сделать предложение Даше.
Глава четвертая. Хромоножка
Лиза предложила Шатову издавать книгу, собранную из газетных новостей разных лет, чтобы оставить в памяти у читателей самые интересные новости. Но он, узнав о том, что капитан Лебядкин посвятил ей стихи и по сути сделал предложение, отказался от этой идеи.
Сергей Трофимович ждал с обедни Варвару Петровну, очень волнуясь перед предстоящим сватовством. К Шатову явился пьяный Лебядкин и стал через дверь кричать, что они с сестрой оба крепостные рабы. Ставрогина шла из церкви, когда у нее попросила милостыню Марья Лебядкина, прозванная Хромоножкой. Она просила поцеловать ручку, хихикая, как ребенок. Варвара Петровна накануне получила анонимное письмо, в котором говорилось, что в ее судьбе сыграет важную роль хромая женщина. Она пригласила Марью вместе с Лизой Тушиной к себе домой.
Глава пятая. Премудрый змий
Марья вела себя странно: хихикала, называла Ставрогину «тетенькой» и приятельски обращалась к Шатову, вызвав недоумение окружающих. Варваре Петровне объяснили, что это сестра капитана Лебядкина. Появилась Даша, и Лебядкина обвинила ее в том, что она в Швейцарии получила от Ставрогина 300 рублей, но ее брату не передала.
Варвара Петровна хотела отправить нахалку домой, но Степан Трофимович привел Лебядкина, который объяснил, что сестра не в своем уме. Сам же он начал говорить намеками и аллегориями, вызвав гнев Варвары Петровны, но как гром среди ясного неба прозвучали слова о приезде Николая, ее сына. Сначала появился Петр Верховенский, а вслед за ним и Ставрогин.
Мать прямо спросила сына, кем приходится ему Лебядкина. Николай увел Хромоножку под ручку к карете, а Петр все присутствующим объяснил, что Ставрогин помогал брату и сестре Лебядкиным, так как они жили в нищете, а Марья всем говорила, что это ее жених, о чем и уведомили «доброжелатели» в анонимных письмах Варвару Петровну.
Мать была растрогана поступком сына и заявила, что должна удочерить эту девушку. Она попросила прощения у вернувшегося сына, но Лиза закатила истерику, несмотря на то, что капитан Лебядкин подтвердил весь рассказ Верховенского. А после того, как Шатов дал Ставрогину пощечину, она упала в обморок.
Часть II
Глава первая. Ночь
Прошло восемь дней. По городу пошли слухи про Лизу и Ставрогина. Последний провел все дни затворником. После к Николаю явился Петр Верховенский. Он сообщил, что прибыли вещи Ставрогина из Петербурга, а попутно рассказал о заседании тайного общества, куда они должны явиться вместе.
Ставрогин отправился к инженеру Кириллову, чтобы просить стать его секундантом в дуэли, где ему придется стреляться с неким Гагановым, который публично его оскорбил. Кириллов показал ему несколько пистолетов и объяснил, что хотел застрелиться, чтобы избавиться от Бога — он есть лишь «боль страха смерти». Если убить себя, заявив своеволие, можно стать человекобогом.
Придя к Шатову, Ставрогин признался, что женился на Лебядкиной в Петербурге «по пьянке» и скоро об этом объявит. А еще он предупредил, что Шатова могут убить в любую минуту за его идею о народе-богоборце. И хотя сам Шатов не верил в Бога, зато посоветовал бросить богатство и жить мужицким трудом.
Глава вторая. Ночь (продолжение)
В ту же ночь Ставрогин по дороге к Лебядкину встретил Федьку Каторжного, которого подослал Верховенский. Федор был готов за плату исполнить любую волю «барина», но Ставрогин прогнал его.
Лебядкин встретил Николая трезвым, но все время ерничал и делал туманные намеки на то, что он готов и дальше хранить тайну их брака за некую сумму. Однако Ставрогин заявил, что больше не намерен держать в тайне, что женился на Марье Тимофеевне «после пьяного обеда, из-за пари на вино».
Николай вошел в комнату к сестре капитана, та спала, а проснувшись, повела себя как испугавшийся ребенок. Ставрогин предложил уехать с ним в Швейцарию, где они будут жить уединенно всю оставшуюся жизнь. Тогда Марья рассказала о своем нехорошем сне и заявила, что Ставрогин — это не ее муж, князь, что он самозванец, Гришка Отрепьев, у которого нож в кармане.
На обратном пути Федька предложил устранить проблему с Лебядкиными. Ставрогин захохотал и бросил ему все деньги, какие были, прямо в грязь.
Глава третья. Поединок
На следующий день произошла дуэль Ставрогина с Гагановым. Противникам было предложено примирение, но Гаганов настаивал на поединке. Он даже поставил условие: если не произойдет ничего решительного, то стреляться три раза. Первым стрелял он, и пуля задела мизинец Ставрогина. Но он выстрелил в воздух. Оба следующие раза Гаганов промахивался, а Ставрогин не целясь стрелял мимо, чем еще больше оскорбил противника.
Дома они объяснились с Дашей: Николай просил больше не приходить к нему, ведь он не хотел ее погубить. А Даша заявила, что рано или поздно именно она останется рядом с ним.
Глава четвертая. Все в ожидании
История с дуэлью в глазах общества подняла Ставрогина на небывалую высоту — он был в моде. А к Варваре Петровне стали относиться с прежним почтением. Ей только не давала покоя мысль о Хромоножке. Петр же Верховенский отнесся к поединку «с чрезвычайной злобой»: он сказал Ставрогину, что тот не имел права стреляться.
Придя к отцу, Верховенский передал слова Варвары Петровны, что она оскорблена его жалобами на то, что его хотят женить на «чужих грехах». Поэтому она назначила ему пенсион и объявила о разрыве. Степан Трофимович был потрясен отношением сына к этой истории, проклинал его, а сын пообещал больше никогда в жизни не приходить, хотя сам вызвал этот скандал.
Глава пятая. Пред праздником
Петр Степанович стал оказывать большое влияние на местного губернатора Андрея Антоновича фон Лембке и его жену Юлию Михайловну. Она собралась проводить праздник по подписке в пользу гувернанток губернии. А в городе бесчинства: осквернена икона, найден юноша-самоубийца. В губернии тоже неспокойно: везде пожары (явные поджоги), свирепствует холера, закрыта фабрика Шпигулиных, что вызывает недовольство рабочих. Ко всему прочему появились призывающие к бунту прокламации.
Варвара Петровна встретилась с Верховенским-старшим лично, чтобы наконец объясниться. Она упрекала его в неблагодарности, в том, что он только и ждал момента оклеветать ее, а Степан Трофимович прослезился, что двадцать лет жил только в мечтах, как рыцарь.
Глава шестая. Петр Степанович в хлопотах
Сын Верховенского в это время развернул бурную деятельность. Он на посылках у жены губернатора, которая не слишком верила в своего мужа, зато мечтала с помощью Петруши раскрыть государственный заговор. Тот не заставил себя долго ждать и выдал губернатору имена Шитова и Кириллова, связанных с появлением революционных прокламаций. Затем он посетил обоих с просьбой обязательно быть на собрании.
А к Ставрогину пришел Маврикий Николаевич, жених Лизы Тушиной. Он чувствовал, что Лиза любит Ставрогина, хотя и ненавидит его при этом. Он предложил Николаю жениться на ней, но Ставрогин признался, что уже женат, повергнув собеседника в шок. После этого он вместе с Петром ушел на тайное собрание.
Глава седьмая. У наших
Собрались у Виргинских под видом празднования именин. Петр уже успел слепить «пятерку», подобную той, которую он создал в Москве. Заседание начала студентка, но инициативу перехватил некто Шигалев с собственной программой «конечного разрешения вопроса». Суть теории заключалась в разделении человечества на две части: меньшая, одна десятая, получает свободу вместе с безграничным правом управлять большей — девятью десятыми, превращенными в стадо.
Петр Степанович задал провокационный вопрос: если бы участники собрания узнали о намечающемся убийстве, донесли бы он в полицию. Присутствующие стали выкрикивать, что не донесут. Неожиданно для всех Шатов встал и называл Верховенского шпионом и подлецом, а потом ушел. Когда дошла очередь до Ставрогина, он сказал, что не собирается себя компрометировать и вместе с Кирилловым удалился.
Глава восьмая. Иван-царевич
Верховенский уже наметил Шатова в жертву, чтобы скрепить кровью созданную им революционную «пятерку». Ставрогин сказал, что Петру хочется связать его преступлением, чтобы получить власть над ним. Когда тот схватил Ставрогина за локоть, он вырвал локоть, бешенство овладело им, и он бросил его из всей силы на землю. Но Верховенский догнал его и предложил помириться, чтобы вместе «сделать смуту». В горячечном бреду он признался, что Ставрогин именно таков, каков нужен сейчас России. Когда начнется смута, пойдет «раскачка», земля заплачет по старым богам, и тогда Ставрогин и должен будет появиться в роли Ивана-царевича, очередного самозванца, спасшегося чудесным образом. Потом он обещал даже без денег убить Лебядкину, а Ставрогину привести Лизу.
Глава девятая. Степана Трофимовича описали
К Г-ву прибежала Настасья с известием, что Степана Трофимовича «описали». Когда рассказчик пришел к нему, тот сказал, что утром у него изъяли сочинения Герцена и две прокламации. Степан Трофимович признался: он боится, что его «посадят в кибитку, и марш в Сибирь на весь век», а перед этим высекут. Но собрав остатки гордости, он заявил, что придет прямо к Лембке на праздник — он предает себя, идет «прямо в львиную пасть».
Глава десятая. Флибустьеры. Роковое утро
К губернатору фон Лембке пришли рабочие с фабрики Шпигулина. Он воспринял это как проявление бунта. Получил и случайно попавший под руку Степан Трофимович, который пытался объясниться. Собравшиеся у Юлии Михайловны стали свидетелями как минимум двух скандалов.
Юлия Михайловна, узнав, как обошелся со Степаном Трофимовичем ее муж, мстила ему, кокетничая с Верховенским-старшим. Разговоры в салоне о социализме и игнорирование супруги взбесили Андрея Антоновича. Он объявил, что меры к «флибустьерам» приняты.
А Лизавета Николаевна намеренно громким голосом попросила Ставрогина, чтобы он запретил своему родственнику, брату жены капитану Лебядкину, обижать ее. Тот публично признал, что он женат уже пять лет на Марье и обещал передать ее просьбу капитану. Затем он уехал в Скворешники.
Часть III
Глава первая. Праздник. Отдел первый
На другой день праздник все-таки состоялся. Лиза явилась в пышном туалете и была так ослепительно прелестна, что все вокруг шептались. Когда появились губернатор с женой, рассказчик заметил на лице Антона Андреевича такое выражение, будто он приносит себя в жертву.
В первой части праздника известный писатель Кармазинов читал свое сочинение «Merci», посвященное идеям нигилизма. Степан Тимофеевич страстно защищал от этих самых нигилистов Шекспира и Рафаэля, но не нашел понимания у публики, которая его освистала.
Глава вторая. Окончание праздника
Г-в отправился к Степану Трофимовичу, но тот заперся и никого не принимал. Он написал прощальное письмо к Дарье Шатовой, в котором просил простить за все то плохое, что было связано с его именем. На улице Г — в узнает о том, что Лиза села в карету к Верховенскому, который увез ее к Ставрогину.
Бал у предводителя дворянства в самом разгаре. Уже под утро представили аллегорическую «кадриль литературы», вызвавшую у всех присутствующих возмущение. В это время сообщили о пожаре в Заречье и убийстве капитана Лебядкина и его сестры. Губернатор поехал на пожар и в припадке безумия бросился спасать, но на него упала доска, и он от удара свалился без чувств на землю.
Глава третья. Законченный роман
Утром Ставрогин и Лиза, которые провели вместе ночь, объяснились. Ставрогин позвал ее с собой в Швейцарию, но она оказалась, так как Николай женат. Он спросил, зачем же она пришла, и Лиза сказала, что это лишь ее фантазия. Появился Верховенский и рассказал о пожаре и гибели Лебядкиных, а Ставрогин сознался, что знал о готовящемся убийстве, но не предотвратил.
Лиза в истерике бежит к пепелищу, падает, ее поднимает Маврикий Николаевич, который караулил всю ночь возле дома Ставрогина. Он попросил не прогонять его, они пошли дальше рука об руку и встретили Степана Трофимовича, который навсегда покидал город, чтобы «искать Россию». Лиза его перекрестила и просила молиться за «бедную Лизу». Когда она подошла к месту пожарища, ее узнали как «ставрогинскую». Все уверены, что убийца Ставрогин, а она с ним заодно. Она получила удары из толпы, упала и потеряла сознание.
Глава четвертая. Последнее решение
В городе потрясены гибелью Лизы и уходом Степана Трофимовича. Его сын собрал свою «пятерку» и убедил, что Шатов готовит на них донос. Он пришел к Кириллову, чтобы припомнить ему договоренность о том, что тот, прежде чем покончить с собой, должен взять на себя чужую кровь. Там он застал Федьку Каторжного. Петр в гневе: как тот посмел здесь появиться. Федьке удалось сбежать, но Петруша заявил: Каторжный последний раз в жизни пил водку.
Утром становится известно, что Федор найден в семи верстах от города с разбитой головой. Этот факт всех участников пятерки убедил во всемогуществе Верховенского, и его никто больше не смел ослушаться.
Глава пятая. Путешественница
К Шатову приехала жена, бросившая его три года назад. Она попросила временного пристанища, и почти сразу у нее начались роды. После рождения ребенка он решил его усыновить и начать новую трудовую жизнь, но перед этим «развязаться» с прежней. Вечером вместе с офицером Эркелем он пришел в парк, где его уже поджидала вся «пятерка».
Глава шестая. Многотрудная ночь
Шатова схватили, Верховенский выстрелил прямо в лоб, после чего к телу привязали два больших камня и бросили в пруд. Верховенский добился, чтобы Кириллов выполнил свое обещание: тот написал записку, где взял вину за убийство на себя, а потом застрелился. Петр собрал вещи и уехал в Петербург, а оттуда за границу.
Глава седьмая. Последнее странствование Степана Трофимовича
Степан Тимофеевич, отправившийся в свое последнее странствие, умер в крестьянской избе. В дороге он познакомился с книгоношей Софьей Михайловной, которой и рассказал о своей жизни, словно бы исповедовавшись.
Она выслушала его участливо, а ночью у него случился припадок. Стараясь его успокоить, она стала читать ему Евангелие, но у него начался и бред, и через несколько дней он умер на руках у Варвары Петровны, приехавшей по зову хозяев.
Глава восьмая. Заключение
Все участники убийства Шатова, кроме Верховенского, были выданы Лямшиным и арестованы. Его сестра получила письмо-исповедь Ставрогина, который признался: из него «вылилось одно отрицание, без всякого великодушия и безо всякой силы». В письме он звал девушку в Швейцарию, где «записался в граждане кантона Ури», чтобы остаться там с ней навечно. Даша дала прочесть письмо своей покровительнице, но тут сообщили, что Ставрогин неожиданно объявился в Скворешниках. Они поспешили туда и обнаружили в мезонине повесившегося Николая.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,15 +1,16 @@
package com.example.shortbooks
import android.content.res.Configuration
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.shortbooks.navigation.MainNavbar
import com.example.shortbooks.ui.theme.ShortBooksTheme
class MainActivity : ComponentActivity() {
@ -17,30 +18,26 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
setContent {
ShortBooksTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
MainNavbar()
}
}
}
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
fun MainNavbarPreview() {
ShortBooksTheme {
Greeting("Android")
Surface(
color = MaterialTheme.colorScheme.background
) {
MainNavbar()
}
}
}

View File

@ -0,0 +1,128 @@
package com.example.shortbooks.book.composeui
import android.content.res.AssetManager
import android.content.res.Configuration
import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.shortbooks.book.model.Book
import com.example.shortbooks.database.AppDatabase
import com.example.shortbooks.navigation.Screen
import com.example.shortbooks.ui.theme.ShortBooksTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun BookList(navController: NavController?) {
val context = LocalContext.current
val books = remember { mutableStateListOf<Book>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).bookDao().getAll().collect { data ->
books.clear()
books.addAll(data)
}
}
}
Column(
Modifier
.padding(all = 10.dp)
.padding(vertical = 30.dp)
.verticalScroll(rememberScrollState())
)
{
Text(text = "Книги", fontSize = 32.sp, modifier = Modifier.padding(all = 10.dp))
books.forEach { book ->
key(book.book_uid) {
val bookId = Screen.BookText.route.replace("{id}", book.book_uid.toString())
Card(
modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp)
.clickable { navController?.navigate(bookId) },
shape = RoundedCornerShape(10.dp),
) {
Box() {
Row(
verticalAlignment = Alignment.CenterVertically
) {
ImageConverse(imagePath = book.image)
Column {
Text("${book.name}", fontSize = 22.sp)
Text("${book.author}", fontSize = 18.sp)
}
}
}
}
}
}
}
}
@Composable
fun ImageConverse(imagePath: String) {
val context = LocalContext.current
val assetManager: AssetManager = context.assets
// Открываем поток данных для изображения в каталоге assets
val inputStream = assetManager.open(imagePath)
// Преобразуем поток данных в Bitmap
val bitmap = BitmapFactory.decodeStream(inputStream)
// Преобразуем Bitmap в ImageBitmap
val imageBitmap = bitmap.asImageBitmap()
// Создаем BitmapPainter из ImageBitmap
val painter = BitmapPainter(imageBitmap)
// Отображаем изображение с помощью Image и BitmapPainter
Image(
painter = painter,
contentDescription = "Image",
modifier = Modifier
.padding(all = 5.dp)
.size(64.dp)
.clip(RoundedCornerShape(10.dp))
)
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun BookListPreview() {
ShortBooksTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
BookList(navController = null)
}
}
}

View File

@ -0,0 +1,65 @@
package com.example.shortbooks.book.composeui
import android.content.res.AssetManager
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.example.shortbooks.book.model.Book
import com.example.shortbooks.database.AppDatabase
import com.example.shortbooks.ui.theme.ShortBooksTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BookText(id: Int) {
val context = LocalContext.current
val assetManager: AssetManager = context.assets
val (book, setBook) = remember { mutableStateOf<Book?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
setBook(AppDatabase.getInstance(context).bookDao().getByUid(id))
}
}
val textContent: String = if (book != null) {
assetManager.open(book.text).bufferedReader().use { it.readText() }
} else {
"Текст отсутствует"
}
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = textContent, modifier = Modifier.verticalScroll(rememberScrollState()))
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun BookTextPreview() {
ShortBooksTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
BookText(id = 1)
}
}
}

View File

@ -0,0 +1,26 @@
package com.example.shortbooks.book.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.shortbooks.book.model.Book
import kotlinx.coroutines.flow.Flow
@Dao
interface BookDao {
@Query("select * from books order by name collate nocase asc")
fun getAll(): Flow<List<Book>>
@Query("select * from books where books.book_uid = :uid")
suspend fun getByUid(uid: Int): Book
@Insert
suspend fun insert(user: Book)
@Update
suspend fun update(user: Book)
@Delete
suspend fun delete(user: Book)
}

View File

@ -0,0 +1,39 @@
package com.example.shortbooks.book.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
@Entity(tableName = "books")
data class Book(
@PrimaryKey(autoGenerate = true)
val book_uid: Int?,
val name: String,
val author: String,
@ColumnInfo(name="age_limit")
val ageLimit: Int,
val text: String,
val image: String
){
@Ignore
constructor(
name: String,
author: String,
ageLimit: Int,
text: String,
image: String
) : this(null, name,author,ageLimit,text,image)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Book
if (book_uid != other.book_uid) return false
return true
}
override fun hashCode(): Int {
return book_uid ?: -1
}
}

View File

@ -0,0 +1,93 @@
package com.example.shortbooks.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.shortbooks.book.dao.BookDao
import com.example.shortbooks.book.model.Book
import com.example.shortbooks.favorite.dao.UserBookDao
import com.example.shortbooks.favorite.model.UserBookCrossRef
import com.example.shortbooks.user.dao.UserDao
import com.example.shortbooks.user.model.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [User::class, Book::class, UserBookCrossRef::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun bookDao(): BookDao
abstract fun userBookDao(): UserBookDao
companion object {
private const val DB_NAME: String = "shortbooks-db"
@Volatile
private var INSTANCE: AppDatabase? = null
private suspend fun populateDatabase() {
INSTANCE?.let { database ->
// Books
val bookDao = database.bookDao()
val book1 = Book("Книга 1", "Автор 1", 18, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
val book2 = Book("Книга 2", "Автор 2", 12, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
val book3 = Book("Книга 3", "Автор 3", 12, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
val book4 = Book("Книга 4", "Автор 4", 12, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
val book5 = Book("Книга 5", "Автор 5", 12, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
val book6 = Book("Книга 6", "Автор 5", 12, "booktexts/dostoevskiy_besy.txt", "images/dostoevskiy_besy.jpg")
bookDao.insert(book1)
bookDao.insert(book2)
bookDao.insert(book3)
bookDao.insert(book4)
bookDao.insert(book5)
bookDao.insert(book6)
// Users
val userDao = database.userDao()
val user1= User("anatoliqw@gmail.com","anatol213","Анатолий", 47)
val user2= User("sergey1988@mail.ru","sergey123","Сергей", 35)
userDao.insert(user1)
userDao.insert(user2)
// Favorites
val userBookDao = database.userBookDao()
val userBook1= UserBookCrossRef(1,2)
val userBook2= UserBookCrossRef(1,3)
val userBook3= UserBookCrossRef(1,4)
val userBook4= UserBookCrossRef(2,1)
val userBook5= UserBookCrossRef(2,2)
val userBook6= UserBookCrossRef(2,4)
userBookDao.insert(userBook1)
userBookDao.insert(userBook2)
userBookDao.insert(userBook3)
userBookDao.insert(userBook4)
userBookDao.insert(userBook5)
userBookDao.insert(userBook6)
}
}
fun getInstance(appContext: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
AppDatabase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
populateDatabase()
}
}
})
.build()
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,124 @@
package com.example.shortbooks.favorite.composeui
import android.content.res.AssetManager
import android.content.res.Configuration
import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.shortbooks.database.AppDatabase
import com.example.shortbooks.favorite.model.UserWithBooks
import com.example.shortbooks.navigation.Screen
import com.example.shortbooks.ui.theme.ShortBooksTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun FavoriteList(navController: NavController?, uid: Int) {
val context = LocalContext.current
val (userBook, setUserBook) = remember { mutableStateOf<UserWithBooks?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
setUserBook(AppDatabase.getInstance(context).userBookDao().getByUid(uid))
}
}
Column(
Modifier
.padding(all = 10.dp)
.padding(vertical = 30.dp)
.verticalScroll(rememberScrollState())) {
Text(text = "Избранное", fontSize = 32.sp, modifier = Modifier.padding(all=10.dp))
userBook?.books?.forEach { book ->
key(book.book_uid) {
val book_uid = Screen.BookText.route.replace("{id}", book.book_uid.toString())
Card(
modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp)
.clickable { navController?.navigate(book_uid) },
shape = RoundedCornerShape(15.dp),
)
{
Box() {
Row(
verticalAlignment = Alignment.CenterVertically
) {
ImageConverse(imagePath = book.image)
Column {
Text("${book.name}", fontSize = 22.sp)
Text("${book.author}", fontSize = 18.sp)
}
}
}
}
}
}
}
}
@Composable
fun ImageConverse(imagePath: String, modifier: Modifier = Modifier) {
val context = LocalContext.current
val assetManager: AssetManager = context.assets
// Открываем поток данных для изображения в каталоге assets
val inputStream = assetManager.open(imagePath)
// Преобразуем поток данных в Bitmap
val bitmap = BitmapFactory.decodeStream(inputStream)
// Преобразуем Bitmap в ImageBitmap
val imageBitmap = bitmap.asImageBitmap()
// Создаем BitmapPainter из ImageBitmap
val painter = BitmapPainter(imageBitmap)
// Отображаем изображение с помощью Image и BitmapPainter
Image(
painter = painter,
contentDescription = "Image",
modifier = modifier
.padding(all = 5.dp)
.size(64.dp)
.clip(RoundedCornerShape(10.dp))
)
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun BookListPreview() {
ShortBooksTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
FavoriteList(navController = null,uid=1)
}
}
}

View File

@ -0,0 +1,30 @@
package com.example.shortbooks.favorite.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.example.shortbooks.book.model.Book
import kotlinx.coroutines.flow.Flow
import com.example.shortbooks.favorite.model.UserBookCrossRef
import com.example.shortbooks.favorite.model.UserWithBooks
@Dao
interface UserBookDao {
@Query("select * from user_books")
fun getAll(): Flow<List<UserBookCrossRef>>
@Query("select * from users where user_uid=:uid")
suspend fun getByUid(uid: Int): UserWithBooks
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(userBookCrossRef: UserBookCrossRef)
@Update
suspend fun update(userBookCrossRef: UserBookCrossRef)
@Delete
suspend fun delete(userBookCrossRef: UserBookCrossRef)
}

View File

@ -0,0 +1,18 @@
package com.example.shortbooks.favorite.model
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
import com.example.shortbooks.book.model.Book
import com.example.shortbooks.user.model.User
data class BookWithUsers (
@Embedded
val book: Book,
@Relation(
parentColumn = "book_uid",
entityColumn = "user_uid",
associateBy = Junction(UserBookCrossRef::class),
)
val users: List<User>
)

View File

@ -0,0 +1,11 @@
package com.example.shortbooks.favorite.model
import androidx.room.ColumnInfo
import androidx.room.Entity
@Entity(tableName = "user_books", primaryKeys = ["user_uid", "book_uid"])
data class UserBookCrossRef (
val user_uid: Int,
val book_uid: Int
)

View File

@ -0,0 +1,18 @@
package com.example.shortbooks.favorite.model
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
import com.example.shortbooks.book.model.Book
import com.example.shortbooks.user.model.User
data class UserWithBooks(
@Embedded
val user: User,
@Relation(
parentColumn = "user_uid",
entityColumn = "book_uid",
associateBy = Junction(UserBookCrossRef::class),
)
val books: List<Book>
)

View File

@ -0,0 +1,114 @@
package com.example.shortbooks.navigation
import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.example.shortbooks.book.composeui.BookList
import com.example.shortbooks.book.composeui.BookText
import com.example.shortbooks.favorite.composeui.FavoriteList
import com.example.shortbooks.ui.theme.ShortBooksTheme
import com.example.shortbooks.user.composeui.UserInfo
@Composable
fun Navbar(
navController: NavHostController,
currentDestination: NavDestination?,
modifier: Modifier = Modifier
) {
NavigationBar(modifier) {
Screen.bottomBarItems.forEach { screen ->
NavigationBarItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
@Composable
fun Navhost(
navController: NavHostController,
innerPadding: PaddingValues, modifier:
Modifier = Modifier
) {
NavHost(
navController,
startDestination = Screen.BookList.route,
modifier.padding(innerPadding)
) {
composable(Screen.BookList.route) { BookList(navController) }
composable(Screen.FavoriteList.route) { FavoriteList(navController,1) }
composable(Screen.UserInfo.route){ UserInfo(1)}
composable(
Screen.BookText.route,
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
backStackEntry.arguments?.let { BookText(it.getInt("id")) }
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainNavbar() {
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
Scaffold(
bottomBar = {
if (currentScreen == null || currentScreen.showInBottomBar) {
Navbar(navController, currentDestination)
}
}
) { innerPadding ->
Navhost(navController, innerPadding)
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun MainNavbarPreview() {
ShortBooksTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
MainNavbar()
}
}
}

View File

@ -0,0 +1,42 @@
package com.example.shortbooks.navigation
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountBox
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.List
import androidx.compose.ui.graphics.vector.ImageVector
import com.example.shortbooks.R
enum class Screen(
val route: String,
@StringRes val resourceId: Int,
val icon: ImageVector = Icons.Filled.Favorite,
val showInBottomBar: Boolean = true
) {
BookList(
"book-list", R.string.book_main_title, Icons.Filled.List
),
FavoriteList(
"favorite-list", R.string.favorite_main_title, Icons.Filled.Favorite
),
UserInfo(
"user-info", R.string.user_main_title, Icons.Filled.AccountBox
),
BookText(
"book-view/{id}",R.string.text_main_title,showInBottomBar = false
);
companion object {
val bottomBarItems = listOf(
BookList,
FavoriteList,
UserInfo
)
fun getItem(route: String): Screen? {
val findRoute = route.split("/").first()
return values().find { value -> value.route.startsWith(findRoute) }
}
}
}

View File

@ -0,0 +1,84 @@
package com.example.shortbooks.user.composeui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.shortbooks.R
import com.example.shortbooks.database.AppDatabase
import com.example.shortbooks.ui.theme.ShortBooksTheme
import com.example.shortbooks.user.model.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UserInfo(id: Int) {
val context = LocalContext.current
val (user, setUser) = remember { mutableStateOf<User?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
setUser(AppDatabase.getInstance(context).userDao().getByUid(id))
}
}
Column(
Modifier
.fillMaxWidth()
.padding(all = 20.dp,)
.padding(vertical = 30.dp)
) {
Text(text = "Профиль", fontSize=32.sp)
OutlinedTextField(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
value = user?.name ?: "", onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.user_name))
}
)
OutlinedTextField(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
value = user?.age.toString(), onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.user_age))
}
)
OutlinedTextField(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
value = user?.email ?: "", onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.user_email))
}
)
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun UserInfoPreview() {
ShortBooksTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
UserInfo(0)
}
}
}

View File

@ -0,0 +1,25 @@
package com.example.shortbooks.user.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.shortbooks.user.model.User
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Query("select * from users order by email collate nocase asc")
fun getAll(): Flow<List<User>>
@Query("select * from users where users.user_uid = :uid")
suspend fun getByUid(uid: Int): User
@Insert
suspend fun insert(user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
}

View File

@ -0,0 +1,36 @@
package com.example.shortbooks.user.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
@Entity(tableName="users")
data class User(
@PrimaryKey(autoGenerate = true)
val user_uid: Int?,
val email: String,
val password: String,
@ColumnInfo(name="user_name")
val name: String,
val age: Int
) {
@Ignore
constructor(
email:String,
password: String,
name: String,
age: Int
) : this(null, email,password,name,age)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as User
if (user_uid != other.user_uid) return false
return true
}
override fun hashCode(): Int {
return user_uid ?: -1
}
}

View File

@ -1,3 +1,10 @@
<resources>
<string name="app_name">ShortBooks</string>
<string name="book_main_title">Книги</string>
<string name="text_main_title">Текст</string>
<string name="favorite_main_title">Избранное</string>
<string name="user_main_title">Профиль</string>
<string name="user_name">Имя</string>
<string name="user_email">Email</string>
<string name="user_age">Возраст</string>
</resources>

View File

@ -1,5 +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.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
}