├── .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 | [Download from Google Play](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 | withBuy Me A Coffee -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------