├── .github
└── FUNDING.yml
├── .gitignore
├── .idea
└── icon.png
├── CODE_OF_CONDUCT.md
├── README.md
├── app
├── .gitignore
├── benchmark-rules.pro
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── jobik
│ │ └── shkiper
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── jobik
│ │ │ └── shkiper
│ │ │ ├── NotepadApplication.kt
│ │ │ ├── SharedPreferencesKeys.kt
│ │ │ ├── activity
│ │ │ ├── MainActivity.kt
│ │ │ └── ShareReceiverActivity.kt
│ │ │ ├── crash
│ │ │ ├── CrashActivity.kt
│ │ │ └── GlobalExceptionHandler.kt
│ │ │ ├── database
│ │ │ ├── data
│ │ │ │ ├── note
│ │ │ │ │ ├── NoteMongoRepository.kt
│ │ │ │ │ └── NoteMongoRepositoryImpl.kt
│ │ │ │ └── reminder
│ │ │ │ │ ├── ReminderMongoRepository.kt
│ │ │ │ │ └── ReminderMongoRepositoryImpl.kt
│ │ │ ├── di
│ │ │ │ └── DatabaseModule.kt
│ │ │ └── models
│ │ │ │ ├── Note.kt
│ │ │ │ └── Reminder.kt
│ │ │ ├── helpers
│ │ │ ├── AppHelper.kt
│ │ │ ├── DateHelper.kt
│ │ │ ├── FileHelper.kt
│ │ │ ├── IntentHelper.kt
│ │ │ ├── LinkHelper.kt
│ │ │ ├── NumberHelper.kt
│ │ │ └── TextHelper.kt
│ │ │ ├── navigation
│ │ │ ├── NavigationAnimations.kt
│ │ │ ├── NavigationHelpers.kt
│ │ │ ├── RouteHelper.kt
│ │ │ ├── Screen.kt
│ │ │ └── SetupHomePageNavGraph.kt
│ │ │ ├── screens
│ │ │ ├── about
│ │ │ │ └── AboutNotepadScreen.kt
│ │ │ ├── advancedSettings
│ │ │ │ ├── AdvancedApplicationSettings.kt
│ │ │ │ ├── AdvancedNotificationSettings.kt
│ │ │ │ ├── AdvancedSecureSettings.kt
│ │ │ │ ├── AdvancedSettings.kt
│ │ │ │ └── AdvancedUpdatesSettings.kt
│ │ │ ├── calendar
│ │ │ │ ├── CalendarScreen.kt
│ │ │ │ ├── CalendarViewModel.kt
│ │ │ │ ├── FullScreenCalendar.kt
│ │ │ │ └── ScreenCalendarTopBar.kt
│ │ │ ├── layout
│ │ │ │ ├── AppLayout.kt
│ │ │ │ ├── SnackBarProvider.kt
│ │ │ │ └── navigation
│ │ │ │ │ ├── AppNavigationBar.kt
│ │ │ │ │ ├── AppNavigationBarState.kt
│ │ │ │ │ ├── BottomAppBarProvider.kt
│ │ │ │ │ └── BottomBarViewModel.kt
│ │ │ ├── note
│ │ │ │ ├── NoteScreen.kt
│ │ │ │ ├── NoteScreenContent.kt
│ │ │ │ ├── NoteScreenFooter.kt
│ │ │ │ ├── NoteScreenHeader.kt
│ │ │ │ ├── NoteScreenRemindersContent.kt
│ │ │ │ ├── NoteScreenShareComponent.kt
│ │ │ │ └── NoteViewModel.kt
│ │ │ ├── noteList
│ │ │ │ ├── NoteListScreen.kt
│ │ │ │ ├── NoteListScreenActionBar.kt
│ │ │ │ ├── NoteListScreenReminderCheck.kt
│ │ │ │ └── NotesViewModel.kt
│ │ │ ├── purchase
│ │ │ │ ├── PurchaseScreen.kt
│ │ │ │ └── PurchaseViewModel.kt
│ │ │ ├── settings
│ │ │ │ ├── SettingsScreen.kt
│ │ │ │ └── SettingsViewModel.kt
│ │ │ └── statistics
│ │ │ │ └── StatisticsScreen.kt
│ │ │ ├── services
│ │ │ ├── backup
│ │ │ │ ├── BackupData.kt
│ │ │ │ └── BackupService.kt
│ │ │ ├── billing
│ │ │ │ ├── AppProducts.kt
│ │ │ │ └── BillingService.kt
│ │ │ ├── inAppUpdates
│ │ │ │ └── InAppUpdatesService.kt
│ │ │ ├── notification
│ │ │ │ ├── NotificationData.kt
│ │ │ │ ├── NotificationReceiver.kt
│ │ │ │ ├── NotificationScheduler.kt
│ │ │ │ └── NotificationStorage.kt
│ │ │ ├── review
│ │ │ │ └── ReviewService.kt
│ │ │ └── statistics
│ │ │ │ ├── StatisticsData.kt
│ │ │ │ ├── StatisticsService.kt
│ │ │ │ └── StatisticsStorage.kt
│ │ │ ├── ui
│ │ │ ├── animation
│ │ │ │ └── AnimateVerticalSwitch.kt
│ │ │ ├── components
│ │ │ │ ├── buttons
│ │ │ │ │ ├── CustomButton.kt
│ │ │ │ │ ├── CustomSwitch.kt
│ │ │ │ │ ├── DropDownButton.kt
│ │ │ │ │ ├── FloatingActionButton.kt
│ │ │ │ │ ├── HashtagButton.kt
│ │ │ │ │ └── RichTextStyleButton.kt
│ │ │ │ ├── cards
│ │ │ │ │ ├── AppIcon.kt
│ │ │ │ │ ├── DonateBannerProvider.kt
│ │ │ │ │ ├── FeatureCard.kt
│ │ │ │ │ ├── LinkCard.kt
│ │ │ │ │ ├── LinkPreviewCard.kt
│ │ │ │ │ ├── MediaCard.kt
│ │ │ │ │ ├── NoteCard.kt
│ │ │ │ │ ├── PurchaseCard.kt
│ │ │ │ │ ├── ReminderCard.kt
│ │ │ │ │ ├── SettingsItem.kt
│ │ │ │ │ ├── SnackbarCard.kt
│ │ │ │ │ ├── StatisticsCard.kt
│ │ │ │ │ ├── ThemePreview.kt
│ │ │ │ │ └── UserCard.kt
│ │ │ │ ├── fields
│ │ │ │ │ ├── CustomDatePicker.kt
│ │ │ │ │ ├── CustomDefaultTextField.kt
│ │ │ │ │ ├── CustomOutlinedTextField.kt
│ │ │ │ │ ├── CustomRichTextEditor.kt
│ │ │ │ │ ├── CustomSlider.kt
│ │ │ │ │ ├── CustomTextField.kt
│ │ │ │ │ ├── CustomTimePicker.kt
│ │ │ │ │ ├── HashtagEditor.kt
│ │ │ │ │ └── SearchBar.kt
│ │ │ │ ├── layouts
│ │ │ │ │ ├── CalendarDayView.kt
│ │ │ │ │ ├── Counter.kt
│ │ │ │ │ ├── LazyGridNotes.kt
│ │ │ │ │ ├── LinkPreviewList.kt
│ │ │ │ │ ├── RichTextBottomToolBar.kt
│ │ │ │ │ ├── RichTextHeaderToolBar.kt
│ │ │ │ │ ├── ScreenStub.kt
│ │ │ │ │ ├── ScreenWrapper.kt
│ │ │ │ │ ├── SettingsGroup.kt
│ │ │ │ │ ├── TopActionBar.kt
│ │ │ │ │ ├── VerticalIndicator.kt
│ │ │ │ │ ├── noteTagsList.kt
│ │ │ │ │ ├── notesList.kt
│ │ │ │ │ └── notesListHeadline.kt
│ │ │ │ └── modals
│ │ │ │ │ ├── ActionDialog.kt
│ │ │ │ │ ├── BottomSheetActions.kt
│ │ │ │ │ ├── CreateReminderDialog.kt
│ │ │ │ │ ├── FullscreenPopup.kt
│ │ │ │ │ ├── InsertLinkDialog.kt
│ │ │ │ │ ├── OfferWriteReview.kt
│ │ │ │ │ ├── ShareNoteDialog.kt
│ │ │ │ │ └── onboarding
│ │ │ │ │ ├── OnboardingDialog.kt
│ │ │ │ │ └── OnboardingScreens.kt
│ │ │ ├── helpers
│ │ │ │ ├── LocalProvider.kt
│ │ │ │ ├── MultipleEventsCutter.kt
│ │ │ │ ├── SecureModeManager.kt
│ │ │ │ ├── SetRichTextDefaultStyles.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ ├── WindowInsets.kt
│ │ │ │ ├── WindowWidthSizeClass.kt
│ │ │ │ ├── dp.kt
│ │ │ │ └── keyboardAsState.kt
│ │ │ ├── modifiers
│ │ │ │ ├── FadingEdges.kt
│ │ │ │ ├── bounceClick.kt
│ │ │ │ ├── circularRotation.kt
│ │ │ │ ├── scrollConnection.kt
│ │ │ │ └── sharedTransition.kt
│ │ │ └── theme
│ │ │ │ ├── AppTheme.kt
│ │ │ │ ├── CustomColors.kt
│ │ │ │ ├── MaterialColors.kt
│ │ │ │ ├── Shape.kt
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Type.kt
│ │ │ ├── util
│ │ │ ├── ContextUtils.kt
│ │ │ ├── LauncherIcon.kt
│ │ │ ├── SnackbarHostUtil.kt
│ │ │ ├── SupportTheDeveloperBannerUtil.kt
│ │ │ └── settings
│ │ │ │ ├── Localization.kt
│ │ │ │ ├── SettingsManager.kt
│ │ │ │ └── SettingsState.kt
│ │ │ └── widgets
│ │ │ ├── WidgetKeys.kt
│ │ │ ├── components
│ │ │ └── NoteWidgetContent.kt
│ │ │ ├── config
│ │ │ └── ConfigWidgetActivity.kt
│ │ │ ├── handlers
│ │ │ └── NotesHandler.kt
│ │ │ ├── screens
│ │ │ └── noteSelection
│ │ │ │ ├── NoteSelectionScreen.kt
│ │ │ │ └── NoteSelectionViewModel.kt
│ │ │ ├── services
│ │ │ ├── NoteWidgetReceiver.kt
│ │ │ └── PinWidgetReceiver.kt
│ │ │ └── widgets
│ │ │ └── NoteWidget.kt
│ └── res
│ │ ├── anim
│ │ └── rotate.xml
│ │ ├── drawable-night
│ │ └── note_widget_preview.png
│ │ ├── drawable
│ │ ├── add_link_fill0_wght400_grad0_opsz24.xml
│ │ ├── bg_gradient.xml
│ │ ├── close_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_align_center_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_align_left_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_align_right_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_bold_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_clear_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_color_fill_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_color_text_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_h1_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_h2_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_h3_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_italic_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_list_bulleted_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_list_numbered_fill0_wght400_grad0_opsz24.xml
│ │ ├── format_strikethrough_black_24dp.xml
│ │ ├── format_underlined_fill0_wght400_grad0_opsz24.xml
│ │ ├── ic_avocado_launcher.xml
│ │ ├── ic_avocado_launcher_foreground.xml
│ │ ├── ic_blueberry_launcher.xml
│ │ ├── ic_blueberry_launcher_foreground.xml
│ │ ├── ic_btc.xml
│ │ ├── ic_bug.xml
│ │ ├── ic_buy_me_a_coffee.xml
│ │ ├── ic_classic_launcher.xml
│ │ ├── ic_classic_launcher_foreground.xml
│ │ ├── ic_classic_white_launcher.xml
│ │ ├── ic_classic_white_launcher_foreground.xml
│ │ ├── ic_eth.xml
│ │ ├── ic_game_of_life.xml
│ │ ├── ic_github.xml
│ │ ├── ic_launcher.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_love_launcher.xml
│ │ ├── ic_love_launcher_foreground.xml
│ │ ├── ic_mail.xml
│ │ ├── ic_mango_launcher.xml
│ │ ├── ic_mango_launcher_foreground.xml
│ │ ├── ic_material_launcher.xml
│ │ ├── ic_material_launcher_foreground.xml
│ │ ├── ic_money_launcher.xml
│ │ ├── ic_money_launcher_foreground.xml
│ │ ├── ic_night_launcher.xml
│ │ ├── ic_night_launcher_foreground.xml
│ │ ├── ic_plum_launcher.xml
│ │ ├── ic_plum_launcher_foreground.xml
│ │ ├── ic_rocket_launcher.xml
│ │ ├── ic_rocket_launcher_foreground.xml
│ │ ├── ic_star_launcher.xml
│ │ ├── ic_star_launcher_foreground.xml
│ │ ├── ic_strawberry_launcher.xml
│ │ ├── ic_strawberry_launcher_foreground.xml
│ │ ├── ic_telegram.xml
│ │ ├── ic_usdt.xml
│ │ ├── match_case_fill0_wght400_grad0_opsz24.xml
│ │ ├── note_widget_preview.png
│ │ ├── notification_ic_celebration.xml
│ │ ├── notification_ic_event.xml
│ │ ├── notification_ic_fitness.xml
│ │ ├── notification_ic_flag.xml
│ │ ├── notification_ic_pill.xml
│ │ ├── notification_ic_travel.xml
│ │ ├── notification_ic_warning.xml
│ │ ├── notification_ic_work.xml
│ │ ├── photo_my_favorite_cat.png
│ │ ├── redo_fill0_wght400_grad0_opsz24.xml
│ │ ├── terminal_fill0_wght400_grad0_opsz24.xml
│ │ ├── three_stars.png
│ │ ├── two_phones_preview.png
│ │ ├── undo_fill0_wght400_grad0_opsz24.xml
│ │ └── widget_background.xml
│ │ ├── layout
│ │ └── widget_preview_layout.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_avocado_launcher.xml
│ │ ├── ic_avocado_launcher_round.xml
│ │ ├── ic_blueberry_launcher.xml
│ │ ├── ic_blueberry_launcher_round.xml
│ │ ├── ic_classic_launcher.xml
│ │ ├── ic_classic_launcher_round.xml
│ │ ├── ic_classic_white_launcher.xml
│ │ ├── ic_classic_white_launcher_round.xml
│ │ ├── ic_launcher.xml
│ │ ├── ic_launcher_round.xml
│ │ ├── ic_love_launcher.xml
│ │ ├── ic_love_launcher_round.xml
│ │ ├── ic_mango_launcher.xml
│ │ ├── ic_mango_launcher_round.xml
│ │ ├── ic_material_launcher.xml
│ │ ├── ic_material_launcher_round.xml
│ │ ├── ic_money_launcher.xml
│ │ ├── ic_money_launcher_round.xml
│ │ ├── ic_night_launcher.xml
│ │ ├── ic_night_launcher_round.xml
│ │ ├── ic_plum_launcher.xml
│ │ ├── ic_plum_launcher_round.xml
│ │ ├── ic_rocket_launcher.xml
│ │ ├── ic_rocket_launcher_round.xml
│ │ ├── ic_star_launcher.xml
│ │ ├── ic_star_launcher_round.xml
│ │ ├── ic_strawberry_launcher.xml
│ │ └── ic_strawberry_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_avocado_launcher.webp
│ │ ├── ic_avocado_launcher_round.webp
│ │ ├── ic_blueberry_launcher.webp
│ │ ├── ic_blueberry_launcher_round.webp
│ │ ├── ic_classic_launcher.webp
│ │ ├── ic_classic_launcher_round.webp
│ │ ├── ic_classic_white_launcher.webp
│ │ ├── ic_classic_white_launcher_round.webp
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_love_launcher.webp
│ │ ├── ic_love_launcher_round.webp
│ │ ├── ic_mango_launcher.webp
│ │ ├── ic_mango_launcher_round.webp
│ │ ├── ic_material_launcher.webp
│ │ ├── ic_material_launcher_round.webp
│ │ ├── ic_money_launcher.webp
│ │ ├── ic_money_launcher_round.webp
│ │ ├── ic_night_launcher.webp
│ │ ├── ic_night_launcher_round.webp
│ │ ├── ic_plum_launcher.webp
│ │ ├── ic_plum_launcher_round.webp
│ │ ├── ic_rocket_launcher.webp
│ │ ├── ic_rocket_launcher_round.webp
│ │ ├── ic_star_launcher.webp
│ │ ├── ic_star_launcher_round.webp
│ │ ├── ic_strawberry_launcher.webp
│ │ └── ic_strawberry_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_avocado_launcher.webp
│ │ ├── ic_avocado_launcher_round.webp
│ │ ├── ic_blueberry_launcher.webp
│ │ ├── ic_blueberry_launcher_round.webp
│ │ ├── ic_classic_launcher.webp
│ │ ├── ic_classic_launcher_round.webp
│ │ ├── ic_classic_white_launcher.webp
│ │ ├── ic_classic_white_launcher_round.webp
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_love_launcher.webp
│ │ ├── ic_love_launcher_round.webp
│ │ ├── ic_mango_launcher.webp
│ │ ├── ic_mango_launcher_round.webp
│ │ ├── ic_material_launcher.webp
│ │ ├── ic_material_launcher_round.webp
│ │ ├── ic_money_launcher.webp
│ │ ├── ic_money_launcher_round.webp
│ │ ├── ic_night_launcher.webp
│ │ ├── ic_night_launcher_round.webp
│ │ ├── ic_plum_launcher.webp
│ │ ├── ic_plum_launcher_round.webp
│ │ ├── ic_rocket_launcher.webp
│ │ ├── ic_rocket_launcher_round.webp
│ │ ├── ic_star_launcher.webp
│ │ ├── ic_star_launcher_round.webp
│ │ ├── ic_strawberry_launcher.webp
│ │ └── ic_strawberry_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_avocado_launcher.webp
│ │ ├── ic_avocado_launcher_round.webp
│ │ ├── ic_blueberry_launcher.webp
│ │ ├── ic_blueberry_launcher_round.webp
│ │ ├── ic_classic_launcher.webp
│ │ ├── ic_classic_launcher_round.webp
│ │ ├── ic_classic_white_launcher.webp
│ │ ├── ic_classic_white_launcher_round.webp
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_love_launcher.webp
│ │ ├── ic_love_launcher_round.webp
│ │ ├── ic_mango_launcher.webp
│ │ ├── ic_mango_launcher_round.webp
│ │ ├── ic_material_launcher.webp
│ │ ├── ic_material_launcher_round.webp
│ │ ├── ic_money_launcher.webp
│ │ ├── ic_money_launcher_round.webp
│ │ ├── ic_night_launcher.webp
│ │ ├── ic_night_launcher_round.webp
│ │ ├── ic_plum_launcher.webp
│ │ ├── ic_plum_launcher_round.webp
│ │ ├── ic_rocket_launcher.webp
│ │ ├── ic_rocket_launcher_round.webp
│ │ ├── ic_star_launcher.webp
│ │ ├── ic_star_launcher_round.webp
│ │ ├── ic_strawberry_launcher.webp
│ │ └── ic_strawberry_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_avocado_launcher.webp
│ │ ├── ic_avocado_launcher_round.webp
│ │ ├── ic_blueberry_launcher.webp
│ │ ├── ic_blueberry_launcher_round.webp
│ │ ├── ic_classic_launcher.webp
│ │ ├── ic_classic_launcher_round.webp
│ │ ├── ic_classic_white_launcher.webp
│ │ ├── ic_classic_white_launcher_round.webp
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_love_launcher.webp
│ │ ├── ic_love_launcher_round.webp
│ │ ├── ic_mango_launcher.webp
│ │ ├── ic_mango_launcher_round.webp
│ │ ├── ic_material_launcher.webp
│ │ ├── ic_material_launcher_round.webp
│ │ ├── ic_money_launcher.webp
│ │ ├── ic_money_launcher_round.webp
│ │ ├── ic_night_launcher.webp
│ │ ├── ic_night_launcher_round.webp
│ │ ├── ic_plum_launcher.webp
│ │ ├── ic_plum_launcher_round.webp
│ │ ├── ic_rocket_launcher.webp
│ │ ├── ic_rocket_launcher_round.webp
│ │ ├── ic_star_launcher.webp
│ │ ├── ic_star_launcher_round.webp
│ │ ├── ic_strawberry_launcher.webp
│ │ └── ic_strawberry_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_avocado_launcher.webp
│ │ ├── ic_avocado_launcher_round.webp
│ │ ├── ic_blueberry_launcher.webp
│ │ ├── ic_blueberry_launcher_round.webp
│ │ ├── ic_classic_launcher.webp
│ │ ├── ic_classic_launcher_round.webp
│ │ ├── ic_classic_white_launcher.webp
│ │ ├── ic_classic_white_launcher_round.webp
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_love_launcher.webp
│ │ ├── ic_love_launcher_round.webp
│ │ ├── ic_mango_launcher.webp
│ │ ├── ic_mango_launcher_round.webp
│ │ ├── ic_material_launcher.webp
│ │ ├── ic_material_launcher_round.webp
│ │ ├── ic_money_launcher.webp
│ │ ├── ic_money_launcher_round.webp
│ │ ├── ic_night_launcher.webp
│ │ ├── ic_night_launcher_round.webp
│ │ ├── ic_plum_launcher.webp
│ │ ├── ic_plum_launcher_round.webp
│ │ ├── ic_rocket_launcher.webp
│ │ ├── ic_rocket_launcher_round.webp
│ │ ├── ic_star_launcher.webp
│ │ ├── ic_star_launcher_round.webp
│ │ ├── ic_strawberry_launcher.webp
│ │ └── ic_strawberry_launcher_round.webp
│ │ ├── values-de
│ │ └── strings.xml
│ │ ├── values-en
│ │ └── strings.xml
│ │ ├── values-es
│ │ └── strings.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-in
│ │ └── strings.xml
│ │ ├── values-it
│ │ └── strings.xml
│ │ ├── values-ja
│ │ └── strings.xml
│ │ ├── values-night-v31
│ │ └── colors.xml
│ │ ├── values-night
│ │ ├── colors.xml
│ │ └── themes.xml
│ │ ├── values-pt
│ │ └── strings.xml
│ │ ├── values-ru
│ │ └── strings.xml
│ │ ├── values-th
│ │ └── strings.xml
│ │ ├── values-tr
│ │ └── strings.xml
│ │ ├── values-uk
│ │ └── strings.xml
│ │ ├── values-v31
│ │ └── colors.xml
│ │ ├── values-vi
│ │ └── strings.xml
│ │ ├── values-zh
│ │ └── strings.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── ic_avocado_launcher_background.xml
│ │ ├── ic_blackberries_launcher_background.xml
│ │ ├── ic_blueberry_launcher_background.xml
│ │ ├── ic_classic_launcher_background.xml
│ │ ├── ic_classic_white_launcher_background.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_material_background.xml
│ │ ├── ic_love_launcher_background.xml
│ │ ├── ic_mango_launcher_background.xml
│ │ ├── ic_material_launcher_background.xml
│ │ ├── ic_money_launcher_background.xml
│ │ ├── ic_night_launcher_background.xml
│ │ ├── ic_plum_launcher_background.xml
│ │ ├── ic_rocket_launcher_background.xml
│ │ ├── ic_star_launcher_background.xml
│ │ ├── ic_strawberry_launcher_background.xml
│ │ ├── non_translatable.xml
│ │ ├── splash_theme.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ ├── note_widget_info.xml
│ │ └── provider_path.xml
│ ├── release
│ └── generated
│ │ └── baselineProfiles
│ │ ├── baseline-prof.txt
│ │ └── startup-prof.txt
│ └── test
│ └── java
│ └── com
│ └── jobik
│ └── shkiper
│ └── ExampleUnitTest.kt
├── assets
├── banner.png
├── ic_night_launcher.png
├── icon-app.png
├── phones.png
└── screenshots_mobile.png
├── baselineProfile
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── tech
│ └── shkiper
│ └── baselineprofile
│ ├── BaselineProfileGenerator.kt
│ └── StartupBenchmarks.kt
├── build-logic
├── .gitignore
├── convention
│ ├── .gitignore
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── ShkiperComposeLibraryPlugin.kt
│ │ ├── ShkiperLibraryHiltPlugin.kt
│ │ ├── ShkiperLibraryPlugin.kt
│ │ └── com
│ │ └── efim
│ │ └── shkiper
│ │ ├── ConfigureCompose.kt
│ │ ├── ConfigureDetekt.kt
│ │ ├── ConfigureKotlinAndroid.kt
│ │ └── ProjectExtensions.kt
└── settings.gradle.kts
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ['https://www.buymeacoffee.com/efim']
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | /.idea/deploymentTargetDropDown.xml
11 | .DS_Store
12 | /build
13 | /app/release
14 | /captures
15 | .externalNativeBuild
16 | .cxx
17 | local.properties
18 | /.idea/
19 |
--------------------------------------------------------------------------------
/.idea/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/.idea/icon.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [//]: # (
)
2 |
3 | [//]: # (
)
4 |
5 | [//]: # ( Shkiper)
6 |
7 | [//]: # (
)
8 |
9 |

10 |
11 |
12 | ## Description
13 |
14 |
15 |
16 | The skipper is designed to make your life easier and organize your daily activities. Take notes, schedule reminders with
17 | flexible repeat modes (daily, weekly, monthly, yearly) and don't forget important events.
18 |
19 | [
](https://play.google.com/store/apps/details?id=com.jobik.shkiper)
20 |
21 | ### Key features
22 |
23 | - Create notes and group them with tags for easy organization.
24 | - View a preview of the links if they are in the note.
25 | - Go back to similar actions when editing notes, so you don't lose anything.
26 | - Customize the themes of the app to make it prestigious and customized to your style.
27 | - Back up your data or download it for quick transitions.
28 | - View application usage statistics, because it can be interesting.
29 | - Convenient reminders for important occasions.
30 | - Task calendar with all reminders and date range.
31 | - Create widgets for quick access and viewing.
32 | - Styling notes and text formatting.
33 | - Ability to share a note and statistics as an image.
34 |
35 | ### App features
36 |
37 | - Switch language (localization)
38 | - Push notifications
39 | - Custom color themes
40 | - In-app updates
41 | - In-app purchases
42 | - Glance app widgets
43 | - Image share
44 | - Text formatting
45 |
46 |
47 | ⭐ Shkiper is still under development, if you have any questions or suggestions, please contact me! We value all of your feedback.
48 |
49 |
50 | ### Design & Screenshots
51 |
52 |
53 |

54 |
55 |
56 | ### Do you like this app? 💜
57 |
58 | Support it by joining __[stargazers](https://github.com/Efimj/Shkiper/stargazers)__ for this repository. ⭐
59 |
60 |
61 | Also, support me
62 | with
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/benchmark-rules.pro:
--------------------------------------------------------------------------------
1 | -dontobfuscate
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | #-keep class com.android.notepad.database.models.NotePosition { *; }
24 | #-keep class com.android.notepad.database.models.RepeatMode { *; }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/jobik/shkiper/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.example.notepadapp", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/NotepadApplication.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import com.jobik.shkiper.services.billing.BillingService
6 | import com.jobik.shkiper.util.ContextUtils
7 | import com.jobik.shkiper.util.settings.SettingsManager
8 | import dagger.hilt.android.HiltAndroidApp
9 |
10 | @HiltAndroidApp
11 | class NotepadApplication : Application() {
12 | override fun onCreate() {
13 | super.onCreate()
14 | }
15 |
16 | val billingClientLifecycle: BillingService
17 | get() = BillingService.getInstance(this)
18 |
19 | override fun attachBaseContext(base: Context) {
20 | SettingsManager.init(base)
21 | super.attachBaseContext(
22 | ContextUtils.setLocale(
23 | context = base,
24 | language = SettingsManager.settings.localization
25 | )
26 | )
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/SharedPreferencesKeys.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper
2 |
3 | import androidx.annotation.Keep
4 |
5 | @Keep
6 | object SharedPreferencesKeys {
7 | // Notification storage
8 | const val NotificationStorageName = "NotificationStorageName"
9 | const val NotificationListKey = "NotificationListKey"
10 | const val NoteIdExtra = "NoteIdExtra"
11 |
12 | // Application storage
13 | const val ApplicationStorageName = "ApplicationStorageName"
14 | const val ApplicationSettings = "ApplicationSettings"
15 | const val ApplicationUiMode = "ApplicationUiMode"
16 | const val OnboardingFinishedData = "2"
17 | const val OnboardingPageFinishedData = "OnboardingPageFinishedData"
18 | const val CountOfferReview = "CountOfferReview"
19 | const val LastDateReviewOffer = "LastDateReviewOffer"
20 | const val Localization = "Localization"
21 | const val Statistics = "Statistics"
22 | const val LastBannerSupportDeveloperShowingDate = "LastBannerSupportDeveloperShowingDate"
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/crash/GlobalExceptionHandler.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.crash
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.util.Log
7 | import androidx.activity.ComponentActivity
8 | import kotlin.system.exitProcess
9 |
10 | class GlobalExceptionHandler private constructor(
11 | private val applicationContext: Context,
12 | private val defaultHandler: Thread.UncaughtExceptionHandler?,
13 | private val activityToBeLaunched: Class
14 | ) : Thread.UncaughtExceptionHandler {
15 |
16 | override fun uncaughtException(
17 | p0: Thread,
18 | p1: Throwable
19 | ) {
20 | runCatching {
21 | Log.e(this.toString(), p1.stackTraceToString())
22 | applicationContext.launchActivity(activityToBeLaunched, p1)
23 | exitProcess(0)
24 | }.getOrElse {
25 | defaultHandler?.uncaughtException(p0, p1)
26 | }
27 | }
28 |
29 | private fun Context.launchActivity(
30 | activity: Class,
31 | exception: Throwable
32 | ) = applicationContext.startActivity(
33 | Intent(applicationContext, activity).putExtra(
34 | INTENT_DATA_NAME,
35 | "${exception::class.java.simpleName}\n\n${Log.getStackTraceString(exception)}"
36 | ).addFlags(defFlags)
37 | )
38 |
39 | companion object {
40 | fun initialize(
41 | applicationContext: Context,
42 | activityToBeLaunched: Class,
43 | ) = Thread.setDefaultUncaughtExceptionHandler(
44 | GlobalExceptionHandler(
45 | applicationContext = applicationContext,
46 | defaultHandler = Thread.getDefaultUncaughtExceptionHandler()!!,
47 | activityToBeLaunched = activityToBeLaunched
48 | )
49 | )
50 | }
51 | }
52 |
53 | private const val INTENT_DATA_NAME = "GlobalExceptionHandler"
54 | private const val defFlags = Intent.FLAG_ACTIVITY_CLEAR_TOP or
55 | Intent.FLAG_ACTIVITY_NEW_TASK or
56 | Intent.FLAG_ACTIVITY_CLEAR_TASK
57 |
58 | abstract class CrashHandler : ComponentActivity() {
59 | fun getCrashReason(): String = intent.getStringExtra(INTENT_DATA_NAME) ?: ""
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/database/data/note/NoteMongoRepository.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.database.data.note
2 |
3 | import com.jobik.shkiper.database.models.Note
4 | import com.jobik.shkiper.database.models.NotePosition
5 | import kotlinx.coroutines.flow.Flow
6 | import org.mongodb.kbson.ObjectId
7 |
8 | interface NoteMongoRepository {
9 | fun getNotesFlow(): Flow>
10 | fun getNote(id: ObjectId): Note?
11 | fun getNotes(position: NotePosition): List
12 | fun getNotesFlow(position: NotePosition): Flow>
13 | fun getNotesFlow(ids: List): List
14 | fun getAllNotes(): List
15 | fun getNotesByHashtag(position: NotePosition, hashtag: String): Flow>
16 | fun getHashtags(): Set
17 | fun getHashtags(position: NotePosition): Flow>
18 | suspend fun insertNote(note: Note)
19 | suspend fun insertOrUpdateNotes(notes: List, updateStatistics: Boolean = true)
20 | suspend fun updateNote(id: ObjectId, updateParams: (Note) -> Unit)
21 | suspend fun updateNote(ids: List, updateParams: (Note) -> Unit)
22 | suspend fun deleteNote(id: ObjectId)
23 | suspend fun deleteNote(ids: List)
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/database/data/reminder/ReminderMongoRepository.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.database.data.reminder
2 |
3 | import com.jobik.shkiper.database.models.Note
4 | import com.jobik.shkiper.database.models.Reminder
5 | import kotlinx.coroutines.flow.Flow
6 | import org.mongodb.kbson.ObjectId
7 |
8 | interface ReminderMongoRepository {
9 | fun getReminders(): Flow>
10 | fun getReminder(id: ObjectId): Reminder?
11 | fun getAllReminders(): List
12 | fun getRemindersForNote(noteId: ObjectId): Flow>
13 | suspend fun insertReminder(reminder: Reminder)
14 | suspend fun insertOrUpdateReminders(reminders: List, updateStatistics: Boolean = true)
15 | suspend fun updateReminder(reminderId: ObjectId, note: Note, updateParams: (Reminder) -> Unit)
16 | suspend fun createReminderForNotes(notes: List, updateParams: (Reminder) -> Unit)
17 | suspend fun deleteReminder(id: ObjectId)
18 | suspend fun deleteReminder(ids: List)
19 | suspend fun deleteAllRemindersForNote(noteId: ObjectId)
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/database/di/DatabaseModule.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.database.di
2 |
3 | import android.content.Context
4 | import androidx.annotation.Keep
5 | import com.jobik.shkiper.database.data.note.NoteMongoRepository
6 | import com.jobik.shkiper.database.data.note.NoteMongoRepositoryImpl
7 | import com.jobik.shkiper.database.data.reminder.ReminderMongoRepository
8 | import com.jobik.shkiper.database.data.reminder.ReminderMongoRepositoryImpl
9 | import com.jobik.shkiper.database.models.Note
10 | import com.jobik.shkiper.database.models.Reminder
11 | import dagger.Module
12 | import dagger.Provides
13 | import dagger.hilt.InstallIn
14 | import dagger.hilt.android.qualifiers.ApplicationContext
15 | import dagger.hilt.components.SingletonComponent
16 | import io.realm.kotlin.Realm
17 | import io.realm.kotlin.RealmConfiguration
18 | import javax.inject.Singleton
19 |
20 | @Module
21 | @InstallIn(SingletonComponent::class)
22 | object DatabaseModule {
23 | @Singleton
24 | @Provides
25 | fun provideRealm(): Realm {
26 | val config = RealmConfiguration.Builder(
27 | schema = setOf(
28 | Note::class,
29 | Reminder::class,
30 | )
31 | )
32 | .compactOnLaunch()
33 | .schemaVersion(3)
34 | .build()
35 | return Realm.open(config)
36 | }
37 |
38 | @Singleton
39 | @Provides
40 | fun provideNoteMongoRepository(realm: Realm, @ApplicationContext appContext: Context): NoteMongoRepository {
41 | return NoteMongoRepositoryImpl(realm = realm, context = appContext)
42 | }
43 |
44 | @Singleton
45 | @Provides
46 | fun provideReminderMongoRepository(realm: Realm, @ApplicationContext appContext: Context): ReminderMongoRepository {
47 | return ReminderMongoRepositoryImpl(realm = realm, context = appContext)
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/database/models/Note.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.database.models
2 |
3 | import androidx.annotation.Keep
4 | import io.realm.kotlin.ext.realmListOf
5 | import io.realm.kotlin.ext.realmSetOf
6 | import io.realm.kotlin.types.RealmList
7 | import io.realm.kotlin.types.RealmObject
8 | import io.realm.kotlin.types.RealmSet
9 | import io.realm.kotlin.types.annotations.Index
10 | import io.realm.kotlin.types.annotations.PrimaryKey
11 | import org.mongodb.kbson.ObjectId
12 | import java.time.LocalDateTime
13 |
14 | @Keep
15 | enum class NotePosition {
16 | MAIN,
17 | ARCHIVE,
18 | DELETE,
19 | }
20 |
21 | class Note : RealmObject {
22 | @PrimaryKey
23 | var _id: ObjectId = ObjectId.invoke()
24 |
25 | @Index
26 | var header: String = ""
27 |
28 | @Index
29 | var body: String = ""
30 | var hashtags: RealmSet = realmSetOf()
31 | var creationDateString: String = ""
32 | var updateDateString: String = ""
33 | var deletionDateString: String? = null
34 | var photos: RealmList = realmListOf()
35 |
36 | @Index
37 | var isPinned: Boolean = false
38 | var isTaskList: Boolean = false
39 | var linkPreviewEnabled: Boolean = true
40 |
41 | @Index
42 | var positionString: String = NotePosition.MAIN.name
43 |
44 | var position: NotePosition
45 | get() = NotePosition.valueOf(positionString)
46 | set(value) {
47 | positionString = value.name
48 | }
49 |
50 | var creationDate: LocalDateTime
51 | get() {
52 | return try {
53 | LocalDateTime.parse(creationDateString)
54 | } catch (e: Exception) {
55 | LocalDateTime.now()
56 | }
57 | }
58 | set(value) {
59 | creationDateString = value.toString()
60 | }
61 |
62 | var updateDate: LocalDateTime
63 | get() {
64 | return try {
65 | LocalDateTime.parse(updateDateString)
66 | } catch (e: Exception) {
67 | LocalDateTime.now()
68 | }
69 | }
70 | set(value) {
71 | updateDateString = value.toString()
72 | }
73 |
74 | var deletionDate: LocalDateTime?
75 | get() {
76 | return try {
77 | LocalDateTime.parse(deletionDateString)
78 | } catch (e: Exception) {
79 | null
80 | }
81 | }
82 | set(value) {
83 | deletionDateString = value.toString()
84 | }
85 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/helpers/AppHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.helpers
2 |
3 | import android.app.AlarmManager
4 | import android.app.NotificationManager
5 | import android.content.Context
6 | import android.os.Build
7 | import androidx.core.app.NotificationManagerCompat
8 | import androidx.core.content.ContextCompat
9 | import com.jobik.shkiper.services.notification.NotificationScheduler
10 |
11 | fun areChanelNotificationsEnabled(context: Context, channelId: String): Boolean {
12 | runCatching {
13 | val notificationManager = context.getSystemService(NotificationManager::class.java)
14 | var channel = notificationManager.getNotificationChannel(channelId)
15 | if (channel == null) {
16 | val notificationScheduler = NotificationScheduler(context)
17 | notificationScheduler.createNotificationChannel(
18 | NotificationScheduler.Companion.NotificationChannels.NOTECHANNEL,
19 | context
20 | )
21 | }
22 | channel = notificationManager.getNotificationChannel(channelId)
23 | return channel.importance != NotificationManager.IMPORTANCE_NONE
24 | }
25 | return false
26 | }
27 |
28 | fun areEXACTNotificationsEnabled(context: Context): Boolean {
29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
30 | val alarmManager = ContextCompat.getSystemService(context, AlarmManager::class.java) ?: return true
31 | return alarmManager.canScheduleExactAlarms()
32 | }
33 | return true
34 | }
35 |
36 | fun areNotificationsEnabled(context: Context): Boolean {
37 | return NotificationManagerCompat.from(context).areNotificationsEnabled()
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/helpers/FileHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.helpers
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.Bitmap.CompressFormat
6 | import android.net.Uri
7 | import androidx.compose.ui.graphics.ImageBitmap
8 | import androidx.compose.ui.graphics.asAndroidBitmap
9 | import java.io.File
10 | import java.io.FileOutputStream
11 |
12 | class FileHelper {
13 | companion object {
14 | fun saveImageToInternalStorage(
15 | context: Context,
16 | bitmap: ImageBitmap,
17 | fileName: String,
18 | compressFormat: CompressFormat = CompressFormat.PNG
19 | ) {
20 | val outputStream: FileOutputStream
21 | try {
22 | outputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE)
23 | bitmap.asAndroidBitmap().compress(compressFormat, 100, outputStream)
24 | outputStream.close()
25 | } catch (e: Exception) {
26 | e.printStackTrace()
27 | }
28 | }
29 |
30 | fun saveFileToInternalStorage(context: Context, fileUri: Uri, fileName: String) {
31 | try {
32 | val inputStream = context.contentResolver.openInputStream(fileUri)
33 | val outputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE)
34 | inputStream?.use { input ->
35 | outputStream.use { output ->
36 | input.copyTo(output)
37 | }
38 | }
39 | } catch (e: Exception) {
40 | e.printStackTrace()
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/helpers/LinkHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.helpers
2 |
3 | import android.util.Log
4 | import androidx.annotation.Keep
5 | import org.jsoup.Jsoup
6 |
7 | @Keep
8 | class LinkHelper {
9 | fun findLinks(text: String): Set {
10 | val regex = Regex("""\b(?:https?://|www\.)\S+\b""")
11 | val matches = regex.findAll(text)
12 | return matches.map { it.value }.toSet()
13 | }
14 |
15 | data class LinkPreview(
16 | var title: String? = null,
17 | var description: String? = null,
18 | var img: String? = null,
19 | var url: String? = null,
20 | var link: String? = null,
21 | )
22 |
23 | suspend fun getOpenGraphData(link: String): LinkPreview {
24 | val linkPreview = LinkPreview(link = link)
25 | try {
26 | val response = Jsoup.connect(link).execute()
27 | val docs = response.parse().getElementsByTag("meta")
28 | for (element in docs) {
29 | when {
30 | element.attr("property").equals("og:image") -> {
31 | linkPreview.img = element.attr("content")
32 | }
33 | element.attr("property").equals("og:title") -> {
34 | linkPreview.title = element.attr("content")
35 | }
36 | element.attr("property").equals("og:description") -> {
37 | linkPreview.description = element.attr("content")
38 | }
39 | element.attr("property").equals("og:url") -> {
40 | linkPreview.url = element.attr("content")
41 | }
42 | }
43 | }
44 | } catch (e: Exception) {
45 | Log.e("getOpenGraphData", "Error occurred", e)
46 | }
47 | return linkPreview
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/helpers/NumberHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.helpers
2 |
3 | import androidx.annotation.Keep
4 |
5 | @Keep
6 | class NumberHelper {
7 | fun formatNumber(number: ULong): String {
8 | val suffixes = listOf("", "K", "M", "B", "T") // Суффиксы для сокращения чисел
9 |
10 | var num = number.toDouble()
11 | var suffixIndex = 0
12 |
13 | while (num >= 1000 && suffixIndex < suffixes.size - 1) {
14 | num /= 1000
15 | suffixIndex++
16 | }
17 |
18 | return buildString {
19 | append(num.toInt())
20 |
21 | if (suffixIndex > 0) {
22 | append(suffixes[suffixIndex])
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/helpers/TextHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.helpers
2 |
3 | import androidx.annotation.Keep
4 |
5 | @Keep
6 | class TextHelper {
7 | companion object{
8 | fun removeMarkdownStyles(input: String): String {
9 | // Remove emphasis (italics, strikethrough and bold)
10 | var output = input.replace(Regex("[*]{1,2}|[_]{1,2}|[~]{1,2}"), "")
11 |
12 | // Remove inline code
13 | output = output.replace(Regex("`{1,2}"), "")
14 |
15 | // Remove headers
16 | output = output.replace(Regex("^#{1,6}\\s"), "")
17 |
18 | // Remove unordered list indicators
19 | output = output.replace(Regex("^\\s*[-+*]\\s"), "")
20 |
21 | // Remove ordered list indicators
22 | output = output.replace(Regex("^\\s*\\d+\\.\\s"), "")
23 |
24 | // Remove blockquotes
25 | output = output.replace(Regex("^>\\s"), "")
26 |
27 | return output
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/navigation/NavigationHelpers.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.navigation
2 |
3 | import android.util.Log
4 | import androidx.lifecycle.Lifecycle
5 | import androidx.navigation.NavController
6 | import androidx.navigation.NavDestination.Companion.hasRoute
7 | import androidx.navigation.NavDestination.Companion.hierarchy
8 | import androidx.navigation.NavGraph.Companion.findStartDestination
9 |
10 | class NavigationHelpers {
11 | companion object {
12 |
13 | fun NavController.canNavigate(): Boolean {
14 | return this.currentBackStackEntry?.lifecycle?.currentState == Lifecycle.State.RESUMED
15 | }
16 |
17 | fun NavController.navigateToMain(destination: Screen) = run {
18 | if (canNavigate().not()) return@run
19 | if (checkIsDestinationCurrent(destination)) return@run
20 | navigate(destination) {
21 | // Pop up to the start destination of the graph to
22 | // avoid building up a large stack of destinations
23 | // on the back stack as users select items
24 | try {
25 | popUpTo(graph.findStartDestination().id) {
26 | saveState = true
27 | }
28 | } catch (e: Exception) {
29 | Log.e("navigateToMain", "findStartDestination", e)
30 | }
31 | // Avoid multiple copies of the same destination when
32 | // reselecting the same item
33 | launchSingleTop = true
34 | // Restore state when reselecting a previously selected item
35 | restoreState = true
36 | }
37 | }
38 |
39 | fun NavController.navigateToSecondary(destination: Screen) = run {
40 | if (canNavigate().not()) return@run
41 | if (checkIsDestinationCurrent(destination)) return@run
42 | navigate(destination) {
43 | // Avoid multiple copies of the same destination when
44 | // reselecting the same item
45 | launchSingleTop = true
46 | // Restore state when reselecting a previously selected item
47 | restoreState = true
48 | }
49 | }
50 |
51 | private fun NavController.checkIsDestinationCurrent(destination: Screen): Boolean {
52 | val backStackEntry = this.currentBackStackEntry ?: return false
53 | return backStackEntry.destination.hierarchy.any {
54 | it.hasRoute(destination::class)
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/navigation/RouteHelper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.navigation
2 |
3 | import androidx.navigation.NavBackStackEntry
4 | import androidx.navigation.NavDestination.Companion.hasRoute
5 | import androidx.navigation.NavDestination.Companion.hierarchy
6 | import androidx.navigation.NavHostController
7 |
8 | class RouteHelper {
9 | val NumberedRoutes = listOf(Screen.NoteList, Screen.Settings)
10 | val SecondaryRoutes = listOf(
11 | Screen.Note(id = ""),
12 | Screen.Calendar,
13 | Screen.Statistics,
14 | Screen.Purchases,
15 | Screen.AboutNotepad,
16 | Screen.AdvancedSettings
17 | )
18 |
19 | /**
20 | * To find the route number to determine the direction of transition
21 | */
22 | fun getRouteNumber(route: Screen): Int? {
23 | NumberedRoutes.forEachIndexed { index, element ->
24 | if (element.name == route.name) return index
25 | }
26 | return null
27 | }
28 |
29 | /**
30 | * This routes not show navigation button
31 | */
32 | fun isSecondaryRoute(route: Screen): Boolean {
33 | return SecondaryRoutes.any { it.name == route.name }
34 | }
35 |
36 | companion object {
37 | /**
38 | * To get route
39 | */
40 | fun NavHostController.getScreen(): Screen? {
41 | val currentDestination = this.currentBackStackEntry?.destination ?: return null
42 | (RouteHelper().NumberedRoutes + RouteHelper().SecondaryRoutes).forEach { screen ->
43 | currentDestination.hierarchy.any {
44 | it.hasRoute(screen::class)
45 | } == true && return screen
46 | }
47 | return null
48 | }
49 |
50 | fun NavBackStackEntry.getScreen(): Screen? {
51 | val currentDestination = this.destination
52 | (RouteHelper().NumberedRoutes + RouteHelper().SecondaryRoutes).forEach { screen ->
53 | currentDestination.hierarchy.any {
54 | it.hasRoute(screen::class)
55 | } == true && return screen
56 | }
57 | return null
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/navigation/Screen.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.navigation
2 |
3 | import androidx.annotation.Keep
4 | import com.jobik.shkiper.ui.components.cards.NoteSharedOriginDefault
5 | import kotlinx.serialization.Serializable
6 |
7 | @Keep
8 | @Serializable
9 | sealed class Screen(val name: String) {
10 |
11 | @Serializable
12 | data object NoteList : Screen(name = "NoteList")
13 |
14 | @Serializable
15 | data object Settings : Screen(name = "Settings")
16 |
17 | @Serializable
18 | data class Note(val id: String, val sharedElementOrigin: String = NoteSharedOriginDefault) :
19 | Screen(name = "Note")
20 |
21 | @Serializable
22 | data object Calendar : Screen(name = "Calendar")
23 |
24 | @Serializable
25 | data object AdvancedSettings : Screen(name = "AdvancedSettings")
26 |
27 | @Serializable
28 | data object Statistics : Screen(name = "Statistics")
29 |
30 | @Serializable
31 | data object AboutNotepad : Screen(name = "AboutNotepad")
32 |
33 | @Serializable
34 | data object Purchases : Screen(name = "Purchases")
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/advancedSettings/AdvancedSecureSettings.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.advancedSettings
2 |
3 | import android.content.Context
4 | import androidx.compose.material.icons.Icons
5 | import androidx.compose.material.icons.outlined.Security
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.platform.LocalContext
8 | import androidx.compose.ui.res.stringResource
9 | import com.jobik.shkiper.R
10 | import com.jobik.shkiper.ui.components.buttons.CustomSwitch
11 | import com.jobik.shkiper.ui.components.cards.SettingsItem
12 | import com.jobik.shkiper.ui.components.layouts.SettingsGroup
13 | import com.jobik.shkiper.util.settings.SettingsManager
14 | import com.jobik.shkiper.util.settings.SettingsState
15 |
16 | @Composable
17 | fun AdvancedSecureSettings() {
18 | SettingsGroup(header = stringResource(R.string.secure)) {
19 | SecureMode()
20 | }
21 | }
22 |
23 | @Composable
24 | private fun SecureMode() {
25 | val context = LocalContext.current
26 | val settings = SettingsManager.settings
27 |
28 | fun switchSecureMode(
29 | settings: SettingsState?,
30 | context: Context
31 | ) {
32 | if (settings != null) {
33 | SettingsManager.update(
34 | context = context,
35 | settings = settings.copy(secureMode = settings.secureMode.not())
36 | )
37 | }
38 | }
39 |
40 | SettingsItem(
41 | icon = Icons.Outlined.Security,
42 | title = stringResource(R.string.secure_mode),
43 | description = stringResource(R.string.secure_mode_description),
44 | onClick = { switchSecureMode(settings = settings, context = context) }
45 | ) {
46 | CustomSwitch(
47 | active = settings?.secureMode ?: false,
48 | onClick = { switchSecureMode(settings = settings, context = context) }
49 | )
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/advancedSettings/AdvancedSettings.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.advancedSettings
2 |
3 | import android.annotation.SuppressLint
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.Arrangement
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.rememberScrollState
10 | import androidx.compose.foundation.verticalScroll
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.unit.dp
14 | import com.jobik.shkiper.ui.helpers.allWindowInsetsPadding
15 | import com.jobik.shkiper.ui.theme.AppTheme
16 |
17 | @SuppressLint("DefaultLocale")
18 | @Composable
19 | fun AdvancedSettings() {
20 | Column(
21 | modifier = Modifier
22 | .fillMaxSize()
23 | .background(AppTheme.colors.background)
24 | .verticalScroll(rememberScrollState())
25 | .allWindowInsetsPadding()
26 | .padding(top = 85.dp, bottom = 30.dp)
27 | .padding(horizontal = 10.dp),
28 | verticalArrangement = Arrangement.spacedBy(10.dp)
29 | ) {
30 | AdvancedApplicationSettings()
31 | AdvancedNotificationSettings()
32 | AdvancedSecureSettings()
33 | AdvancedUpdatesSettings()
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/layout/SnackBarProvider.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.layout
2 |
3 | import androidx.compose.animation.core.animateDpAsState
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.material3.SnackbarHost
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.unit.IntOffset
10 | import androidx.compose.ui.unit.dp
11 | import com.jobik.shkiper.screens.layout.navigation.AppNavigationBarState
12 | import com.jobik.shkiper.screens.layout.navigation.DefaultNavigationValues
13 | import com.jobik.shkiper.ui.components.cards.SnackbarCard
14 | import com.jobik.shkiper.ui.helpers.px
15 | import com.jobik.shkiper.util.SnackbarHostUtil
16 | import com.jobik.shkiper.util.SnackbarVisualsCustom
17 |
18 | @Composable
19 | fun BoxScope.SnackBarProvider() {
20 | val bottomPadding = 20.dp
21 | val currentOffsetY =
22 | (if (AppNavigationBarState.isVisible.value) bottomPadding + DefaultNavigationValues().containerHeight else 0.dp)
23 | val currentOffsetYValue =
24 | animateDpAsState(targetValue = currentOffsetY, label = "currentOffsetYValue")
25 | val pixelYOffset = -currentOffsetYValue.value.px
26 |
27 | SnackbarHost(
28 | hostState = SnackbarHostUtil.snackbarHostState,
29 | modifier = Modifier
30 | .align(Alignment.BottomCenter)
31 | .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom))
32 | ) { snackBarData ->
33 | val customVisuals = snackBarData.visuals as SnackbarVisualsCustom
34 | Box(
35 | modifier = Modifier
36 | .offset { IntOffset(x = 0, y = pixelYOffset) }
37 | .align(Alignment.BottomCenter),
38 | ) {
39 | SnackbarCard(customVisuals)
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/layout/navigation/AppNavigationBarState.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.layout.navigation
2 |
3 | import androidx.compose.runtime.MutableState
4 | import androidx.compose.runtime.State
5 | import androidx.compose.runtime.mutableStateOf
6 |
7 | object AppNavigationBarState {
8 | private var _visible: MutableState = mutableStateOf(false)
9 | private var _locked: MutableState = mutableStateOf(false)
10 |
11 | val isVisible: State = _visible
12 | val isLocked: State = _locked
13 |
14 | fun show() {
15 | if (isLocked.value.not())
16 | _visible.value = true
17 | }
18 |
19 | fun hide() {
20 | if (isLocked.value.not())
21 | _visible.value = false
22 | }
23 |
24 | fun showWithUnlock() {
25 | unlock()
26 | show()
27 | }
28 |
29 | fun hideWithLock() {
30 | hide()
31 | lock()
32 | }
33 |
34 | fun lock() {
35 | _locked.value = true
36 | }
37 |
38 | fun unlock() {
39 | _locked.value = false
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/layout/navigation/BottomBarViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.layout.navigation
2 |
3 | import androidx.compose.runtime.State
4 | import androidx.compose.runtime.mutableStateOf
5 | import androidx.lifecycle.ViewModel
6 | import com.jobik.shkiper.database.data.note.NoteMongoRepository
7 | import com.jobik.shkiper.database.models.Note
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import org.mongodb.kbson.ObjectId
10 | import javax.inject.Inject
11 |
12 | data class BottomBarState(
13 | val isCreating: Boolean = false,
14 | val createdNoteId: ObjectId? = null
15 | )
16 |
17 | @HiltViewModel
18 | class BottomBarViewModel @Inject constructor(
19 | private val noteRepository: NoteMongoRepository,
20 | ) : ViewModel() {
21 | private val _screenState = mutableStateOf(BottomBarState())
22 | val screenState: State = _screenState
23 |
24 | suspend fun createNewNote(invokeOnCreate: suspend (ObjectId) -> Unit): ObjectId {
25 | _screenState.value = _screenState.value.copy(isCreating = true)
26 | val newNote = Note()
27 | noteRepository.insertNote(newNote)
28 | invokeOnCreate(newNote._id)
29 | _screenState.value =
30 | _screenState.value.copy(createdNoteId = newNote._id, isCreating = false)
31 | return newNote._id
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/screens/note/NoteScreen.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.screens.note
2 |
3 | import androidx.activity.compose.BackHandler
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.DisposableEffect
6 | import androidx.compose.runtime.LaunchedEffect
7 | import androidx.hilt.navigation.compose.hiltViewModel
8 |
9 | @Composable
10 | fun NoteScreen(
11 | onBack: () -> Unit,
12 | noteViewModel: NoteViewModel = hiltViewModel()
13 | ) {
14 | BackHandler(true) {
15 | onBack()
16 | }
17 |
18 | NoteScreenContent(
19 | noteViewModel = noteViewModel,
20 | onBack = onBack
21 | )
22 | NoteScreenRemindersContent(noteViewModel)
23 | LeaveScreenIfNeeded(noteViewModel = noteViewModel, onBack = onBack)
24 |
25 | DisposableEffect(Unit) {
26 | onDispose {
27 | noteViewModel.deleteNoteIfEmpty()
28 | }
29 | }
30 | }
31 |
32 | @Composable
33 | private fun LeaveScreenIfNeeded(
34 | noteViewModel: NoteViewModel,
35 | onBack: () -> Unit,
36 | ) {
37 | LaunchedEffect(noteViewModel.screenState.value.isGoBack) {
38 | noteViewModel.refreshLinks()
39 | if (noteViewModel.screenState.value.isGoBack) onBack()
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/services/billing/AppProducts.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.services.billing
2 |
3 | import androidx.annotation.Keep
4 |
5 | @Keep
6 | object AppProducts {
7 | //Product IDs
8 | const val Product_1 = "product_1"
9 | const val Product_2 = "product_2"
10 |
11 | //Subscriptions IDs
12 | const val SimpleSubscription = "simple_subscription"
13 | const val Monthly = "simple-monthly"
14 | const val Yearly = "simple-yearly"
15 |
16 | val ListOfProducts = listOf(
17 | Product_1,
18 | Product_2,
19 | )
20 | val ListOfSubscriptions = listOf(
21 | SimpleSubscription,
22 | )
23 |
24 | val ListOfSubscriptionsPlans = listOf(
25 | Monthly,
26 | Yearly
27 | )
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/services/notification/NotificationData.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.services.notification
2 |
3 | import androidx.annotation.Keep
4 | import com.jobik.shkiper.database.models.Note
5 | import com.jobik.shkiper.database.models.NotificationColor
6 | import com.jobik.shkiper.database.models.NotificationIcon
7 | import com.jobik.shkiper.database.models.Reminder
8 | import com.jobik.shkiper.database.models.RepeatMode
9 | import kotlinx.serialization.Serializable
10 |
11 | @Keep
12 | @Serializable
13 | data class NotificationData(
14 | val noteId: String,
15 | val notificationId: Int,
16 | val title: String,
17 | val message: String,
18 | val repeatMode: RepeatMode,
19 | val requestCode: Int,
20 | val trigger: Long,
21 | val icon: NotificationIcon = NotificationIcon.EVENT,
22 | val color: NotificationColor = NotificationColor.MATERIAL,
23 | val channel: NotificationScheduler.Companion.NotificationChannels = NotificationScheduler.Companion.NotificationChannels.NOTECHANNEL
24 | )
25 |
26 | fun createNotificationData(note: Note, reminder: Reminder, trigger: Long): NotificationData {
27 | return NotificationData(
28 | noteId = note._id.toHexString(),
29 | notificationId = reminder._id.timestamp,
30 | title = note.header,
31 | message = note.body,
32 | repeatMode = reminder.repeat,
33 | requestCode = reminder._id.timestamp,
34 | icon = reminder.icon,
35 | color = reminder.color,
36 | trigger = trigger
37 | )
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/services/statistics/StatisticsService.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.services.statistics
2 |
3 | import android.content.Context
4 |
5 | class StatisticsService(val context: Context) {
6 | var appStatistics = AppStatistics(StatisticsStorage().getStatistics(context))
7 |
8 | fun saveStatistics() {
9 | StatisticsStorage().saveStatistics(appStatistics.statisticsData, context)
10 | }
11 |
12 | fun updateStatistics(newStatisticsData: StatisticsData) {
13 | for ((index, property) in appStatistics.statisticsData.javaClass.declaredFields.withIndex()) {
14 | property.isAccessible = true
15 | val value = property.get(appStatistics.statisticsData)
16 | val newStatisticsValue = newStatisticsData.javaClass.declaredFields[index]
17 | newStatisticsValue.isAccessible = true
18 | val newValue = property.get(newStatisticsData)
19 |
20 | if (value is LongStatistics && newValue is LongStatistics)
21 | if (newValue.value > value.value) value.value = newValue.value
22 | if (value is BooleanStatistics && newValue is BooleanStatistics)
23 | if (newValue.value > value.value) value.value = newValue.value
24 | }
25 | saveStatistics()
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/services/statistics/StatisticsStorage.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.services.statistics
2 |
3 | import android.content.Context
4 | import com.google.gson.Gson
5 | import com.jobik.shkiper.SharedPreferencesKeys
6 |
7 | class StatisticsStorage() {
8 | private val gson = Gson()
9 |
10 | fun saveStatistics(statistics: StatisticsData, context: Context) {
11 | val json = gson.toJson(statistics)
12 | val sharedPreferences =
13 | context.getSharedPreferences(SharedPreferencesKeys.ApplicationStorageName, Context.MODE_PRIVATE)
14 | val editor = sharedPreferences.edit()
15 | editor.putString(SharedPreferencesKeys.Statistics, json)
16 | editor.apply()
17 | }
18 |
19 | fun getStatistics(context: Context): StatisticsData {
20 | val sharedPreferences =
21 | context.getSharedPreferences(SharedPreferencesKeys.ApplicationStorageName, Context.MODE_PRIVATE)
22 | val json = sharedPreferences.getString(SharedPreferencesKeys.Statistics, "")
23 | return if (json.isNullOrEmpty()) StatisticsData() else gson.fromJson(json, StatisticsData::class.java)
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/buttons/CustomSwitch.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.buttons
2 |
3 | import androidx.compose.material3.Switch
4 | import androidx.compose.material3.SwitchDefaults
5 | import androidx.compose.runtime.Composable
6 | import com.jobik.shkiper.ui.theme.AppTheme
7 |
8 | @Composable
9 | fun CustomSwitch(active: Boolean, onClick: (Boolean) -> Unit, thumbContent: @Composable() (() -> Unit)? = null) {
10 | Switch(
11 | checked = active,
12 | onCheckedChange = onClick,
13 | thumbContent = thumbContent,
14 | colors = SwitchDefaults.colors(
15 | checkedThumbColor = AppTheme.colors.primary,
16 | checkedTrackColor = AppTheme.colors.secondaryContainer,
17 | checkedIconColor = AppTheme.colors.text,
18 | uncheckedThumbColor = AppTheme.colors.textSecondary,
19 | uncheckedTrackColor = AppTheme.colors.background,
20 | uncheckedIconColor = AppTheme.colors.primary,
21 | uncheckedBorderColor = AppTheme.colors.textSecondary
22 | )
23 | )
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/buttons/HashtagButton.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.buttons
2 |
3 | import androidx.compose.animation.animateColorAsState
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.foundation.shape.RoundedCornerShape
6 | import androidx.compose.material3.Card
7 | import androidx.compose.material3.CardDefaults
8 | import androidx.compose.material3.MaterialTheme
9 | import androidx.compose.material3.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.text.font.FontWeight
15 | import androidx.compose.ui.text.style.TextOverflow
16 | import androidx.compose.ui.unit.dp
17 | import com.jobik.shkiper.ui.theme.AppTheme
18 |
19 | @Composable
20 | fun HashtagButton(
21 | modifier: Modifier = Modifier,
22 | text: String,
23 | selected: Boolean = false,
24 | onClick: (String) -> Unit
25 | ) {
26 | val buttonContentColor: Color by animateColorAsState(
27 | targetValue = if (selected) AppTheme.colors.onPrimary else AppTheme.colors.text,
28 | label = "buttonContentColor"
29 | )
30 |
31 | val buttonBackgroundColor: Color by animateColorAsState(
32 | targetValue = if (selected) AppTheme.colors.primary else AppTheme.colors.container,
33 | label = "buttonBackgroundColor"
34 | )
35 |
36 | Card(
37 | modifier = modifier,
38 | onClick = { onClick(text) },
39 | shape = RoundedCornerShape(10.dp),
40 | colors = CardDefaults.cardColors(
41 | containerColor = buttonBackgroundColor,
42 | contentColor = buttonContentColor
43 | ),
44 | ) {
45 | Text(
46 | modifier = Modifier.padding(vertical = 8.dp, horizontal = 14.dp),
47 | text = text,
48 | maxLines = 1,
49 | style = MaterialTheme.typography.titleMedium,
50 | color = buttonContentColor,
51 | fontWeight = FontWeight.Normal,
52 | overflow = TextOverflow.Ellipsis
53 | )
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/buttons/RichTextStyleButton.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.buttons
2 |
3 | import androidx.annotation.DrawableRes
4 | import androidx.compose.animation.animateColorAsState
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material3.Icon
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.getValue
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.draw.clip
13 | import androidx.compose.ui.focus.focusProperties
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.res.painterResource
16 | import androidx.compose.ui.unit.dp
17 | import com.jobik.shkiper.ui.theme.AppTheme
18 | import androidx.compose.material3.*
19 | import androidx.compose.ui.Alignment
20 |
21 | @Composable
22 | fun RichTextStyleButton(
23 | isActive: Boolean,
24 | onClick: () -> Unit,
25 | @DrawableRes icon: Int,
26 | contentDescription: String = "",
27 | ) {
28 | val buttonContentColor: Color by animateColorAsState(
29 | targetValue = if (isActive) AppTheme.colors.onPrimary else AppTheme.colors.onSecondaryContainer,
30 | label = "buttonContentColor"
31 | )
32 |
33 | val buttonBackgroundColor: Color by animateColorAsState(
34 | targetValue = if (isActive) AppTheme.colors.primary else Color.Transparent,
35 | label = "buttonBackgroundColor"
36 | )
37 |
38 | Card(
39 | modifier = Modifier
40 | .size(30.dp)
41 | .clip(RoundedCornerShape(5.dp))
42 | .clickable(onClick = onClick)
43 | .focusProperties { canFocus = false },
44 | shape = RoundedCornerShape(5.dp),
45 | border = null,
46 | colors = CardDefaults.cardColors(contentColor = buttonContentColor, containerColor = buttonBackgroundColor),
47 | ) {
48 | Box(
49 | modifier = Modifier.fillMaxSize(),
50 | contentAlignment = Alignment.Center
51 | ) {
52 | Icon(
53 | modifier = Modifier.padding(2.dp),
54 | painter = painterResource(id = icon),
55 | contentDescription = contentDescription,
56 | tint = buttonContentColor
57 | )
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/fields/CustomTimePicker.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.fields
2 |
3 | import androidx.compose.foundation.BorderStroke
4 | import androidx.compose.foundation.shape.RoundedCornerShape
5 | import androidx.compose.material3.MaterialTheme
6 | import androidx.compose.runtime.*
7 | import androidx.compose.ui.graphics.Color
8 | import androidx.compose.ui.unit.DpSize
9 | import androidx.compose.ui.unit.dp
10 | import com.commandiron.wheel_picker_compose.WheelTimePicker
11 | import com.commandiron.wheel_picker_compose.core.TimeFormat
12 | import com.commandiron.wheel_picker_compose.core.WheelPickerDefaults
13 | import com.jobik.shkiper.ui.theme.AppTheme
14 | import java.time.LocalTime
15 |
16 | @Composable
17 | fun CustomTimePicker(
18 | startTime: LocalTime,
19 | minTime: LocalTime = LocalTime.MIN,
20 | maxTime: LocalTime = LocalTime.MAX,
21 | onTimeChange: (LocalTime) -> Unit,
22 | ) {
23 | WheelTimePicker(
24 | startTime = startTime,
25 | minTime = minTime,
26 | maxTime = maxTime,
27 | timeFormat = TimeFormat.HOUR_24,
28 | size = DpSize(150.dp, 250.dp),
29 | rowCount = 5,
30 | textStyle = MaterialTheme.typography.titleMedium,
31 | textColor = AppTheme.colors.text,
32 | selectorProperties = WheelPickerDefaults.selectorProperties(
33 | enabled = true,
34 | shape = RoundedCornerShape(12.dp),
35 | color = Color.Transparent,
36 | border = BorderStroke(2.dp, AppTheme.colors.primary)
37 | )
38 | ) { snappedDateTime -> onTimeChange(snappedDateTime) }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/Counter.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.compose.animation.*
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.width
7 | import androidx.compose.material3.MaterialTheme
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.text.TextStyle
14 | import androidx.compose.ui.text.style.TextAlign
15 | import androidx.compose.ui.unit.dp
16 | import com.jobik.shkiper.ui.theme.AppTheme
17 |
18 | @Composable
19 | fun Counter(
20 | count: Int,
21 | style: TextStyle = MaterialTheme.typography.bodyMedium,
22 | color: Color = AppTheme.colors.text
23 | ) {
24 | Row(
25 | modifier = Modifier.animateContentSize(),
26 | horizontalArrangement = Arrangement.Center,
27 | verticalAlignment = Alignment.CenterVertically,
28 | ) {
29 | count.toString()
30 | .mapIndexed { index, c -> Digit(c, count, index) }
31 | .forEach { digit ->
32 | AnimatedContent(
33 | modifier = Modifier.width(10.dp),
34 | targetState = digit,
35 | transitionSpec = {
36 | if (targetState > initialState) {
37 | slideInVertically { -it } togetherWith slideOutVertically { it }
38 | } else {
39 | slideInVertically { it } togetherWith slideOutVertically { -it }
40 | }
41 | },
42 | label = "Counter"
43 | ) { digit ->
44 | Text(
45 | text = "${digit.digitChar}",
46 | style = style,
47 | textAlign = TextAlign.Center,
48 | color = color
49 | )
50 | }
51 | }
52 | }
53 | }
54 |
55 | private data class Digit(val digitChar: Char, val fullNumber: Int, val place: Int) {
56 | override fun equals(other: Any?): Boolean {
57 | return when (other) {
58 | is Digit -> digitChar == other.digitChar
59 | else -> super.equals(other)
60 | }
61 | }
62 | }
63 |
64 | private operator fun Digit.compareTo(other: Digit): Int {
65 | return fullNumber.compareTo(other.fullNumber)
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/LazyGridNotes.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import android.content.res.Configuration
4 | import androidx.compose.foundation.ExperimentalFoundationApi
5 | import androidx.compose.foundation.layout.Arrangement
6 | import androidx.compose.foundation.layout.PaddingValues
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.lazy.staggeredgrid.*
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.remember
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.platform.LocalConfiguration
13 | import androidx.compose.ui.unit.dp
14 |
15 | @Composable
16 | fun LazyGridNotes(
17 | modifier: Modifier = Modifier.fillMaxSize(),
18 | gridState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
19 | contentPadding: PaddingValues = PaddingValues(0.dp),
20 | gridContent: LazyStaggeredGridScope.() -> Unit
21 | ) {
22 | val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
23 | val staggeredGridCellsMode: StaggeredGridCells = remember {
24 | if (isPortrait) StaggeredGridCells.Fixed(2) else StaggeredGridCells.Adaptive(200.dp)
25 | }
26 |
27 | LazyVerticalStaggeredGrid(
28 | state = gridState,
29 | columns = staggeredGridCellsMode,
30 | verticalItemSpacing = 8.dp,
31 | horizontalArrangement = Arrangement.spacedBy(8.dp),
32 | contentPadding = contentPadding,
33 | modifier = modifier,
34 | ) {
35 | gridContent()
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/ScreenStub.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.annotation.StringRes
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.material3.*
6 | import androidx.compose.material3.Icon
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.graphics.vector.ImageVector
12 | import androidx.compose.ui.res.stringResource
13 | import androidx.compose.ui.text.font.FontWeight
14 | import androidx.compose.ui.text.style.TextOverflow
15 | import androidx.compose.ui.unit.dp
16 | import com.jobik.shkiper.ui.theme.AppTheme
17 |
18 | @Composable
19 | fun ScreenStub(modifier: Modifier = Modifier, @StringRes title: Int, icon: ImageVector) {
20 | Column(
21 | modifier = modifier.fillMaxSize(),
22 | verticalArrangement = Arrangement.Center,
23 | horizontalAlignment = Alignment.CenterHorizontally
24 | ) {
25 | Icon(
26 | imageVector = icon,
27 | contentDescription = null,
28 | tint = AppTheme.colors.primary,
29 | modifier = Modifier.size(90.dp)
30 | )
31 | Spacer(Modifier.height(10.dp))
32 | Text(
33 | text = stringResource(title),
34 | style = MaterialTheme.typography.titleLarge,
35 | maxLines = 2,
36 | overflow = TextOverflow.Ellipsis,
37 | color = AppTheme.colors.textSecondary,
38 | fontWeight = FontWeight.SemiBold
39 | )
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/ScreenWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.widthIn
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.unit.dp
11 | import com.jobik.shkiper.ui.theme.AppTheme
12 |
13 | val ScreenWrapperContentMaxWidth = 500.dp
14 |
15 | @Composable
16 | fun ScreenWrapper(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
17 | Column(
18 | modifier = Modifier
19 | .fillMaxSize()
20 | .background(AppTheme.colors.background),
21 | horizontalAlignment = Alignment.CenterHorizontally
22 | ) {
23 | Column(
24 | modifier = modifier.widthIn(max = ScreenWrapperContentMaxWidth),
25 | horizontalAlignment = Alignment.CenterHorizontally
26 | ) {
27 | content()
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/noteTagsList.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.PaddingValues
5 | import androidx.compose.foundation.layout.width
6 | import androidx.compose.foundation.layout.wrapContentSize
7 | import androidx.compose.foundation.lazy.LazyRow
8 | import androidx.compose.foundation.lazy.items
9 | import androidx.compose.foundation.lazy.rememberLazyListState
10 | import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridScope
11 | import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.platform.LocalConfiguration
14 | import androidx.compose.ui.unit.dp
15 | import com.jobik.shkiper.ui.components.buttons.HashtagButton
16 | import com.jobik.shkiper.ui.modifiers.fadingEdges
17 |
18 | fun LazyStaggeredGridScope.noteTagsList(
19 | tags: Set,
20 | selected: String?,
21 | onSelect: (String) -> Unit
22 | ) {
23 | if (tags.isNotEmpty()) {
24 | item(span = StaggeredGridItemSpan.FullLine) {
25 | val scroll = rememberLazyListState()
26 |
27 | LazyRow(
28 | modifier = Modifier
29 | .animateItem()
30 | .wrapContentSize(unbounded = true)
31 | .fadingEdges(scrollableState = scroll)
32 | .width(LocalConfiguration.current.screenWidthDp.dp),
33 | state = scroll,
34 | contentPadding = PaddingValues(10.dp, 0.dp, 10.dp, 0.dp),
35 | horizontalArrangement = Arrangement.spacedBy(8.dp)
36 | ) {
37 | items(items = tags.toList(), key = { it }) { tag ->
38 | HashtagButton(
39 | modifier = Modifier.animateItem(),
40 | text = tag,
41 | selected = tag == selected,
42 | onClick = onSelect
43 | )
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/notesList.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridScope
4 | import androidx.compose.foundation.lazy.staggeredgrid.items
5 | import androidx.compose.ui.Modifier
6 | import com.jobik.shkiper.database.models.Note
7 | import com.jobik.shkiper.database.models.Reminder
8 | import com.jobik.shkiper.ui.components.cards.NoteCard
9 | import com.jobik.shkiper.ui.helpers.rememberNextReminder
10 | import org.mongodb.kbson.ObjectId
11 |
12 | fun LazyStaggeredGridScope.notesList(
13 | notes: List,
14 | reminders: List = emptyList(),
15 | selected: Set = emptySet(),
16 | marker: String? = null,
17 | onClick: (Note) -> Unit,
18 | onLongClick: ((Note) -> Unit)? = null,
19 | ) {
20 | items(items = notes, key = { it._id.toHexString() }) { note ->
21 | NoteCard(
22 | note = note,
23 | modifier = Modifier.animateItem(),
24 | reminder = rememberNextReminder(reminders = reminders.filter { it.noteId == note._id }),
25 | markedText = marker,
26 | selected = note._id in selected,
27 | onClick = { onClick(note) },
28 | onLongClick = {
29 | if (onLongClick != null) {
30 | onLongClick(note)
31 | }
32 | },
33 | )
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/components/layouts/notesListHeadline.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.components.layouts
2 |
3 | import androidx.annotation.StringRes
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridScope
6 | import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
7 | import androidx.compose.material3.MaterialTheme
8 | import androidx.compose.material3.Text
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.res.stringResource
11 | import androidx.compose.ui.unit.dp
12 | import com.jobik.shkiper.ui.theme.AppTheme
13 |
14 | fun LazyStaggeredGridScope.notesListHeadline(@StringRes headline: Int) {
15 | item(span = StaggeredGridItemSpan.FullLine) {
16 | Text(
17 | text = stringResource(id = headline),
18 | color = AppTheme.colors.textSecondary,
19 | style = MaterialTheme.typography.bodyLarge,
20 | modifier = Modifier.animateItem().padding(horizontal = 10.dp)
21 | )
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/LocalProvider.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import androidx.compose.animation.AnimatedVisibilityScope
4 | import androidx.compose.animation.ExperimentalSharedTransitionApi
5 | import androidx.compose.animation.SharedTransitionScope
6 | import androidx.compose.runtime.compositionLocalOf
7 | import com.jobik.shkiper.database.models.NotePosition
8 |
9 | val LocalNotePosition = compositionLocalOf { NotePosition.MAIN }
10 | val LocalSharedElementKey = compositionLocalOf { "default" }
11 | val LocalNavAnimatedVisibilityScope = compositionLocalOf { null }
12 |
13 | @OptIn(ExperimentalSharedTransitionApi::class)
14 | val LocalSharedTransitionScope = compositionLocalOf { null }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/MultipleEventsCutter.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | internal interface MultipleEventsCutter {
4 | fun processEvent(event: () -> Unit)
5 |
6 | companion object
7 | }
8 |
9 | internal fun MultipleEventsCutter.Companion.get(): MultipleEventsCutter =
10 | MultipleEventsCutterImpl()
11 |
12 | private class MultipleEventsCutterImpl : MultipleEventsCutter {
13 | private val now: Long
14 | get() = System.currentTimeMillis()
15 |
16 | private var lastEventTimeMs: Long = 0
17 |
18 | override fun processEvent(event: () -> Unit) {
19 | if (now - lastEventTimeMs >= 250L) {
20 | event.invoke()
21 | }
22 | lastEventTimeMs = now
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/SecureModeManager.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import android.view.WindowManager
4 | import androidx.activity.ComponentActivity
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.LaunchedEffect
7 | import androidx.compose.ui.platform.LocalContext
8 | import com.jobik.shkiper.util.settings.SettingsManager
9 |
10 | @Composable
11 | fun SecureModeManager(
12 | enabled: Boolean = SettingsManager.settings.secureMode ?: false
13 | ) {
14 | val context = LocalContext.current as ComponentActivity
15 |
16 | LaunchedEffect(enabled) {
17 | if (enabled) {
18 | context.window.setFlags(
19 | WindowManager.LayoutParams.FLAG_SECURE,
20 | WindowManager.LayoutParams.FLAG_SECURE
21 | )
22 | } else {
23 | context.window.clearFlags(
24 | WindowManager.LayoutParams.FLAG_SECURE
25 | )
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/SetRichTextDefaultStyles.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.LaunchedEffect
5 | import androidx.compose.ui.graphics.Color
6 | import androidx.compose.ui.text.style.TextDecoration
7 | import com.jobik.shkiper.ui.theme.AppTheme
8 | import com.mohamedrejeb.richeditor.annotation.ExperimentalRichTextApi
9 | import com.mohamedrejeb.richeditor.model.RichTextConfig
10 | import com.mohamedrejeb.richeditor.model.RichTextState
11 |
12 | @Composable
13 | fun SetRichTextDefaultStyles(
14 | richTextState: RichTextState,
15 | ) {
16 | val codeColor = AppTheme.colors.onSecondaryContainer
17 | val codeStrokeColor = AppTheme.colors.secondaryContainer
18 | val linkColor = AppTheme.colors.text
19 |
20 | LaunchedEffect(Unit) {
21 | richTextState.config.linkColor = linkColor
22 | richTextState.config.linkTextDecoration = TextDecoration.Underline
23 | richTextState.config.codeSpanColor = codeColor
24 | richTextState.config.codeSpanBackgroundColor = Color.Transparent
25 | richTextState.config.codeSpanStrokeColor = codeStrokeColor
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import androidx.compose.runtime.*
4 | import com.jobik.shkiper.database.models.Reminder
5 | import com.jobik.shkiper.helpers.DateHelper
6 | import com.kizitonwose.calendar.compose.weekcalendar.WeekCalendarState
7 | import com.kizitonwose.calendar.core.Week
8 | import kotlinx.coroutines.flow.filter
9 | import java.time.LocalDateTime
10 | import java.time.Month
11 | import java.time.YearMonth
12 | import java.time.format.TextStyle
13 | import java.util.*
14 |
15 | /**
16 | * Find first visible week in a paged week calendar **after** scrolling stops.
17 | */
18 | @Composable
19 | fun rememberFirstVisibleWeekAfterScroll(state: WeekCalendarState): Week {
20 | val visibleWeek = remember(state) { mutableStateOf(state.firstVisibleWeek) }
21 | LaunchedEffect(state) {
22 | snapshotFlow { state.isScrollInProgress }
23 | .filter { scrolling -> !scrolling }
24 | .collect { visibleWeek.value = state.firstVisibleWeek }
25 | }
26 | return visibleWeek.value
27 | }
28 |
29 | /**
30 | * To display month name.
31 | */
32 | fun YearMonth.displayText(): String {
33 | return "${this.month.getDisplayName(TextStyle.FULL, Locale.getDefault())} ${this.year}"
34 | }
35 |
36 | @Composable
37 | fun rememberNextReminder(
38 | reminders: List,
39 | pointDate: LocalDateTime = LocalDateTime.now()
40 | ): Reminder? {
41 | val nextReminder = remember { mutableStateOf(null) }
42 |
43 | LaunchedEffect(reminders) {
44 | nextReminder.value = DateHelper.sortReminders(reminders = reminders, pointDate = pointDate).firstOrNull()
45 | }
46 |
47 | return nextReminder.value
48 | }
49 |
50 | /**
51 | * To display month name.
52 | */
53 | fun Month.displayText(short: Boolean = true): String {
54 | val style = if (short) TextStyle.SHORT else TextStyle.FULL
55 | return getDisplayName(style, Locale.getDefault())
56 | }
57 |
58 | fun splitIntoTriple(input: List): Triple, List, List> {
59 | val list1 = mutableListOf()
60 | val list2 = mutableListOf()
61 | val list3 = mutableListOf()
62 |
63 | input.forEachIndexed { index, element ->
64 | when (index % 3) {
65 | 0 -> list1.add(element)
66 | 1 -> list2.add(element)
67 | 2 -> list3.add(element)
68 | }
69 | }
70 |
71 | return Triple(list1, list2, list3)
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/WindowWidthSizeClass.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import androidx.annotation.Keep
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.platform.LocalConfiguration
7 | import androidx.compose.ui.unit.dp
8 |
9 | @Keep
10 | enum class WindowWidthSizeClass(val minValue: Int) {
11 | Compact(0),
12 | Medium(600),
13 | Expanded(840),
14 | }
15 |
16 | @Keep
17 | enum class WindowHeightSizeClass(val minValue: Int) {
18 | Compact(0),
19 | Medium(480),
20 | Expanded(900),
21 | }
22 |
23 | @Composable
24 | fun isWidth(sizeClass: WindowWidthSizeClass): Boolean {
25 | val configuration = LocalConfiguration.current
26 | val widthInDp = configuration.screenWidthDp.dp
27 |
28 | val (mediumMin, expandedMin) = remember {
29 | Pair(WindowWidthSizeClass.Medium.minValue.dp, WindowWidthSizeClass.Expanded.minValue.dp)
30 | }
31 |
32 | return when (sizeClass) {
33 | WindowWidthSizeClass.Compact -> widthInDp < mediumMin
34 | WindowWidthSizeClass.Medium -> widthInDp >= WindowWidthSizeClass.Medium.minValue.dp && widthInDp < WindowWidthSizeClass.Expanded.minValue.dp
35 | WindowWidthSizeClass.Expanded -> widthInDp >= expandedMin
36 | }
37 | }
38 |
39 | @Composable
40 | fun isHeight(sizeClass: WindowHeightSizeClass): Boolean {
41 | val configuration = LocalConfiguration.current
42 | val widthInDp = configuration.screenWidthDp.dp
43 |
44 | val (mediumMin, expandedMin) = remember {
45 | Pair(WindowHeightSizeClass.Medium.minValue.dp, WindowHeightSizeClass.Expanded.minValue.dp)
46 | }
47 |
48 | return when (sizeClass) {
49 | WindowHeightSizeClass.Compact -> widthInDp < mediumMin
50 | WindowHeightSizeClass.Medium -> widthInDp >= WindowHeightSizeClass.Medium.minValue.dp && widthInDp < WindowHeightSizeClass.Expanded.minValue.dp
51 | WindowHeightSizeClass.Expanded -> widthInDp >= expandedMin
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/dp.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.platform.LocalDensity
5 | import androidx.compose.ui.unit.Dp
6 | import kotlin.math.roundToInt
7 |
8 | inline val Int.dp: Dp
9 | @Composable get() = with(LocalDensity.current) { this@dp.toDp() }
10 |
11 | inline val Dp.px: Int
12 | @Composable get() = with(LocalDensity.current) { this@px.toPx().roundToInt() }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/helpers/keyboardAsState.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.helpers
2 |
3 | import android.graphics.Rect
4 | import android.view.ViewTreeObserver
5 | import androidx.annotation.Keep
6 | import androidx.compose.runtime.*
7 | import androidx.compose.ui.platform.LocalView
8 |
9 | @Keep
10 | internal enum class Keyboard {
11 | Opened, Closed
12 | }
13 |
14 | @Composable
15 | internal fun keyboardAsState(): State {
16 | val keyboardState = remember { mutableStateOf(Keyboard.Closed) }
17 | val view = LocalView.current
18 | DisposableEffect(view) {
19 | val onGlobalListener = ViewTreeObserver.OnGlobalLayoutListener {
20 | val rect = Rect()
21 | view.getWindowVisibleDisplayFrame(rect)
22 | val screenHeight = view.rootView.height
23 | val keypadHeight = screenHeight - rect.bottom
24 | keyboardState.value = if (keypadHeight > screenHeight * 0.15) {
25 | Keyboard.Opened
26 | } else {
27 | Keyboard.Closed
28 | }
29 | }
30 | view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalListener)
31 |
32 | onDispose {
33 | view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalListener)
34 | }
35 | }
36 |
37 | return keyboardState
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/modifiers/bounceClick.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.modifiers
2 |
3 | import androidx.compose.animation.core.animateFloatAsState
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.gestures.awaitFirstDown
6 | import androidx.compose.foundation.gestures.waitForUpOrCancellation
7 | import androidx.compose.foundation.interaction.MutableInteractionSource
8 | import androidx.compose.runtime.getValue
9 | import androidx.compose.runtime.mutableStateOf
10 | import androidx.compose.runtime.remember
11 | import androidx.compose.runtime.setValue
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.composed
14 | import androidx.compose.ui.graphics.graphicsLayer
15 | import androidx.compose.ui.input.pointer.pointerInput
16 |
17 | private enum class ItemState { Pressed, Idle }
18 |
19 | /**
20 | * Shrinks the card when clicked
21 | */
22 | fun Modifier.bounceClick(
23 | targetValue: Float = 0.90f
24 | ) = composed {
25 | var itemState by remember { mutableStateOf(ItemState.Idle) }
26 | val scale by animateFloatAsState(if (itemState == ItemState.Pressed) targetValue else 1f)
27 |
28 | this
29 | .graphicsLayer {
30 | scaleX = scale
31 | scaleY = scale
32 | }
33 | .clickable(
34 | interactionSource = remember { MutableInteractionSource() },
35 | indication = null,
36 | onClick = { }
37 | )
38 | .pointerInput(itemState) {
39 | awaitPointerEventScope {
40 | itemState = if (itemState == ItemState.Pressed) {
41 | waitForUpOrCancellation()
42 | ItemState.Idle
43 | } else {
44 | awaitFirstDown(false)
45 | ItemState.Pressed
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/modifiers/circularRotation.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.modifiers
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.runtime.LaunchedEffect
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.draw.rotate
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.composed
9 |
10 | fun Modifier.circularRotation() = composed {
11 | val rotation = remember { Animatable(0f) }
12 | LaunchedEffect(Unit) {
13 | with(rotation) {
14 | animateTo(
15 | targetValue = 360f,
16 | animationSpec = infiniteRepeatable(
17 | animation = tween(durationMillis = 1000, easing = LinearEasing),
18 | repeatMode = RepeatMode.Restart
19 | )
20 | )
21 | }
22 | }
23 |
24 | this
25 | .rotate(rotation.value)
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/modifiers/scrollConnection.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.modifiers
2 |
3 | import androidx.compose.runtime.MutableState
4 | import androidx.compose.runtime.remember
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.composed
7 | import androidx.compose.ui.geometry.Offset
8 | import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
9 | import androidx.compose.ui.input.nestedscroll.NestedScrollSource
10 | import androidx.compose.ui.input.nestedscroll.nestedScroll
11 |
12 | fun Modifier.scrollConnectionToProvideVisibility(visible: MutableState) = composed {
13 | this.nestedScroll(
14 | remember {
15 | object : NestedScrollConnection {
16 | override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
17 | if (consumed.y < -30) {
18 | visible.value = false
19 | }
20 | if (consumed.y > 30) {
21 | visible.value = true
22 | }
23 | if (available.y > 0) {
24 | visible.value = true
25 | }
26 |
27 | return super.onPostScroll(consumed, available, source)
28 | }
29 | }
30 | }
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/modifiers/sharedTransition.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.modifiers
2 |
3 | import androidx.compose.animation.ExperimentalSharedTransitionApi
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.composed
7 | import com.jobik.shkiper.ui.components.cards.NoteSharedElementKey
8 | import com.jobik.shkiper.ui.components.cards.NoteSharedElementType
9 | import com.jobik.shkiper.ui.helpers.LocalNavAnimatedVisibilityScope
10 | import com.jobik.shkiper.ui.helpers.LocalSharedElementKey
11 | import com.jobik.shkiper.ui.helpers.LocalSharedTransitionScope
12 |
13 | @OptIn(ExperimentalSharedTransitionApi::class)
14 | @Composable
15 | fun Modifier.skipToLookaheadSize() = composed {
16 | val sharedTransitionScope = LocalSharedTransitionScope.current
17 | val animatedVisibilityScope = LocalNavAnimatedVisibilityScope.current
18 |
19 | val sharedTransitionModifier = sharedTransitionScope?.let { scope ->
20 | animatedVisibilityScope?.let { visibilityScope ->
21 | with(scope) {
22 | Modifier
23 | .skipToLookaheadSize()
24 | }
25 | }
26 | } ?: Modifier
27 | this.then(sharedTransitionModifier)
28 | }
29 |
30 | @OptIn(ExperimentalSharedTransitionApi::class)
31 | @Composable
32 | fun Modifier.sharedNoteTransitionModifier(
33 | noteId: String
34 | ) = composed {
35 | val sharedTransitionScope = LocalSharedTransitionScope.current
36 | val animatedVisibilityScope = LocalNavAnimatedVisibilityScope.current
37 | val sharedElementKey = LocalSharedElementKey.current
38 |
39 | val sharedTransitionModifier = sharedTransitionScope?.let { scope ->
40 | animatedVisibilityScope?.let { visibilityScope ->
41 | with(scope) {
42 | Modifier
43 | .skipToLookaheadSize()
44 | .sharedBounds(
45 | rememberSharedContentState(
46 | key = NoteSharedElementKey(
47 | noteId = noteId,
48 | origin = sharedElementKey,
49 | type = NoteSharedElementType.Bounds
50 | )
51 | ),
52 | animatedVisibilityScope = visibilityScope
53 | )
54 | }
55 | }
56 | } ?: Modifier
57 | this.then(sharedTransitionModifier)
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.theme
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.material3.Shapes
5 | import androidx.compose.ui.graphics.RectangleShape
6 | import androidx.compose.ui.unit.dp
7 |
8 | val CustomShapes = CustomThemeShapes(
9 | none = RectangleShape,
10 | small = RoundedCornerShape(10.dp),
11 | medium = RoundedCornerShape(15.dp),
12 | large = RoundedCornerShape(20.dp),
13 | )
14 |
15 | val MaterialShapes = Shapes(
16 | extraSmall = RoundedCornerShape(15.dp),
17 | small = RoundedCornerShape(15.dp),
18 | medium = RoundedCornerShape(15.dp),
19 | large = RoundedCornerShape(15.dp),
20 | extraLarge = RoundedCornerShape(15.dp)
21 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material3.MaterialTheme
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.CompositionLocalProvider
7 | import androidx.compose.runtime.SideEffect
8 | import androidx.compose.ui.graphics.Color.Companion.Transparent
9 | import com.google.accompanist.systemuicontroller.rememberSystemUiController
10 |
11 | @Composable
12 | fun ShkiperTheme(
13 | darkTheme: Boolean = isSystemInDarkTheme(),
14 | style: CustomThemeStyle = CustomThemeStyle.MaterialDynamicColors,
15 | content: @Composable () -> Unit
16 | ) {
17 | val colors = getThemeColors(style = style, darkTheme = darkTheme)
18 |
19 | val systemUiController = rememberSystemUiController()
20 | SideEffect {
21 | systemUiController.setSystemBarsColor(color = Transparent, darkIcons = darkTheme.not())
22 | }
23 |
24 | CompositionLocalProvider(
25 | LocalCustomThemeColors provides colors,
26 | LocalCustomThemeShapes provides CustomShapes,
27 | ) {
28 | MaterialTheme(
29 | typography = Typography,
30 | shapes = MaterialShapes,
31 | content = content
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.ui.theme
2 |
3 |
4 | import androidx.compose.material3.Typography
5 |
6 |
7 | // Set of Material typography styles to start with
8 | val Typography = Typography(
9 | // body1 = TextStyle(
10 | // fontFamily = FontFamily.Default,
11 | // fontWeight = FontWeight.Normal,
12 | // fontSize = 16.sp
13 | // )
14 | /* Other default text styles to override
15 | button = TextStyle(
16 | fontFamily = FontFamily.Default,
17 | fontWeight = FontWeight.W500,
18 | fontSize = 14.sp
19 | ),
20 | caption = TextStyle(
21 | fontFamily = FontFamily.Default,
22 | fontWeight = FontWeight.Normal,
23 | fontSize = 12.sp
24 | )
25 | */
26 | )
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/util/SnackbarHostUtil.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.util
2 |
3 | import androidx.compose.material3.SnackbarHostState
4 | import androidx.compose.material3.SnackbarDuration
5 | import androidx.compose.material3.SnackbarVisuals
6 | import androidx.compose.ui.graphics.vector.ImageVector
7 |
8 | data class SnackbarVisualsCustom(
9 | override val message: String,
10 | override val actionLabel: String? = null,
11 | override val withDismissAction: Boolean = false,
12 | override val duration: SnackbarDuration = if (actionLabel == null) SnackbarDuration.Short else SnackbarDuration.Indefinite,
13 | val action: (() -> Unit)? = null,
14 | val icon: ImageVector? = null
15 | ) : SnackbarVisuals
16 |
17 | object SnackbarHostUtil {
18 | val snackbarHostState = SnackbarHostState()
19 |
20 | // fun showSnackbar(snackbarData: SnackbarVisualsCustom) {
21 | // snackbarHostState.showSnackbar(
22 | // snackbarData
23 | // )
24 | // }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/util/SupportTheDeveloperBannerUtil.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.util
2 |
3 | import android.content.Context
4 | import androidx.annotation.Keep
5 | import com.jobik.shkiper.SharedPreferencesKeys
6 | import java.time.LocalDateTime
7 | import java.time.temporal.ChronoUnit
8 |
9 | @Keep
10 | object SupportTheDeveloperBannerUtil {
11 | const val DaysSpan = 15
12 |
13 | fun isBannerNeeded(context: Context): Boolean {
14 | return ChronoUnit.DAYS.between(getLastShowingDate(context), LocalDateTime.now()) >= DaysSpan
15 | }
16 |
17 | fun updateLastShowingDate(context: Context) {
18 | val sharedPreferences =
19 | context.getSharedPreferences(SharedPreferencesKeys.ApplicationStorageName, Context.MODE_PRIVATE)
20 | sharedPreferences.edit()
21 | .putString(SharedPreferencesKeys.LastBannerSupportDeveloperShowingDate, LocalDateTime.now().toString())
22 | .apply()
23 | }
24 |
25 | private fun getLastShowingDate(context: Context): LocalDateTime {
26 | val sharedPreferences =
27 | context.getSharedPreferences(SharedPreferencesKeys.ApplicationStorageName, Context.MODE_PRIVATE)
28 | return try {
29 | LocalDateTime.parse(
30 | sharedPreferences.getString(
31 | SharedPreferencesKeys.LastBannerSupportDeveloperShowingDate,
32 | "noLastDate"
33 | )
34 | )
35 | } catch (e: Exception) {
36 | updateLastShowingDate(context)
37 | LocalDateTime.now()
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/util/settings/SettingsManager.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.util.settings
2 |
3 | import android.content.Context
4 | import androidx.compose.runtime.MutableState
5 | import androidx.compose.runtime.mutableStateOf
6 | import com.google.gson.Gson
7 | import com.jobik.shkiper.SharedPreferencesKeys.ApplicationSettings
8 | import com.jobik.shkiper.SharedPreferencesKeys.ApplicationStorageName
9 |
10 | object SettingsManager {
11 | private var _settings: MutableState = mutableStateOf(SettingsState())
12 | var state: MutableState
13 | get() = _settings
14 | private set(value) {
15 | _settings = value
16 | }
17 |
18 | val settings: SettingsState
19 | get() = _settings.value
20 |
21 |
22 | fun init(context: Context) {
23 | state.value = restore(context = context)
24 | }
25 |
26 | fun update(context: Context, settings: SettingsState) {
27 | updateState(settings)
28 | saveToSharedPreferences(settings = settings, context = context)
29 | }
30 |
31 | fun update(context: Context, settings: (SettingsState) -> Unit): Boolean {
32 | val updatedSettings = _settings.value.apply {
33 | settings(_settings.value)
34 | }
35 | updateState(updatedSettings)
36 | saveToSharedPreferences(settings = updatedSettings, context = context)
37 | return true
38 | }
39 |
40 | private fun updateState(settings: SettingsState) {
41 | _settings.value = settings
42 | }
43 |
44 | private fun saveToSharedPreferences(
45 | settings: SettingsState,
46 | context: Context
47 | ) {
48 | val storedUiThemeString = Gson().toJson(settings, SettingsState::class.java)
49 | val store = context.getSharedPreferences(ApplicationStorageName, Context.MODE_PRIVATE)
50 | store.edit().putString(ApplicationSettings, storedUiThemeString.toString()).apply()
51 | }
52 |
53 | private fun restore(context: Context): SettingsState {
54 | val store = context.getSharedPreferences(ApplicationStorageName, Context.MODE_PRIVATE)
55 | val savedSettings = store.getString(ApplicationSettings, "")
56 | return if (savedSettings.isNullOrEmpty()) {
57 | SettingsState()
58 | } else {
59 | try {
60 | Gson().fromJson(savedSettings, SettingsState::class.java)
61 | } catch (e: Exception) {
62 | SettingsState()
63 | }
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/util/settings/SettingsState.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.util.settings
2 |
3 | import androidx.annotation.Keep
4 | import com.jobik.shkiper.database.models.NotificationColor
5 | import com.jobik.shkiper.database.models.NotificationIcon
6 | import com.jobik.shkiper.ui.theme.CustomThemeStyle
7 | import java.util.Locale
8 |
9 | @Keep
10 | enum class NightMode {
11 | Light,
12 | Dark,
13 | System,
14 | }
15 |
16 | @Keep
17 | data class SettingsState(
18 | val fontScale: Float = 1f,
19 | val checkUpdates: Boolean = true,
20 | val secureMode: Boolean = false,
21 | val nightMode: NightMode = NightMode.System,
22 | val theme: CustomThemeStyle = CustomThemeStyle.MaterialDynamicColors,
23 | val defaultNotificationIcon: NotificationIcon = NotificationIcon.EVENT,
24 | val defaultNotificationColor: NotificationColor = NotificationColor.MATERIAL,
25 | val localization: Localization = defaultLocalization()
26 | )
27 |
28 | private fun defaultLocalization() = Localization.entries.find {
29 | (Locale.getDefault().language.equals(
30 | Locale(it.name).language
31 | ))
32 | } ?: Localization.EN
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/widgets/WidgetKeys.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.widgets
2 |
3 | import androidx.annotation.Keep
4 | import androidx.datastore.preferences.core.stringPreferencesKey
5 | import androidx.glance.action.ActionParameters
6 |
7 | @Keep
8 | object WidgetKeys {
9 | object Prefs {
10 | val noteId = stringPreferencesKey("noteId")
11 | val noteHeader = stringPreferencesKey("noteHeader")
12 | val noteBody = stringPreferencesKey("noteBody")
13 | val noteLastUpdate = stringPreferencesKey("noteLastUpdate")
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/widgets/handlers/NotesHandler.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.widgets.handlers
2 |
3 | import android.app.PendingIntent
4 | import android.content.Context
5 | import android.content.Intent
6 | import androidx.datastore.preferences.core.Preferences
7 | import androidx.glance.appwidget.GlanceAppWidgetManager
8 | import androidx.glance.appwidget.state.updateAppWidgetState
9 | import androidx.glance.appwidget.updateIf
10 | import com.jobik.shkiper.SharedPreferencesKeys
11 | import com.jobik.shkiper.database.models.Note
12 | import com.jobik.shkiper.helpers.TextHelper
13 | import com.jobik.shkiper.widgets.WidgetKeys
14 | import com.jobik.shkiper.widgets.WidgetKeys.Prefs.noteId
15 | import com.jobik.shkiper.widgets.services.NoteWidgetReceiver
16 | import com.jobik.shkiper.widgets.services.PinWidgetReceiver
17 | import com.jobik.shkiper.widgets.widgets.NoteWidget
18 | import com.mohamedrejeb.richeditor.model.RichTextState
19 | import org.mongodb.kbson.ObjectId
20 |
21 | suspend fun handleNoteWidgetPin(context: Context, noteId: String) {
22 | val intent = Intent(context, PinWidgetReceiver::class.java)
23 | intent.putExtra(SharedPreferencesKeys.NoteIdExtra, noteId)
24 | val pendingIntent = PendingIntent.getBroadcast(
25 | context,
26 | ObjectId(noteId).timestamp,
27 | intent,
28 | PendingIntent.FLAG_IMMUTABLE
29 | )
30 | GlanceAppWidgetManager(context).requestPinGlanceAppWidget(
31 | NoteWidgetReceiver::class.java,
32 | successCallback = pendingIntent
33 | )
34 | }
35 |
36 | suspend fun GlanceAppWidgetManager.mapNoteToWidget(context: Context, note: Note) =
37 | getGlanceIds(NoteWidget::class.java)
38 | .forEach { glanceId ->
39 | updateAppWidgetState(context, glanceId) { prefs ->
40 | if (prefs[noteId] == note._id.toHexString()) {
41 | val richBody = RichTextState()
42 | richBody.setHtml(note.body)
43 |
44 | prefs[WidgetKeys.Prefs.noteHeader] = note.header
45 | prefs[WidgetKeys.Prefs.noteBody] = TextHelper.removeMarkdownStyles(richBody.toMarkdown())
46 | prefs[WidgetKeys.Prefs.noteLastUpdate] = note.updateDateString
47 | NoteWidget().update(context, glanceId)
48 | }
49 | }
50 | NoteWidget().updateIf(context) {
51 | it[noteId] == note._id.toHexString()
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/widgets/services/NoteWidgetReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.widgets.services
2 |
3 | import androidx.glance.appwidget.GlanceAppWidget
4 | import androidx.glance.appwidget.GlanceAppWidgetReceiver
5 | import com.jobik.shkiper.widgets.widgets.NoteWidget
6 |
7 | class NoteWidgetReceiver : GlanceAppWidgetReceiver() {
8 | override val glanceAppWidget: GlanceAppWidget = NoteWidget()
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/jobik/shkiper/widgets/widgets/NoteWidget.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper.widgets.widgets
2 |
3 | import android.content.Context
4 | import androidx.datastore.preferences.core.Preferences
5 | import androidx.glance.GlanceId
6 | import androidx.glance.appwidget.GlanceAppWidget
7 | import androidx.glance.appwidget.provideContent
8 | import androidx.glance.currentState
9 | import androidx.glance.state.GlanceStateDefinition
10 | import androidx.glance.state.PreferencesGlanceStateDefinition
11 | import com.jobik.shkiper.widgets.components.NoteWidgetContent
12 |
13 | class NoteWidget : GlanceAppWidget() {
14 |
15 | override var stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition
16 |
17 | override suspend fun provideGlance(context: Context, id: GlanceId) {
18 | // In this method, load data needed to render the AppWidget.
19 | // Use `withContext` to switch to another thread for long running
20 | // operations.
21 |
22 | provideContent {
23 | val prefs = currentState()
24 | NoteWidgetContent(prefs)
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/note_widget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/drawable-night/note_widget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/add_link_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/close_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_align_center_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_align_left_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_align_right_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_bold_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_clear_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_color_fill_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_color_text_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_h1_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_h2_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_h3_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_italic_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_list_bulleted_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_list_numbered_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_strikethrough_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/format_underlined_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_btc.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bug.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_eth.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
15 |
19 |
24 |
28 |
33 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_github.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_mail.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_telegram.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_usdt.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/match_case_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/note_widget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/drawable/note_widget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_celebration.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_event.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_fitness.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_flag.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_pill.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_travel.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_warning.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notification_ic_work.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/photo_my_favorite_cat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/drawable/photo_my_favorite_cat.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/redo_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/terminal_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/three_stars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/drawable/three_stars.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/two_phones_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/drawable/two_phones_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/undo_fill0_wght400_grad0_opsz24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_preview_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_avocado_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_avocado_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_blueberry_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_blueberry_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_classic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_classic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_classic_white_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_classic_white_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_love_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_love_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_mango_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_mango_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_material_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_material_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_money_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_money_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_night_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_night_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_plum_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_plum_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_rocket_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_rocket_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_star_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_star_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_strawberry_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_strawberry_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_avocado_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_avocado_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_avocado_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_avocado_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_blueberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_blueberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_blueberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_blueberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_classic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_classic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_classic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_classic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_classic_white_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_classic_white_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_classic_white_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_classic_white_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_love_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_love_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_love_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_love_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_mango_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_mango_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_mango_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_mango_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_material_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_material_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_material_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_material_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_money_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_money_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_money_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_money_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_night_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_night_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_night_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_night_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_plum_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_plum_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_plum_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_plum_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_rocket_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_rocket_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_rocket_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_rocket_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_star_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_star_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_star_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_star_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_strawberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_strawberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_strawberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-hdpi/ic_strawberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_avocado_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_avocado_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_avocado_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_avocado_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_blueberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_blueberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_blueberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_blueberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_classic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_classic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_classic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_classic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_classic_white_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_classic_white_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_classic_white_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_classic_white_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_love_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_love_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_love_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_love_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_mango_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_mango_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_mango_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_mango_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_material_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_material_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_material_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_material_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_money_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_money_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_money_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_money_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_night_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_night_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_night_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_night_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_plum_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_plum_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_plum_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_plum_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_rocket_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_rocket_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_rocket_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_rocket_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_star_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_star_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_star_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_star_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_strawberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_strawberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_strawberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-mdpi/ic_strawberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_avocado_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_avocado_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_avocado_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_avocado_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_blueberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_blueberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_blueberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_blueberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_classic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_classic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_classic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_classic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_classic_white_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_classic_white_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_classic_white_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_classic_white_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_love_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_love_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_love_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_love_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_mango_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_mango_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_mango_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_mango_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_material_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_material_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_material_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_material_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_money_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_money_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_money_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_money_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_night_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_night_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_night_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_night_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_plum_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_plum_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_plum_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_plum_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_rocket_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_rocket_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_rocket_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_rocket_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_star_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_star_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_star_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_star_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_strawberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_strawberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_strawberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xhdpi/ic_strawberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_avocado_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_avocado_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_avocado_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_avocado_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_blueberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_blueberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_blueberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_blueberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_classic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_classic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_classic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_classic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_classic_white_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_classic_white_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_classic_white_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_classic_white_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_love_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_love_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_love_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_love_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_mango_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_mango_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_mango_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_mango_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_material_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_material_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_material_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_material_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_money_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_money_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_money_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_money_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_night_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_night_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_night_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_night_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_plum_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_plum_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_plum_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_plum_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_rocket_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_rocket_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_rocket_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_rocket_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_star_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_star_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_star_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_star_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_strawberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_strawberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_strawberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxhdpi/ic_strawberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_avocado_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_avocado_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_avocado_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_avocado_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_blueberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_blueberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_blueberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_blueberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_classic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_classic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_classic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_classic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_classic_white_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_classic_white_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_classic_white_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_classic_white_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_love_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_love_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_love_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_love_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_mango_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_mango_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_mango_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_mango_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_material_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_material_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_material_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_material_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_money_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_money_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_money_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_money_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_night_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_night_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_night_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_night_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_plum_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_plum_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_plum_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_plum_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_rocket_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_rocket_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_rocket_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_rocket_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_star_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_star_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_star_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_star_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_strawberry_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_strawberry_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_strawberry_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/app/src/main/res/mipmap-xxxhdpi/ic_strawberry_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night-v31/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:color/system_accent2_800
4 | @android:color/system_accent1_100
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #0B0B0B
4 | #242424
5 | #242424
6 | #F6F6F6
7 | #DBDBDB
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v31/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:color/system_accent1_100
4 | @android:color/system_accent1_700
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #212121
5 | #FFFFFF
6 | #0F0F0F
7 | #313131
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_avocado_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_blackberries_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_blueberry_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_classic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_classic_white_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_material_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_love_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_mango_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_material_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/primary
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_money_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_night_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_plum_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_rocket_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_star_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_strawberry_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/splash_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
13 |
14 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/note_widget_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_path.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/test/java/com/jobik/shkiper/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.jobik.shkiper
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/assets/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/assets/banner.png
--------------------------------------------------------------------------------
/assets/ic_night_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/assets/ic_night_launcher.png
--------------------------------------------------------------------------------
/assets/icon-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/assets/icon-app.png
--------------------------------------------------------------------------------
/assets/phones.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/assets/phones.png
--------------------------------------------------------------------------------
/assets/screenshots_mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/assets/screenshots_mobile.png
--------------------------------------------------------------------------------
/baselineProfile/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/baselineProfile/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.android.test)
3 | alias(libs.plugins.jetbrains.kotlin.android)
4 | alias(libs.plugins.baselineprofile)
5 | }
6 |
7 | android {
8 | namespace = "com.tech.shkiper.baselineprofile"
9 | compileSdk = libs.versions.androidCompileSdk.get().toIntOrNull()
10 |
11 | compileOptions {
12 | sourceCompatibility = JavaVersion.toVersion(libs.versions.jvmTarget.get())
13 | targetCompatibility = JavaVersion.toVersion(libs.versions.jvmTarget.get())
14 | }
15 |
16 | kotlinOptions {
17 | jvmTarget = libs.versions.jvmTarget.get()
18 | }
19 |
20 | defaultConfig {
21 | minSdk = 28
22 | targetSdk = libs.versions.androidCompileSdk.get().toIntOrNull()
23 |
24 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
25 | }
26 |
27 | targetProjectPath = ":app"
28 |
29 | }
30 |
31 | // This is the configuration block for the Baseline Profile plugin.
32 | // You can specify to run the generators on a managed devices or connected devices.
33 | baselineProfile {
34 | useConnectedDevices = true
35 | }
36 |
37 | dependencies {
38 | implementation(libs.androidx.junit)
39 | implementation(libs.androidx.espresso.core)
40 | implementation(libs.androidx.uiautomator)
41 | implementation(libs.androidx.benchmark.macro.junit4)
42 | }
43 |
44 | androidComponents {
45 | onVariants { v ->
46 | val artifactsLoader = v.artifacts.getBuiltArtifactsLoader()
47 | v.instrumentationRunnerArguments.put(
48 | "targetAppId",
49 | v.testedApks.map { artifactsLoader.load(it)?.applicationId }
50 | )
51 | }
52 | }
--------------------------------------------------------------------------------
/baselineProfile/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/build-logic/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /app/release
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | /.idea
--------------------------------------------------------------------------------
/build-logic/convention/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /app/release
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | /.idea
--------------------------------------------------------------------------------
/build-logic/convention/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | plugins {
4 | `kotlin-dsl`
5 | }
6 |
7 | group = "com.efim.shkiper.buildlogic"
8 |
9 | // Configure the build-logic plugins to target JDK
10 | val javaVersion = JavaVersion.toVersion(libs.versions.jvmTarget.get())
11 |
12 | java {
13 | sourceCompatibility = javaVersion
14 | targetCompatibility = javaVersion
15 | }
16 |
17 | tasks.withType().configureEach {
18 | kotlinOptions {
19 | jvmTarget = javaVersion.toString()
20 | }
21 | }
22 |
23 | dependencies {
24 | compileOnly(libs.agp.gradle)
25 | compileOnly(libs.kotlin.gradle)
26 | compileOnly(libs.detekt.gradle)
27 | }
28 |
29 | gradlePlugin {
30 | // register the convention plugin
31 | plugins {
32 | register("shkiperLibraryPlugin") {
33 | id = "efim.shkiper.library"
34 | implementationClass = "ShkiperLibraryPlugin"
35 | }
36 | register("shkiperLibraryHilt") {
37 | id = "efim.shkiper.hilt"
38 | implementationClass = "ShkiperLibraryHiltPlugin"
39 | }
40 | register("shkiperLibraryCompose") {
41 | id = "efim.shkiper.compose"
42 | implementationClass = "ShkiperComposeLibraryPlugin"
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/ShkiperComposeLibraryPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.api.dsl.LibraryExtension
2 | import com.efim.shkiper.configureCompose
3 | import convention.src.main.kotlin.src.efim.shkiper.libs
4 | import org.gradle.api.Plugin
5 | import org.gradle.api.Project
6 | import org.gradle.kotlin.dsl.configure
7 | import org.gradle.kotlin.dsl.dependencies
8 | import org.gradle.kotlin.dsl.withType
9 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
10 |
11 | @Suppress("UNUSED")
12 | class ShkiperComposeLibraryPlugin : Plugin {
13 | override fun apply(target: Project) {
14 | with(target) {
15 | dependencies {
16 | "implementation"(libs.findLibrary("androidx.material3").get())
17 | "implementation"(libs.findLibrary("androidx.material.icons.extended").get())
18 | }
19 |
20 | extensions.configure {
21 | configureCompose(this)
22 | }
23 |
24 | tasks.withType {
25 | compilerOptions.freeCompilerArgs.addAll(
26 | "-P",
27 | "plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true",
28 | )
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/ShkiperLibraryHiltPlugin.kt:
--------------------------------------------------------------------------------
1 | import convention.src.main.kotlin.src.efim.shkiper.libs
2 | import org.gradle.api.Plugin
3 | import org.gradle.api.Project
4 | import org.gradle.kotlin.dsl.dependencies
5 |
6 | @Suppress("UNUSED")
7 | class ShkiperLibraryHiltPlugin : Plugin {
8 | override fun apply(target: Project) {
9 | with(target) {
10 | with(pluginManager) {
11 | apply("dagger.hilt.android.plugin")
12 | apply("org.jetbrains.kotlin.kapt")
13 | }
14 | dependencies {
15 | "implementation"(libs.findLibrary("hilt").get())
16 | "kapt"(libs.findLibrary("dagger.hilt.compiler").get())
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/ShkiperLibraryPlugin.kt:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.LibraryExtension
2 | import convention.src.main.kotlin.com.efim.shkiper.configureDetekt
3 | import convention.src.main.kotlin.com.efim.shkiper.configureKotlinAndroid
4 | import convention.src.main.kotlin.src.efim.shkiper.libs
5 | import io.gitlab.arturbosch.detekt.extensions.DetektExtension
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 | import org.gradle.kotlin.dsl.configure
9 | import org.gradle.kotlin.dsl.getByType
10 |
11 | @Suppress("UNUSED")
12 | class ShkiperLibraryPlugin : Plugin {
13 | override fun apply(target: Project) {
14 |
15 | with(target) {
16 | with(pluginManager) {
17 | apply("com.android.library")
18 | apply("org.jetbrains.kotlin.android")
19 | apply("kotlin-parcelize")
20 |
21 | apply(
22 | libs.findLibrary("detekt-gradle").get().get().group.toString()
23 | )
24 | }
25 |
26 | configureDetekt(extensions.getByType())
27 |
28 | extensions.configure {
29 | configureKotlinAndroid(this)
30 | defaultConfig.minSdk =
31 | libs.findVersion("androidMinSdk").get().toString().toIntOrNull()
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/efim/shkiper/ConfigureCompose.kt:
--------------------------------------------------------------------------------
1 | package com.efim.shkiper
2 |
3 | import com.android.build.api.dsl.CommonExtension
4 | import convention.src.main.kotlin.com.efim.shkiper.kotlinOptions
5 | import convention.src.main.kotlin.src.efim.shkiper.libs
6 | import org.gradle.api.Project
7 |
8 | internal fun Project.configureCompose(
9 | commonExtension: CommonExtension<*, *, *, *, *, *>,
10 | ) {
11 | commonExtension.apply {
12 | buildFeatures {
13 | compose = true
14 | }
15 |
16 | composeOptions {
17 | kotlinCompilerExtensionVersion = libs.findVersion("compose.compiler").get().toString()
18 | }
19 |
20 | kotlinOptions {
21 | freeCompilerArgs += listOf(
22 | "-P",
23 | "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
24 | "${project.rootProject.projectDir.absolutePath}/compose_compiler_config.conf"
25 | )
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/efim/shkiper/ConfigureDetekt.kt:
--------------------------------------------------------------------------------
1 | package convention.src.main.kotlin.com.efim.shkiper
2 |
3 | import convention.src.main.kotlin.src.efim.shkiper.libs
4 | import io.gitlab.arturbosch.detekt.Detekt
5 | import io.gitlab.arturbosch.detekt.extensions.DetektExtension
6 | import org.gradle.api.Project
7 | import org.gradle.kotlin.dsl.dependencies
8 | import org.gradle.kotlin.dsl.named
9 |
10 | internal fun Project.configureDetekt(extension: DetektExtension) = extension.apply {
11 | tasks.named("detekt") {
12 | reports {
13 | xml.required.set(true)
14 | html.required.set(true)
15 | txt.required.set(true)
16 | sarif.required.set(true)
17 | md.required.set(true)
18 | }
19 | }
20 | dependencies {
21 | "detektPlugins"(libs.findLibrary("detekt-formatting").get())
22 | "detektPlugins"(libs.findLibrary("detekt-compose").get())
23 | }
24 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/efim/shkiper/ProjectExtensions.kt:
--------------------------------------------------------------------------------
1 | package convention.src.main.kotlin.src.efim.shkiper
2 |
3 | import org.gradle.api.artifacts.VersionCatalog
4 | import org.gradle.api.artifacts.VersionCatalogsExtension
5 | import org.gradle.api.Project
6 | import org.gradle.kotlin.dsl.getByType
7 |
8 | val Project.libs
9 | get(): VersionCatalog = extensions.getByType().named("libs")
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | dependencyResolutionManagement {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | }
8 | versionCatalogs {
9 | create("libs") {
10 | from(files("../gradle/libs.versions.toml"))
11 | }
12 | }
13 | }
14 |
15 | rootProject.name = "build-logic"
16 | include(":convention")
17 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | buildscript {
2 | dependencies {
3 | classpath(libs.hilt.gradle)
4 | classpath(libs.realm.gradle.plugin)
5 | classpath(libs.detekt.gradle)
6 | classpath(libs.agp.gradle)
7 | classpath(libs.kotlin.gradle)
8 | }
9 | }
10 |
11 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
12 | plugins {
13 | id("com.android.application") version "8.7.0-alpha07" apply false
14 | id("com.android.library") version "8.7.0-alpha07" apply false
15 | id("org.jetbrains.kotlin.android") version "1.9.24" apply false
16 | id("io.realm.kotlin") version "1.16.0" apply false
17 | id("com.google.devtools.ksp") version "1.9.24-1.0.20" apply false
18 | id("com.google.dagger.hilt.android") version "2.51.1" apply false
19 | id("com.android.test") version "8.7.0-alpha07" apply false
20 | alias(libs.plugins.baselineprofile) apply false
21 | }
22 |
23 | tasks.register("clean", Delete::class) {
24 | delete(rootProject.layout.buildDirectory)
25 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 | # android.defaults.buildfeatures.buildconfig=true
25 | android.nonFinalResIds=false
26 | org.gradle.configuration-cache=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Efimj/Shkiper/0cd6135cfd4e0a199fae09e2aed51736e33feeaf/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jul 05 22:05:09 EEST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | include(":baselineprofile")
4 |
5 | pluginManagement {
6 | repositories {
7 | includeBuild("build-logic")
8 | google()
9 | mavenCentral()
10 | gradlePluginPortal()
11 | }
12 | }
13 |
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | maven { url = uri("https://jitpack.io") }
20 | }
21 | }
22 |
23 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
24 |
25 | rootProject.name = "Shkiper"
26 |
27 | include(":app")
28 |
29 |
--------------------------------------------------------------------------------