├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── compiler.xml
├── encodings.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── jarRepositories.xml
├── kotlinc.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── objectbox-models
│ ├── default.json
│ └── default.json.bak
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ └── com
│ │ └── louiskirsch
│ │ └── quickdynalist
│ │ ├── AdvancedItemActivity.kt
│ │ ├── BaseItemListFragment.kt
│ │ ├── DetailsActivity.kt
│ │ ├── DialogSetupFragment.kt
│ │ ├── Dynalist.kt
│ │ ├── DynalistApp.kt
│ │ ├── DynalistLinkSpan.kt
│ │ ├── DynalistTagSpan.kt
│ │ ├── EditFilterActivity.kt
│ │ ├── Events.kt
│ │ ├── FilteredItemListFragment.kt
│ │ ├── InboxConfigurationFragment.kt
│ │ ├── InsertBarFragment.kt
│ │ ├── ItemListFragment.kt
│ │ ├── Location.kt
│ │ ├── LoginFragment.kt
│ │ ├── MainActivity.kt
│ │ ├── NavigationActivity.kt
│ │ ├── OnLinkTouchListener.kt
│ │ ├── ProcessTextActivity.kt
│ │ ├── QuickDialogTileService.kt
│ │ ├── SearchActivity.kt
│ │ ├── SettingsActivity.kt
│ │ ├── ShortcutActivity.kt
│ │ ├── SyncShortcutActivity.kt
│ │ ├── SyncStatusFragment.kt
│ │ ├── TagManagerFragment.kt
│ │ ├── ViewModels.kt
│ │ ├── WizardActivity.kt
│ │ ├── adapters
│ │ ├── EmojiAdapter.kt
│ │ ├── FilterAdapter.kt
│ │ ├── FilterItemListAdapter.kt
│ │ ├── ItemListAdapter.kt
│ │ ├── ItemTouchCallback.kt
│ │ ├── SectionedAdapter.kt
│ │ └── SwipeBackgroundDrawer.kt
│ │ ├── jobs
│ │ ├── AddItemJob.kt
│ │ ├── BulkEditItemJob.kt
│ │ ├── CloneItemJob.kt
│ │ ├── DeleteItemJob.kt
│ │ ├── EditItemJob.kt
│ │ ├── Exceptions.kt
│ │ ├── ItemJob.kt
│ │ ├── JobService.kt
│ │ ├── MoveItemJob.kt
│ │ ├── SyncJob.kt
│ │ └── VerifyTokenJob.kt
│ │ ├── network
│ │ ├── AddItemTreeService.kt
│ │ └── DynalistService.kt
│ │ ├── objectbox
│ │ ├── DocumentTreeNode.kt
│ │ ├── DynalistDocument.kt
│ │ ├── DynalistFolder.kt
│ │ ├── DynalistItem.kt
│ │ ├── DynalistItemFilter.kt
│ │ ├── DynalistItemMetaData.kt
│ │ ├── DynalistTag.kt
│ │ ├── Exceptions.kt
│ │ ├── SubscriberOBLiveData.kt
│ │ └── TransformedOBLiveData.kt
│ │ ├── text
│ │ ├── EnhancedMovementMethod.kt
│ │ ├── IndentedBulletSpan.kt
│ │ ├── ThemedSpan.kt
│ │ └── TintedImageSpan.kt
│ │ ├── utils
│ │ ├── DynalistEditActionHelper.kt
│ │ ├── EmojiFactory.kt
│ │ ├── Extensions.kt
│ │ ├── ImageCache.kt
│ │ └── SpeechRecognitionHelper.kt
│ │ ├── views
│ │ ├── BottomBarScrollingViewBehavior.kt
│ │ ├── MoveUpwardBehavior.kt
│ │ ├── NestedCoordinatorLayout.kt
│ │ ├── ScrollFABBehavior.kt
│ │ └── SquareImageView.kt
│ │ └── widget
│ │ ├── ListAppWidget.kt
│ │ ├── ListAppWidgetConfigurationReceiver.kt
│ │ ├── ListAppWidgetConfigureActivity.kt
│ │ └── ListAppWidgetService.kt
│ └── res
│ ├── drawable-night
│ ├── dashed_border.xml
│ └── dashed_border_activated.xml
│ ├── drawable-nodpi
│ └── appwidget_preview.png
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── activatable_selectable_background.xml
│ ├── circular_progress_bar.xml
│ ├── dashed_border.xml
│ ├── dashed_border_activated.xml
│ ├── dropoff_background.xml
│ ├── ic_action_advanced_item.xml
│ ├── ic_action_change_color.xml
│ ├── ic_action_clear.xml
│ ├── ic_action_create_filter.xml
│ ├── ic_action_create_shortcut.xml
│ ├── ic_action_date.xml
│ ├── ic_action_details.xml
│ ├── ic_action_discard.xml
│ ├── ic_action_duplicate.xml
│ ├── ic_action_edit.xml
│ ├── ic_action_edit_filter.xml
│ ├── ic_action_goto_parent.xml
│ ├── ic_action_help.xml
│ ├── ic_action_item_list.xml
│ ├── ic_action_jump_to_bottom.xml
│ ├── ic_action_link.xml
│ ├── ic_action_manage_tags.xml
│ ├── ic_action_more.xml
│ ├── ic_action_move.xml
│ ├── ic_action_move_inbox.xml
│ ├── ic_action_open_large.xml
│ ├── ic_action_open_settings.xml
│ ├── ic_action_rate_quickdynalist.xml
│ ├── ic_action_record_speech.xml
│ ├── ic_action_search.xml
│ ├── ic_action_search_white.xml
│ ├── ic_action_send_bug_report.xml
│ ├── ic_action_send_item.xml
│ ├── ic_action_share.xml
│ ├── ic_action_share_quickdynalist.xml
│ ├── ic_action_show_image.xml
│ ├── ic_action_show_text.xml
│ ├── ic_action_sync.xml
│ ├── ic_backward_link.xml
│ ├── ic_chip_add.xml
│ ├── ic_folder.xml
│ ├── ic_folder_open.xml
│ ├── ic_folder_stateful.xml
│ ├── ic_forward_link.xml
│ ├── ic_launcher_background.xml
│ ├── ic_shortcut_quick_dialog_foreground.xml
│ ├── ic_shortcut_record_speech_foreground.xml
│ ├── ic_shortcut_search_item_foreground.xml
│ ├── ic_shortcut_sync_foreground.xml
│ ├── ic_shortcut_type_dialog.xml
│ ├── ic_shortcut_type_list.xml
│ ├── ic_swipe_delete.xml
│ ├── ic_swipe_edit.xml
│ ├── ic_tile_quick_dialog.xml
│ ├── item_color_picker.xml
│ └── side_nav_bar.xml
│ ├── layout-w900dp
│ └── activity_navigation.xml
│ ├── layout
│ ├── activity_advanced_item.xml
│ ├── activity_auth.xml
│ ├── activity_details.xml
│ ├── activity_edit_filter.xml
│ ├── activity_main.xml
│ ├── activity_navigation.xml
│ ├── activity_search.xml
│ ├── activity_settings.xml
│ ├── activity_shortcut.xml
│ ├── activity_wizard.xml
│ ├── app_bar_navigation.xml
│ ├── dropdown_menu_popup_item.xml
│ ├── emoji_list_item.xml
│ ├── fragment_dialog_setup.xml
│ ├── fragment_inbox_configuration.xml
│ ├── fragment_insert_bar.xml
│ ├── fragment_item_list.xml
│ ├── fragment_login.xml
│ ├── fragment_sync_status.xml
│ ├── fragment_tag_manager.xml
│ ├── item_list_dropoff.xml
│ ├── item_list_item.xml
│ ├── list_app_widget.xml
│ ├── list_app_widget_configure.xml
│ ├── list_app_widget_item.xml
│ ├── list_separator.xml
│ ├── menu_color_picker.xml
│ ├── nav_header_navigation.xml
│ └── search_list_item.xml
│ ├── menu
│ ├── activity_details.xml
│ ├── activity_edit_filter.xml
│ ├── activity_list_app_widget_configure.xml
│ ├── activity_navigation_drawer.xml
│ ├── activity_shortcut.xml
│ ├── advanced_item_activity_menu.xml
│ ├── filter_item_list_menu.xml
│ ├── item_list_activity_menu.xml
│ ├── item_list_popup_image_extension.xml
│ ├── item_list_popup_menu.xml
│ ├── item_text_insert_context_menu.xml
│ ├── item_text_selection_context_menu.xml
│ ├── navigation.xml
│ └── quick_dialog_menu.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ ├── ic_launcher_round.xml
│ ├── ic_shortcut_quick_dialog.xml
│ ├── ic_shortcut_quick_dialog_round.xml
│ ├── ic_shortcut_record_speech.xml
│ ├── ic_shortcut_record_speech_round.xml
│ ├── ic_shortcut_search_item.xml
│ ├── ic_shortcut_search_item_round.xml
│ ├── ic_shortcut_sync.xml
│ └── ic_shortcut_sync_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ ├── ic_launcher_round.png
│ ├── ic_shortcut_quick_dialog.png
│ ├── ic_shortcut_quick_dialog_round.png
│ ├── ic_shortcut_record_speech.png
│ ├── ic_shortcut_record_speech_round.png
│ ├── ic_shortcut_search_item.png
│ ├── ic_shortcut_search_item_round.png
│ ├── ic_shortcut_sync.png
│ └── ic_shortcut_sync_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ ├── ic_launcher_round.png
│ ├── ic_shortcut_quick_dialog.png
│ ├── ic_shortcut_quick_dialog_round.png
│ ├── ic_shortcut_record_speech.png
│ ├── ic_shortcut_record_speech_round.png
│ ├── ic_shortcut_search_item.png
│ ├── ic_shortcut_search_item_round.png
│ ├── ic_shortcut_sync.png
│ └── ic_shortcut_sync_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ ├── ic_launcher_round.png
│ ├── ic_shortcut_quick_dialog.png
│ ├── ic_shortcut_quick_dialog_round.png
│ ├── ic_shortcut_record_speech.png
│ ├── ic_shortcut_record_speech_round.png
│ ├── ic_shortcut_search_item.png
│ ├── ic_shortcut_search_item_round.png
│ ├── ic_shortcut_sync.png
│ └── ic_shortcut_sync_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ ├── ic_launcher_round.png
│ ├── ic_shortcut_quick_dialog.png
│ ├── ic_shortcut_quick_dialog_round.png
│ ├── ic_shortcut_record_speech.png
│ ├── ic_shortcut_record_speech_round.png
│ ├── ic_shortcut_search_item.png
│ ├── ic_shortcut_search_item_round.png
│ ├── ic_shortcut_sync.png
│ └── ic_shortcut_sync_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ ├── ic_launcher_round.png
│ ├── ic_shortcut_quick_dialog.png
│ ├── ic_shortcut_quick_dialog_round.png
│ ├── ic_shortcut_record_speech.png
│ ├── ic_shortcut_record_speech_round.png
│ ├── ic_shortcut_search_item.png
│ ├── ic_shortcut_search_item_round.png
│ ├── ic_shortcut_sync.png
│ └── ic_shortcut_sync_round.png
│ ├── raw
│ └── dialog_tutorial.webm
│ ├── transition
│ ├── change_view_bounds.xml
│ └── window_explode.xml
│ ├── values-night
│ ├── colors.xml
│ ├── styles.xml
│ └── widget.xml
│ ├── values-v28
│ └── preferences.xml
│ ├── values-w900dp
│ ├── dimens.xml
│ └── styles.xml
│ ├── values
│ ├── actions.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── ic_launcher_background.xml
│ ├── ic_shortcut_background.xml
│ ├── ic_shortcut_quick_dialog_background.xml
│ ├── ids.xml
│ ├── preferences.xml
│ ├── request_codes.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── widget.xml
│ └── xml
│ ├── chip.xml
│ ├── file_paths.xml
│ ├── list_app_widget_info.xml
│ ├── preferences.xml
│ └── shortcuts.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── hashkode
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── nl
│ └── pvdberg
│ └── hashkode
│ ├── Difference.kt
│ ├── Equals.kt
│ ├── HashKode.kt
│ ├── HashKodeContext.kt
│ └── Hashing.kt
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/android
3 |
4 | ### Android ###
5 | # Built application files
6 | *.apk
7 | *.ap_
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | .idea/caches
48 |
49 | # Keystore files
50 | # Uncomment the following line if you do not want to check your keystore files in.
51 | #*.jks
52 |
53 | # External native build folder generated in Android Studio 2.2 and later
54 | .externalNativeBuild
55 |
56 | # Google Services (e.g. APIs or Firebase)
57 | google-services.json
58 |
59 | # Freeline
60 | freeline.py
61 | freeline/
62 | freeline_project_description.json
63 |
64 | # fastlane
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 | fastlane/readme.md
70 |
71 | ### Android Patch ###
72 | gen-external-apklibs
73 |
74 |
75 | # End of https://www.gitignore.io/api/android
76 |
77 | app/release
78 | .DS_Store
79 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QuickDynalist
2 |
3 | Quick Dynalist is an independent open-source client for [Dynalist](https://dynalist.io/) (an enhanced [Workflowy](https://workflowy.com/)).
4 | Its focus is on providing rapid access to any part of your Dynalist database via shortcuts, widgets, and other deep integrations into Android.
5 | New items should be added with as little overhead as possible to make Dynalist a true extension to your brain.
6 | We also provide an extremly responsive native experience optimized for the Android platform.
7 |
8 |
9 |
10 |
11 |
12 | ## Features
13 |
14 | Dynalist is the best place for all of your todos, ideas, and notes.
15 | Quick Dynalist transforms your mobile phone into your extended memory: See your lists, add & edit new items amazingly fast, search & filter for anything.
16 |
17 | This app requires a Dynalist account: http://dynalist.io
18 |
19 | - A much faster experience compared to the original Dynalist App
20 | - Quickly add items anywhere using shortcuts and widgets
21 | - Quickly share text, URLs, and more to your inbox
22 | - Even works offline
23 | - Use the Google Assistant "Add a note" or "Note to myself"
24 | - Browse & edit the contents of your different inboxes and documents
25 | - Create permanent filters that show you exactly what you need across your Dynalist
26 | - Create shortcuts to jump directly to a specific location
27 | - Create widgets to see exactly what you need right from your homescreen
28 | - Share your favorite list with other apps and people.
29 | Add new items to dynalist quickly (native android app)
30 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | apply plugin: 'kotlin-android-extensions'
5 | apply plugin: 'kotlin-kapt'
6 | apply plugin: 'io.objectbox'
7 |
8 | android {
9 | compileSdk 33
10 | defaultConfig {
11 | applicationId "com.louiskirsch.quickdynalist"
12 | minSdkVersion 21
13 | targetSdkVersion 33
14 | versionCode 55
15 | versionName "2.10.1"
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_17
26 | targetCompatibility JavaVersion.VERSION_17
27 | }
28 | namespace 'com.louiskirsch.quickdynalist'
29 | }
30 |
31 | dependencies {
32 | def lifecycle_version = "2.0.0"
33 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
34 | implementation 'org.jetbrains.anko:anko-commons:0.10.7'
35 | implementation fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
37 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
38 | implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
39 | testImplementation 'junit:junit:4.12'
40 | androidTestImplementation 'androidx.test:runner:1.1.1'
41 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
42 | // implementation 'org.jetbrains:annotations-java5:16.0.3'
43 | implementation 'com.birbit:android-priority-jobqueue:2.0.1'
44 | implementation 'org.greenrobot:eventbus:3.1.1'
45 | implementation 'com.squareup.retrofit2:retrofit:2.5.0'
46 | implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
47 | implementation 'com.google.android.material:material:1.1.0-alpha02'
48 | implementation "io.objectbox:objectbox-kotlin:$objectboxVersion"
49 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
50 | implementation "androidx.preference:preference:1.0.0"
51 | implementation 'com.squareup.picasso:picasso:2.71828'
52 | implementation 'com.github.timediv:jlatexmath-android:e661bda'
53 | implementation 'ru.noties:jlatexmath-android-font-cyrillic:0.1.0'
54 | implementation 'ru.noties:jlatexmath-android-font-greek:0.1.0'
55 | implementation project(':hashkode')
56 | }
57 |
58 | configurations {
59 | cleanedAnnotations
60 | compile.exclude group: 'org.jetbrains', module: 'annotations'
61 | }
62 |
63 | repositories {
64 | mavenCentral()
65 | jcenter()
66 | }
67 |
--------------------------------------------------------------------------------
/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.
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 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/DynalistLinkSpan.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.text.style.ClickableSpan
4 | import android.view.View
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import io.objectbox.kotlin.boxFor
7 | import org.greenrobot.eventbus.EventBus
8 |
9 | class DynalistLinkSpan(val item: DynalistItem): ClickableSpan() {
10 |
11 | override fun onClick(widget: View) {
12 | EventBus.getDefault().post(DynalistLocateEvent(item))
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/DynalistTagSpan.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.text.style.ClickableSpan
4 | import android.view.View
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItemFilter
7 | import com.louiskirsch.quickdynalist.objectbox.DynalistTag
8 | import io.objectbox.kotlin.boxFor
9 | import org.greenrobot.eventbus.EventBus
10 |
11 | class DynalistTagSpan(private val tag: DynalistTag): ClickableSpan() {
12 |
13 | override fun onClick(widget: View) {
14 | val filter = DynalistItemFilter().apply {
15 | name = widget.context.getString(R.string.filter_name_tag, tag.fullName)
16 | tags.add(tag)
17 | searchDepth = DynalistItemFilter.MAX_SEARCH_DEPTH
18 | }
19 | EventBus.getDefault().post(DynalistFilterEvent(filter))
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/Events.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.net.Uri
4 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItemFilter
6 |
7 | class AuthenticatedEvent(val success: Boolean)
8 | class ItemEvent(val success: Boolean, val retrying: Boolean = false)
9 | class InboxEvent(val configured: Boolean)
10 | class RateLimitDelay(val delay: Long, val jobTag: String)
11 | class DynalistLocateEvent(val item: DynalistItem)
12 | class DynalistFilterEvent(val filter: DynalistItemFilter)
13 | class ForbiddenImageEvent(val uri: Uri)
14 | class ItemAddedEvent(val item: DynalistItem)
15 |
16 | enum class SyncStatus { RUNNING, NOT_RUNNING, SUCCESS, NO_SUCCESS }
17 | class SyncEvent(val status: SyncStatus, val isManual: Boolean)
18 | class SyncProgressEvent(val progress: Float)
19 |
20 | class NightModeChangedEvent
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/LoginFragment.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 |
4 | import android.os.Bundle
5 | import android.text.Editable
6 | import android.text.TextWatcher
7 | import androidx.fragment.app.Fragment
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import com.louiskirsch.quickdynalist.jobs.SyncJob
12 | import com.louiskirsch.quickdynalist.jobs.VerifyTokenJob
13 | import kotlinx.android.synthetic.main.fragment_login.*
14 | import org.greenrobot.eventbus.EventBus
15 | import org.greenrobot.eventbus.Subscribe
16 | import org.greenrobot.eventbus.ThreadMode
17 | import org.jetbrains.anko.browse
18 | import org.jetbrains.anko.toast
19 |
20 | class LoginFragment : Fragment() {
21 |
22 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
23 | savedInstanceState: Bundle?): View? {
24 | return inflater.inflate(R.layout.fragment_login, container, false)
25 |
26 | }
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 | auth_open_browser.setOnClickListener {
31 | context!!.browse("https://dynalist.io/developer")
32 | }
33 | auth_submit_token.isEnabled = false
34 | auth_submit_token.setOnClickListener {
35 | val token = auth_token.text.toString()
36 | val jobManager = DynalistApp.instance.jobManager
37 | val job = VerifyTokenJob(token)
38 | jobManager.addJobInBackground(job)
39 | auth_submit_token.isEnabled = false
40 | }
41 | auth_token.addTextChangedListener(object : TextWatcher{
42 | override fun afterTextChanged(s: Editable?) {}
43 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
44 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
45 | auth_submit_token.isEnabled = s?.isNotBlank() ?: false
46 | }
47 |
48 | })
49 | val dynalist = Dynalist(context!!)
50 | sync_mobile_data.isChecked = dynalist.syncMobileData
51 | sync_mobile_data.setOnCheckedChangeListener { _, isChecked ->
52 | dynalist.syncMobileData = isChecked
53 | }
54 | }
55 |
56 | override fun onStart() {
57 | super.onStart()
58 | EventBus.getDefault().register(this)
59 | }
60 |
61 | override fun onStop() {
62 | super.onStop()
63 | EventBus.getDefault().unregister(this)
64 | }
65 |
66 | @Subscribe(threadMode = ThreadMode.MAIN)
67 | fun onAuthenticationEvent(event: AuthenticatedEvent) {
68 | if (!event.success) {
69 | auth_token_layout.error = getString(R.string.token_invalid)
70 | } else {
71 | val job = SyncJob(requireUnmeteredNetwork = false, isManual = true)
72 | DynalistApp.instance.jobManager.addJobInBackground(job)
73 | activity!!.supportFragmentManager.beginTransaction().apply {
74 | setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
75 | replace(R.id.fragment_container, SyncStatusFragment())
76 | commit()
77 | }
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/OnLinkTouchListener.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.MotionEvent
5 | import android.view.View
6 | import android.text.style.ClickableSpan
7 | import android.widget.TextView
8 | import android.text.Spannable
9 |
10 |
11 | /**
12 | * Allows TextViews with clickable links while still not handling all touch events
13 | */
14 | class OnLinkTouchListener: View.OnTouchListener {
15 |
16 | @SuppressLint("ClickableViewAccessibility")
17 | override fun onTouch(v: View?, event: MotionEvent?): Boolean {
18 | var ret = false
19 | val text = (v as TextView).text
20 | val stext = Spannable.Factory.getInstance().newSpannable(text)
21 | val action = event!!.action
22 |
23 | if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
24 | var x = event.x
25 | var y = event.y
26 |
27 | x -= v.totalPaddingLeft
28 | y -= v.totalPaddingTop
29 |
30 | x += v.scrollX
31 | y += v.scrollY
32 |
33 | val layout = v.layout
34 | val line = layout.getLineForVertical(y.toInt())
35 | val off = layout.getOffsetForHorizontal(line, x)
36 |
37 | val link = stext.getSpans(off, off, ClickableSpan::class.java)
38 |
39 | if (link.isNotEmpty()) {
40 | if (action == MotionEvent.ACTION_UP) {
41 | link[0].onClick(v)
42 | }
43 | ret = true
44 | }
45 | }
46 | return ret
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/QuickDialogTileService.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.content.Intent
4 | import android.os.Build
5 | import android.service.quicksettings.TileService
6 | import androidx.annotation.RequiresApi
7 |
8 | @RequiresApi(api = Build.VERSION_CODES.N)
9 | class QuickDialogTileService : TileService() {
10 |
11 | private fun showQuickDialog() {
12 | startActivityAndCollapse(Intent(this, MainActivity::class.java).apply {
13 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
14 | addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
15 | })
16 | }
17 |
18 | override fun onClick() {
19 | if (isLocked) {
20 | unlockAndRun { showQuickDialog() }
21 | } else {
22 | showQuickDialog()
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/SearchActivity.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import android.app.Activity
4 | import android.app.ActivityOptions
5 | import android.app.PendingIntent
6 | import android.content.Intent
7 | import androidx.appcompat.app.AppCompatActivity
8 | import android.os.Bundle
9 | import android.os.Parcelable
10 | import android.text.Editable
11 | import android.text.TextWatcher
12 | import androidx.lifecycle.Observer
13 | import androidx.lifecycle.ViewModelProviders
14 | import androidx.recyclerview.widget.LinearLayoutManager
15 | import com.louiskirsch.quickdynalist.adapters.FilterItemListAdapter
16 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
17 | import com.louiskirsch.quickdynalist.utils.fixedFinishAfterTransition
18 | import kotlinx.android.synthetic.main.activity_search.*
19 |
20 | class SearchActivity : AppCompatActivity() {
21 |
22 | companion object {
23 | const val ACTION_SEARCH_DISPLAY_ITEM = "com.louiskirsch.quickdynalist.SEARCH_DISPLAY_ITEM"
24 | }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | setContentView(R.layout.activity_search)
29 | window.allowEnterTransitionOverlap = true
30 |
31 | val adapter = FilterItemListAdapter(this)
32 | searchResults.layoutManager = LinearLayoutManager(this)
33 | searchResults.adapter = adapter
34 |
35 | adapter.onClickListener = { finishWithSelectedItem(it) }
36 |
37 | val model = ViewModelProviders.of(this).get(DynalistItemViewModel::class.java)
38 | model.searchTerm.value = ""
39 | model.searchItemsLiveData.observe(this, Observer {
40 | adapter.updateItems(it)
41 | })
42 |
43 | searchBar.addTextChangedListener(object: TextWatcher {
44 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
45 | override fun afterTextChanged(s: Editable?) {}
46 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
47 | val searchTerm = s.toString().trim()
48 | model.searchTerm.value = searchTerm
49 | adapter.searchTerm = searchTerm
50 | }
51 | })
52 | }
53 |
54 | private fun finishWithSelectedItem(item: DynalistItem) {
55 | val result = Intent().apply {
56 | putExtra(DynalistApp.EXTRA_DISPLAY_ITEM, item as Parcelable)
57 | if (intent.hasExtra("payload")) {
58 | putExtra("payload", intent.getBundleExtra("payload"))
59 | }
60 | }
61 | if (intent.action == ACTION_SEARCH_DISPLAY_ITEM) {
62 | val transition = ActivityOptions.makeSceneTransitionAnimation(
63 | this, toolbar, "toolbar")
64 | val intent = Intent(this, NavigationActivity::class.java)
65 | intent.fillIn(result, 0)
66 | startActivity(intent, transition.toBundle())
67 | } else {
68 | setResult(Activity.RESULT_OK, result)
69 | fixedFinishAfterTransition()
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/SyncShortcutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import com.louiskirsch.quickdynalist.jobs.SyncJob
6 | import org.jetbrains.anko.toast
7 |
8 | class SyncShortcutActivity : AppCompatActivity() {
9 |
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | val dynalist = Dynalist(this)
13 | if (dynalist.isAuthenticated) {
14 | SyncJob.forceSync()
15 | toast(R.string.sync_started)
16 | finish()
17 | } else {
18 | dynalist.authenticate()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/WizardActivity.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import org.jetbrains.anko.toast
6 |
7 | class WizardActivity : AppCompatActivity() {
8 |
9 | companion object {
10 | const val EXTRA_CONFIG_INBOX_ONLY = "EXTRA_CONFIG_INBOX_ONLY"
11 | const val EXTRA_DIALOG_SETUP_ONLY = "EXTRA_DIALOG_SETUP_ONLY"
12 | }
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_wizard)
17 |
18 | if (savedInstanceState == null) {
19 | val fragment = when {
20 | intent.getBooleanExtra(EXTRA_CONFIG_INBOX_ONLY, false) ->
21 | InboxConfigurationFragment.newInstance(finishAfter = true)
22 | intent.getBooleanExtra(EXTRA_DIALOG_SETUP_ONLY, false) ->
23 | DialogSetupFragment()
24 | else -> LoginFragment()
25 | }
26 | supportFragmentManager.beginTransaction()
27 | .add(R.id.fragment_container, fragment).commit()
28 | }
29 | }
30 |
31 | override fun onBackPressed() {
32 | toast(R.string.wizard_not_completed)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/adapters/EmojiAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.adapters
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.TextView
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.louiskirsch.quickdynalist.R
9 | import com.louiskirsch.quickdynalist.utils.EmojiFactory
10 |
11 | class EmojiViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)
12 |
13 | class EmojiAdapter: RecyclerView.Adapter() {
14 |
15 | var selectedPosition: Int = 0
16 | set(value) {
17 | assert(value in 0..(itemCount - 1))
18 | val oldValue = field
19 | field = value
20 | notifyItemChanged(oldValue)
21 | notifyItemChanged(value)
22 | }
23 |
24 | var selectedValue: String
25 | get() = EmojiFactory.getEmojiAt(selectedPosition)
26 | set(value) = EmojiFactory.emojis.indexOf(value).let {
27 | if (it >= 0) selectedPosition = it
28 | }
29 |
30 | init {
31 | setHasStableIds(true)
32 | }
33 |
34 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojiViewHolder {
35 | val inflater = LayoutInflater.from(parent.context)
36 | return EmojiViewHolder(inflater.inflate(R.layout.emoji_list_item,
37 | parent, false) as TextView)
38 | }
39 |
40 | override fun getItemCount(): Int = EmojiFactory.size
41 | override fun getItemId(position: Int): Long = position.toLong()
42 |
43 | override fun onBindViewHolder(holder: EmojiViewHolder, position: Int) {
44 | holder.textView.run {
45 | isActivated = selectedPosition == position
46 | text = EmojiFactory.getEmojiAt(position)
47 | setOnClickListener { selectedPosition = position }
48 | forceLayout()
49 | }
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/adapters/FilterAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.adapters
2 |
3 | import android.content.Context
4 | import android.widget.ArrayAdapter
5 | import android.widget.Filter
6 |
7 | class FilterAdapter(context: Context, resource: Int, objects: MutableList)
8 | : ArrayAdapter(context, resource, objects) {
9 |
10 | private val filterableItems = ArrayList(objects)
11 | private val excludedItems = HashSet()
12 |
13 | fun excludeItem(item: T) {
14 | excludedItems.add(item)
15 | }
16 |
17 | fun includeItem(item: T) {
18 | excludedItems.remove(item)
19 | }
20 |
21 | fun updateFilterableItems(items: List) {
22 | filterableItems.clear()
23 | filterableItems.addAll(items)
24 | clear()
25 | addAll(items)
26 | notifyDataSetChanged()
27 | }
28 |
29 | private val filter = object: Filter() {
30 | override fun performFiltering(constraint: CharSequence?): FilterResults {
31 | val results = FilterResults()
32 | if (constraint != null && constraint.isNotEmpty()) {
33 | val items: List = filterableItems.filter {
34 | it.toString().contains(constraint, true) &&
35 | it !in excludedItems
36 | }
37 | results.values = items
38 | results.count = items.size
39 | } else {
40 | results.values = filterableItems
41 | results.count = filterableItems.size
42 | }
43 | return results
44 | }
45 |
46 | override fun publishResults(constraint: CharSequence?, results: FilterResults) {
47 | val values = results.values as List
48 | clear()
49 | addAll(values)
50 |
51 | if (results.count > 0) {
52 | notifyDataSetChanged()
53 | } else {
54 | notifyDataSetInvalidated()
55 | }
56 | }
57 |
58 | }
59 |
60 | override fun getFilter(): Filter = filter
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/AddItemJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.louiskirsch.quickdynalist.*
4 | import com.louiskirsch.quickdynalist.network.*
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem_
7 | import com.louiskirsch.quickdynalist.widget.ListAppWidget
8 | import io.objectbox.kotlin.query
9 | import io.objectbox.query.QueryBuilder
10 | import org.greenrobot.eventbus.EventBus
11 |
12 |
13 | class AddItemJob(text: String, note: String, val parent: DynalistItem): ItemJob() {
14 |
15 | private val newItem = DynalistItem(parent.serverFileId, parent.serverItemId,
16 | null, text, note)
17 |
18 | override fun addToDatabase() {
19 | val dynalist = Dynalist(applicationContext)
20 | DynalistApp.instance.boxStore.runInTx {
21 | box.get(parent.clientId)?.also { parent ->
22 | newItem.syncJob = id
23 | newItem.position = if (dynalist.addToTopOfList) {
24 | (minPosition(parent.clientId) ?: 1) - 1
25 | } else {
26 | (maxPosition(parent.clientId) ?: -1) + 1
27 | }
28 | newItem.parent.target = parent
29 | newItem.isChecklist = parent.isChecklist
30 | newItem.checkbox = parent.isChecklist
31 | newItem.notifyModified()
32 | box.put(newItem)
33 | }
34 | }
35 | ListAppWidget.notifyItemChanged(applicationContext, newItem)
36 | EventBus.getDefault().post(ItemAddedEvent(newItem))
37 | }
38 |
39 | private fun insertAPIRequest(): DynalistResponse {
40 | val dynalist = Dynalist(applicationContext)
41 | val token = dynalist.token
42 | requireItemId(parent)
43 | val request = InsertItemRequest(parent.serverFileId!!, parent.serverItemId!!,
44 | newItem.name, newItem.note, parent.isChecklist, token!!,
45 | index = dynalist.insertPosition)
46 | return dynalistService.addToDocument(request).execute().body()!!
47 | }
48 |
49 | @Throws(Throwable::class)
50 | override fun onRun() {
51 | val response = insertAPIRequest()
52 | requireSuccess(response)
53 | val newItemId = when (response) {
54 | is InboxItemResponse -> response.node_id
55 | is InsertedItemsResponse -> response.new_node_ids!![0]
56 | else -> throw BackendException("Invalid response - no itemId included")
57 | }
58 | DynalistApp.instance.boxStore.runInTx {
59 | val updatedItem = box.query {
60 | equal(DynalistItem_.syncJob, id, QueryBuilder.StringOrder.CASE_INSENSITIVE)
61 | }.findFirst()?.apply {
62 | syncJob = null
63 | serverItemId = newItemId
64 | }
65 | updatedItem?.let { box.put(it) }
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/BulkEditItemJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.louiskirsch.quickdynalist.*
4 | import com.louiskirsch.quickdynalist.network.*
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem_
7 | import com.louiskirsch.quickdynalist.widget.ListAppWidget
8 | import io.objectbox.kotlin.query
9 | import org.jetbrains.anko.collections.forEachWithIndex
10 | import retrofit2.Response
11 | import java.lang.IllegalArgumentException
12 |
13 |
14 | class BulkEditItemJob(val items: List): ItemJob() {
15 |
16 | init {
17 | require(items.isNotEmpty()) { "Items to edit must not be empty" }
18 | require(items.all { it.serverFileId == items[0].serverFileId }) { "Items mut be in the same file" }
19 | }
20 |
21 | private val serverFileId = items[0].serverFileId!!
22 |
23 | override fun addToDatabase() {
24 | items.forEach { item ->
25 | item.syncJob = id
26 | box.attach(item)
27 | item.notifyModified()
28 | }
29 | box.put(items)
30 | val parents = items.mapNotNull { it.parent.target }.distinct()
31 | if (parents.size == 1)
32 | ListAppWidget.notifyItemChanged(applicationContext, parents[0])
33 | else
34 | items.forEach { ListAppWidget.notifyItemChanged(applicationContext, it) }
35 | }
36 |
37 | @Throws(Throwable::class)
38 | override fun onRun() {
39 | items.forEach { requireItemId(it) }
40 | val token = Dynalist(applicationContext).token
41 | val edits = items.map { item ->
42 | EditItemRequest.EditSpec(item.serverItemId!!, item.name,
43 | item.note, item.isChecked, item.checkbox, item.heading, item.color)
44 | }.toTypedArray()
45 | val request = BulkEditItemRequest(serverFileId, token!!, edits)
46 | val response = dynalistService.editItems(request).execute()
47 | val body = response.body()!!
48 | requireSuccess(body)
49 | markItemsCompleted()
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/CloneItemJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.louiskirsch.quickdynalist.*
4 | import com.louiskirsch.quickdynalist.network.*
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem_
7 | import com.louiskirsch.quickdynalist.widget.ListAppWidget
8 | import io.objectbox.kotlin.query
9 | import io.objectbox.query.Query
10 | import io.objectbox.query.QueryBuilder
11 | import java.util.*
12 |
13 |
14 | class CloneItemJob(val item: DynalistItem): ItemJob() {
15 |
16 | override fun addToDatabase() {
17 | val now = Date()
18 | val dynalist = Dynalist(applicationContext)
19 | DynalistApp.instance.boxStore.runInTx {
20 | box.get(item.clientId)?.let { item ->
21 | item.position = if (dynalist.addToTopOfList) {
22 | (minPosition(item.parent.targetId) ?: 1) - 1
23 | } else {
24 | (maxPosition(item.parent.targetId) ?: -1) + 1
25 | }
26 | if (item.date != null)
27 | item.date = Date()
28 | box.put(cloneRecursively(item, now).apply { syncJob = "$id-root" })
29 | }
30 | }
31 | ListAppWidget.notifyItemChanged(applicationContext, item)
32 | }
33 |
34 | private fun cloneRecursively(item: DynalistItem, time: Date): DynalistItem {
35 | val newChildren = item.children.map {
36 | cloneRecursively(it, time).apply { it.parent.targetId = 0 }
37 | }
38 | item.apply {
39 | clientId = 0
40 | serverItemId = null
41 | syncJob = id
42 | isChecked = false
43 | children.clear()
44 | children.addAll(newChildren)
45 | notifyModified(time)
46 | }
47 | return item
48 | }
49 |
50 | private fun waitForItem(query: Query, timeout: Long = 10000): DynalistItem? {
51 | val start = System.currentTimeMillis()
52 | while (System.currentTimeMillis() < start + timeout) {
53 | val item = query.findFirst()
54 | if (item != null) return item
55 | Thread.sleep(500)
56 | }
57 | return null
58 | }
59 |
60 | @Throws(Throwable::class)
61 | override fun onRun() {
62 | // need to wait for db operations to complete
63 | val item = waitForItem(box.query {
64 | equal(DynalistItem_.syncJob, "$id-root", QueryBuilder.StringOrder.CASE_INSENSITIVE)
65 | }) ?: throw InvalidJobException("Item to clone has vanished")
66 |
67 | val treeService = AddItemTreeService( this)
68 | val updatedItems = treeService.insert(item)
69 | box.put(updatedItems.apply { forEach { it.syncJob = null } })
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/DeleteItemJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.louiskirsch.quickdynalist.*
4 | import com.louiskirsch.quickdynalist.network.*
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem_
7 | import com.louiskirsch.quickdynalist.widget.ListAppWidget
8 | import io.objectbox.kotlin.query
9 | import io.objectbox.query.QueryBuilder
10 | import org.jetbrains.anko.collections.forEachWithIndex
11 | import retrofit2.Response
12 |
13 |
14 | class DeleteItemJob(val item: DynalistItem): ItemJob() {
15 |
16 | override fun addToDatabase() {
17 | val parent = item.parent.target
18 | DynalistApp.instance.boxStore.runInTx {
19 | box.get(item.clientId)?.let { item ->
20 | val items = getChildrenRecursively(item) + listOf(item)
21 | items.forEach {
22 | it.hidden = true
23 | it.syncJob = id
24 | }
25 | box.put(items)
26 | }
27 | }
28 | ListAppWidget.notifyItemChanged(applicationContext, parent)
29 | }
30 |
31 | private fun getChildrenRecursively(item: DynalistItem): List {
32 | val children = item.children
33 | return children.flatMap { getChildrenRecursively(it) } + children
34 | }
35 |
36 | @Throws(Throwable::class)
37 | override fun onRun() {
38 | requireItemId(item)
39 | val token = Dynalist(applicationContext).token
40 | val request = DeleteItemRequest(item.serverFileId!!, item.serverItemId!!, token!!)
41 | val response = dynalistService.deleteItem(request).execute()
42 | val body = response.body()!!
43 | requireSuccess(body)
44 | DynalistApp.instance.boxStore.runInTx {
45 | val items = box.query {
46 | equal(DynalistItem_.syncJob, id, QueryBuilder.StringOrder.CASE_INSENSITIVE)
47 | }.find()
48 | box.remove(items)
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/EditItemJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.louiskirsch.quickdynalist.*
4 | import com.louiskirsch.quickdynalist.network.*
5 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
6 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem_
7 | import com.louiskirsch.quickdynalist.widget.ListAppWidget
8 | import io.objectbox.kotlin.query
9 | import org.jetbrains.anko.collections.forEachWithIndex
10 | import retrofit2.Response
11 |
12 |
13 | class EditItemJob(val item: DynalistItem): ItemJob() {
14 |
15 | override fun addToDatabase() {
16 | item.syncJob = id
17 | box.attach(item)
18 | item.notifyModified()
19 | box.put(item)
20 | ListAppWidget.notifyItemChanged(applicationContext, item)
21 | }
22 |
23 | @Throws(Throwable::class)
24 | override fun onRun() {
25 | requireItemId(item)
26 | val token = Dynalist(applicationContext).token
27 | val request = EditItemRequest(item.serverFileId!!, item.serverItemId!!, item.name,
28 | item.note, item.isChecked, item.checkbox, item.heading, item.color, token!!)
29 | val response = dynalistService.editItem(request).execute()
30 | val body = response.body()!!
31 | requireSuccess(body)
32 | markItemsCompleted()
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/Exceptions.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | class BackendException(message: String): Exception(message)
4 | class NoInboxException: Exception()
5 | class ItemIdUnavailableException: Exception()
6 | class InvalidJobException(message: String): Exception(message)
7 | class NotAuthenticatedException: Exception()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/JobService.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.birbit.android.jobqueue.JobManager
4 | import com.birbit.android.jobqueue.scheduling.FrameworkJobSchedulerService
5 | import com.louiskirsch.quickdynalist.DynalistApp
6 |
7 | class JobService: FrameworkJobSchedulerService() {
8 |
9 | override fun getJobManager(): JobManager {
10 | return DynalistApp.instance.jobManager
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/jobs/VerifyTokenJob.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.jobs
2 |
3 | import com.birbit.android.jobqueue.RetryConstraint
4 | import org.greenrobot.eventbus.EventBus
5 | import com.birbit.android.jobqueue.CancelReason
6 | import com.birbit.android.jobqueue.Job
7 | import com.birbit.android.jobqueue.Params
8 | import com.louiskirsch.quickdynalist.AuthenticatedEvent
9 | import com.louiskirsch.quickdynalist.Dynalist
10 | import com.louiskirsch.quickdynalist.DynalistApp
11 | import com.louiskirsch.quickdynalist.ItemEvent
12 | import com.louiskirsch.quickdynalist.network.AuthenticatedRequest
13 | import org.jetbrains.annotations.Nullable
14 |
15 |
16 | class VerifyTokenJob(private val token: String)
17 | : Job(Params(2).requireNetwork().singleInstanceBy("verify_token")) {
18 |
19 | override fun onAdded() {}
20 |
21 | @Throws(Throwable::class)
22 | override fun onRun() {
23 | val service = DynalistApp.instance.dynalistService
24 | val dynalist = Dynalist(applicationContext)
25 |
26 | val call = service.listFiles(AuthenticatedRequest(token))
27 | val response = call.execute()
28 | val success = response.isSuccessful && response.body()!!.isOK
29 | if (!success)
30 | throw BackendException(response.body()?.errorDesc ?: "")
31 | dynalist.token = token
32 | EventBus.getDefault().post(AuthenticatedEvent(success))
33 | }
34 |
35 | override fun onCancel(@CancelReason cancelReason: Int, throwable: Throwable?) {
36 | EventBus.getDefault().post(AuthenticatedEvent(false))
37 | }
38 |
39 | override fun getRetryLimit() = 0
40 |
41 | override fun shouldReRunOnThrowable(throwable: Throwable, runCount: Int,
42 | maxRunCount: Int): RetryConstraint {
43 | return RetryConstraint.CANCEL
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/network/AddItemTreeService.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.network
2 |
3 | import com.louiskirsch.quickdynalist.Dynalist
4 | import com.louiskirsch.quickdynalist.DynalistApp
5 | import com.louiskirsch.quickdynalist.RateLimitDelay
6 | import com.louiskirsch.quickdynalist.jobs.ItemJob
7 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
8 | import com.louiskirsch.quickdynalist.utils.execRespectRateLimit
9 | import org.greenrobot.eventbus.EventBus
10 |
11 | class AddItemTreeService(private val itemJob: ItemJob) {
12 |
13 | private val dynalist = Dynalist(itemJob.applicationContext)
14 | private val token = dynalist.token!!
15 |
16 | private val dynalistService
17 | get() = DynalistApp.instance.dynalistService
18 |
19 | private val delayCallback = { _: Any, delay: Long ->
20 | EventBus.getDefault().post(RateLimitDelay(delay, ItemJob.TAG))
21 | }
22 |
23 | private fun insertRecursively(item: DynalistItem): List {
24 | if (item.children.isEmpty())
25 | return emptyList()
26 | // TODO API has weird bug that items are inserted in reverse order
27 | val children = item.children.sortedBy { it.position }.reversed()
28 | val changes = children.mapIndexed { i: Int, it ->
29 | // TODO we could define the index here, but the API is bugged
30 | InsertItemRequest.InsertSpec(item.serverItemId!!, it.name, it.note, it.checkbox,
31 | it.color)
32 | }.toTypedArray()
33 | val request = BulkInsertItemRequest(item.serverFileId!!, token, changes)
34 | val response = dynalistService.addToDocument(request)
35 | .execRespectRateLimit(delayCallback).body()!!
36 | itemJob.requireSuccess(response)
37 | response.new_node_ids!!.zip(children).forEach { (newItemId, child) ->
38 | child.serverItemId = newItemId
39 | }
40 | return children + children.flatMap { insertRecursively(it) }
41 | }
42 |
43 | fun insert(item: DynalistItem): List {
44 | val request = InsertItemRequest(item.serverFileId!!, item.serverParentId!!, item.name,
45 | item.note, item.checkbox, token, item.color, dynalist.insertPosition)
46 | val response = dynalistService.addToDocument(request)
47 | .execRespectRateLimit(delayCallback).body()!!
48 | itemJob.requireSuccess(response)
49 | item.serverItemId = response.new_node_ids!![0]
50 | val children = insertRecursively(item)
51 | return children + item
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/DocumentTreeNode.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import io.objectbox.relation.ToOne
4 |
5 | interface DocumentTreeNode {
6 | val parent: ToOne
7 | var position: Int
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/DynalistDocument.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import com.louiskirsch.quickdynalist.DynalistApp
4 | import io.objectbox.Box
5 | import io.objectbox.annotation.Entity
6 | import io.objectbox.annotation.Id
7 | import io.objectbox.annotation.Transient
8 | import io.objectbox.kotlin.boxFor
9 | import io.objectbox.relation.ToOne
10 |
11 | @Entity
12 | class DynalistDocument(var serverFileId: String?): DocumentTreeNode {
13 |
14 | constructor() : this(null)
15 |
16 | @Id
17 | var id: Long = 0
18 | var version: Long = 0
19 | override var position: Int = 0
20 | lateinit var folder: ToOne
21 |
22 | val rootItem: DynalistItem? get() = DynalistItem.byServerId(serverFileId!!, "root")
23 | override val parent: ToOne get() = folder
24 |
25 | companion object {
26 | val box: Box get() = DynalistApp.instance.boxStore.boxFor()
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/DynalistFolder.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import com.louiskirsch.quickdynalist.DynalistApp
4 | import io.objectbox.Box
5 | import io.objectbox.annotation.Backlink
6 | import io.objectbox.annotation.Entity
7 | import io.objectbox.annotation.Id
8 | import io.objectbox.kotlin.boxFor
9 | import io.objectbox.relation.ToMany
10 | import io.objectbox.relation.ToOne
11 |
12 | @Entity
13 | class DynalistFolder(var serverFolderId: String?): DocumentTreeNode {
14 |
15 | constructor() : this(null)
16 |
17 | @Id
18 | var id: Long = 0
19 | var title: String? = null
20 | override var position: Int = 0
21 | override lateinit var parent: ToOne
22 | @Backlink(to = "parent")
23 | lateinit var children: ToMany
24 | @Backlink(to = "folder")
25 | lateinit var documents: ToMany
26 |
27 | override fun hashCode(): Int = (id % Int.MAX_VALUE).toInt()
28 |
29 | companion object {
30 | const val LOCATION_TYPE = "folder"
31 | val box: Box get() = DynalistApp.instance.boxStore.boxFor()
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/DynalistItemMetaData.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import com.louiskirsch.quickdynalist.DynalistApp
4 | import io.objectbox.annotation.Entity
5 | import io.objectbox.annotation.Id
6 | import io.objectbox.kotlin.boxFor
7 | import io.objectbox.relation.ToMany
8 | import io.objectbox.relation.ToOne
9 | import java.io.Serializable
10 | import java.util.*
11 |
12 | @Entity
13 | class DynalistItemMetaData(): Serializable {
14 |
15 | @Id var id: Long = 0
16 |
17 | var date: Date? = null
18 | var image: String? = null
19 | var symbol: String? = null
20 | lateinit var tags: ToMany
21 | lateinit var linkedItem: ToOne
22 |
23 | constructor(fromItem: DynalistItem) : this() {
24 | update(fromItem)
25 | }
26 |
27 | fun update(fromItem: DynalistItem) {
28 | date = fromItem.date
29 | image = fromItem.image
30 | symbol = fromItem.symbol
31 | tags.clear()
32 | tags.addAll(fromItem.tags.map { DynalistTag.find(it) })
33 | linkedItem.target = fromItem.linkedItem
34 | }
35 |
36 | companion object {
37 | val box get() = DynalistApp.instance.boxStore.boxFor()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/Exceptions.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 |
4 | class InvalidTagException: Exception()
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/SubscriberOBLiveData.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import android.util.Log
4 | import androidx.lifecycle.LiveData
5 | import io.objectbox.BoxStore
6 | import io.objectbox.query.Query
7 | import io.objectbox.reactive.DataObserver
8 | import io.objectbox.reactive.DataSubscription
9 | import io.objectbox.reactive.DataTransformer
10 |
11 | class SubscriberOBLiveData(private val boxStore: BoxStore,
12 | private val subscribeClass: Class,
13 | private val query: Query,
14 | private val transformer: (Query) -> List) :
15 | LiveData>() {
16 | private var subscription: DataSubscription? = null
17 | private val listener = DataObserver> { data -> postValue(data) }
18 |
19 | override fun onActive() {
20 | // called when the LiveData object has an active observer
21 | if (subscription == null) {
22 | subscription = boxStore.subscribe(subscribeClass).transform {
23 | transformer(query)
24 | }.onError {
25 | Log.e(javaClass.name, "Transform failed", it)
26 | }.observer(listener)
27 | }
28 | }
29 |
30 | override fun onInactive() {
31 | // called when the LiveData object doesn't have any active observers
32 | if (!hasObservers()) {
33 | subscription!!.cancel()
34 | subscription = null
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/objectbox/TransformedOBLiveData.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.objectbox
2 |
3 | import android.util.Log
4 | import androidx.lifecycle.LiveData
5 | import io.objectbox.query.Query
6 | import io.objectbox.reactive.DataObserver
7 | import io.objectbox.reactive.DataSubscription
8 | import io.objectbox.reactive.DataTransformer
9 |
10 | class TransformedOBLiveData(private val query: Query,
11 | private val transformer: (List) -> List) :
12 | LiveData>() {
13 | private var subscription: DataSubscription? = null
14 | private val listener = DataObserver> { data -> postValue(data) }
15 |
16 | override fun onActive() {
17 | // called when the LiveData object has an active observer
18 | if (subscription == null) {
19 | subscription = query.subscribe().transform(transformer).onError {
20 | Log.e(javaClass.name, "Transform failed", it)
21 | }.observer(listener)
22 | }
23 | }
24 |
25 | override fun onInactive() {
26 | // called when the LiveData object doesn't have any active observers
27 | if (!hasObservers()) {
28 | subscription!!.cancel()
29 | subscription = null
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/text/EnhancedMovementMethod.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.text
2 |
3 | import android.text.Selection
4 | import android.text.Spannable
5 | import android.text.method.ArrowKeyMovementMethod
6 | import android.text.method.MovementMethod
7 | import android.text.style.ClickableSpan
8 | import android.view.MotionEvent
9 | import android.widget.TextView
10 |
11 | /**
12 | * ArrowKeyMovementMethod does support selection of text but not the clicking of links.
13 | * LinkMovementMethod does support clicking of links but not the selection of text.
14 | * This class adds the link clicking to the ArrowKeyMovementMethod.
15 | * We basically take the LinkMovementMethod onTouchEvent code and remove the line
16 | * Selection.removeSelection(buffer);
17 | * which deselects all text when no link was found.
18 | */
19 | class EnhancedMovementMethod : ArrowKeyMovementMethod() {
20 |
21 | override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
22 | val action = event.action
23 |
24 | if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
25 | var x = event.x.toInt()
26 | var y = event.y.toInt()
27 |
28 | x -= widget.totalPaddingLeft
29 | y -= widget.totalPaddingTop
30 |
31 | x += widget.scrollX
32 | y += widget.scrollY
33 |
34 | val layout = widget.layout
35 | val line = layout.getLineForVertical(y)
36 | val off = layout.getOffsetForHorizontal(line, x.toFloat())
37 |
38 | val link = buffer.getSpans(off, off, ClickableSpan::class.java)
39 |
40 | if (link.isNotEmpty()) {
41 | if (action == MotionEvent.ACTION_UP) {
42 | link[0].onClick(widget)
43 | } else if (action == MotionEvent.ACTION_DOWN) {
44 | Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]))
45 | }
46 |
47 | return true
48 | }
49 | }
50 |
51 | return super.onTouchEvent(widget, buffer, event)
52 | }
53 |
54 | companion object {
55 | val instance: MovementMethod by lazy { EnhancedMovementMethod() }
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/text/IndentedBulletSpan.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.text
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import android.os.Parcel
6 | import android.text.Layout
7 | import android.text.style.BulletSpan
8 |
9 | class IndentedBulletSpan: BulletSpan {
10 | private val indentWidth: Int
11 |
12 | constructor(gapWidth: Int, indentWidth: Int) : super(gapWidth) {
13 | this.indentWidth = indentWidth
14 | }
15 | constructor(src: Parcel) : super(src) {
16 | this.indentWidth = src.readInt()
17 | }
18 |
19 | override fun writeToParcel(dest: Parcel, flags: Int) {
20 | super.writeToParcel(dest, flags)
21 | dest.writeInt(indentWidth)
22 | }
23 |
24 | override fun getLeadingMargin(first: Boolean): Int {
25 | return super.getLeadingMargin(first) + indentWidth
26 | }
27 |
28 | override fun drawLeadingMargin(canvas: Canvas, paint: Paint, x: Int, dir: Int, top: Int,
29 | baseline: Int, bottom: Int, text: CharSequence, start: Int,
30 | end: Int, first: Boolean, layout: Layout?) {
31 | val newX = x + indentWidth * dir
32 | super.drawLeadingMargin(canvas, paint, newX, dir, top, baseline, bottom, text, start, end,
33 | first, layout)
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/text/ThemedSpan.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.text
2 |
3 | import android.content.Context
4 | import android.content.res.Resources
5 | import android.text.Spannable
6 |
7 | class ThemedSpan(private val spanCreator: (Context) -> Any) {
8 |
9 | fun apply(context: Context, spannable: Spannable) {
10 | val start = spannable.getSpanStart(this)
11 | val end = spannable.getSpanEnd(this)
12 | val flags = spannable.getSpanFlags(this)
13 | val newSpan = spanCreator(context)
14 | spannable.removeSpan(this)
15 | spannable.setSpan(newSpan, start, end, flags)
16 | }
17 |
18 | companion object {
19 | fun applyAll(context: Context, spannable: Spannable) {
20 | spannable.getSpans(0, spannable.length, ThemedSpan::class.java).forEach {
21 | it.apply(context, spannable)
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/text/TintedImageSpan.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.text
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.text.style.ImageSpan
5 |
6 | class TintedImageSpan(drawable: Drawable, verticalAlignment: Int, val lineHeight: Float = 1.0f)
7 | : ImageSpan(drawable, verticalAlignment)
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/utils/SpeechRecognitionHelper.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.utils
2 |
3 | import android.app.Activity
4 | import android.content.ActivityNotFoundException
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.speech.RecognizerIntent
8 | import androidx.fragment.app.Fragment
9 | import com.louiskirsch.quickdynalist.R
10 | import org.jetbrains.anko.toast
11 |
12 | class SpeechRecognitionHelper {
13 |
14 | fun startSpeechRecognition(activity: Activity) {
15 | startSpeechRecognition(activity, activity::startActivityForResult)
16 | }
17 |
18 | fun startSpeechRecognition(fragment: Fragment) {
19 | startSpeechRecognition(fragment.context!!, fragment::startActivityForResult)
20 | }
21 |
22 | private fun startSpeechRecognition(context: Context, starter: (Intent, Int) -> Unit) {
23 | val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
24 | putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
25 | }
26 | val speechRecognitionRequestCode =
27 | context.resources.getInteger(R.integer.request_code_speech_recognition)
28 | try {
29 | starter(intent, speechRecognitionRequestCode)
30 | } catch (e: ActivityNotFoundException) {
31 | context.toast(R.string.error_speech_recognition_not_available)
32 | }
33 | }
34 |
35 | fun dispatchResult(context:Context, requestCode: Int, resultCode: Int, data: Intent?,
36 | cancelCallback: (() -> Unit)? = null, callback: (String) -> Unit) {
37 | val speechRecognitionRequestCode =
38 | context.resources.getInteger(R.integer.request_code_speech_recognition)
39 | if (requestCode == speechRecognitionRequestCode) {
40 | if (resultCode == Activity.RESULT_OK) {
41 | val spokenText = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
42 | .let { it!![0] }
43 | callback(spokenText)
44 | } else {
45 | cancelCallback?.invoke()
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/views/BottomBarScrollingViewBehavior.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.views
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.coordinatorlayout.widget.CoordinatorLayout
7 | import com.google.android.material.appbar.AppBarLayout
8 |
9 | class BottomBarScrollingViewBehavior: AppBarLayout.ScrollingViewBehavior {
10 |
11 | constructor() : super()
12 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
13 |
14 | override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
15 | val superDependence = super.layoutDependsOn(parent, child, dependency)
16 | return superDependence || dependency.tag == "bottomBar"
17 | }
18 |
19 | override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean {
20 | parent.getDependencies(child).first { it.tag == "bottomBar" }?.let { dependency ->
21 | val paddingBottom = if (dependency.visibility == View.VISIBLE) dependency.height else 0
22 | child.setPadding(child.paddingLeft, child.paddingTop, child.paddingRight, paddingBottom)
23 | }
24 | return super.onLayoutChild(parent, child, layoutDirection)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/views/MoveUpwardBehavior.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.views
2 |
3 | import android.content.Context
4 | import androidx.core.view.ViewCompat
5 | import androidx.coordinatorlayout.widget.CoordinatorLayout
6 | import android.util.AttributeSet
7 | import android.view.View
8 | import com.google.android.material.snackbar.Snackbar
9 | import androidx.annotation.Keep
10 |
11 |
12 | @Keep
13 | class MoveUpwardBehavior(context: Context?, attrs: AttributeSet?)
14 | : CoordinatorLayout.Behavior(context, attrs) {
15 |
16 | override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
17 | return dependency is Snackbar.SnackbarLayout
18 | }
19 |
20 | override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
21 | child.translationY = Math.min(0f, dependency.translationY - dependency.height)
22 | return true
23 | }
24 |
25 | override fun onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View) {
26 | ViewCompat.animate(child).translationY(0f).start()
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/views/ScrollFABBehavior.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.views
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import androidx.annotation.Keep
7 | import androidx.coordinatorlayout.widget.CoordinatorLayout
8 | import androidx.core.view.ViewCompat
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import androidx.recyclerview.widget.RecyclerView
11 | import com.google.android.material.floatingactionbutton.FloatingActionButton
12 |
13 | @Keep
14 | class ScrollFABBehavior(context: Context?, attrs: AttributeSet?)
15 | : FloatingActionButton.Behavior(context, attrs) {
16 |
17 | companion object {
18 | val hideListener = object: FloatingActionButton.OnVisibilityChangedListener() {
19 | override fun onHidden(fab: FloatingActionButton) {
20 | fab.visibility = View.INVISIBLE
21 | }
22 | }
23 | }
24 |
25 | override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,
26 | child: FloatingActionButton, directTargetChild: View,
27 | target: View, axes: Int, type: Int): Boolean {
28 | return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||
29 | super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,target, axes,
30 | type)
31 | }
32 |
33 | override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton,
34 | target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int,
35 | dyUnconsumed: Int, type: Int) {
36 | super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
37 | dyUnconsumed, type)
38 | if (dyConsumed < 0 && child.visibility == View.VISIBLE) {
39 | child.hide(hideListener)
40 | } else if (dyConsumed > 0 && child.visibility != View.VISIBLE) {
41 | child.show()
42 | }
43 | }
44 |
45 | override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout,
46 | child: FloatingActionButton, target: View, type: Int) {
47 | super.onStopNestedScroll(coordinatorLayout, child, target, type)
48 | (target as? RecyclerView)?.let { recycler ->
49 | (recycler.layoutManager as? LinearLayoutManager)?.let {
50 | val lastItem = it.itemCount - 1
51 | val lastVisible = it.findLastVisibleItemPosition()
52 | if (lastVisible >= lastItem) {
53 | child.hide(hideListener)
54 | }
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/views/SquareImageView.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.views
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.ImageView
6 | import androidx.appcompat.widget.AppCompatImageView
7 |
8 | class SquareImageView @JvmOverloads constructor(
9 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
10 | ) : AppCompatImageView(context, attrs, defStyleAttr) {
11 |
12 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
13 | super.onMeasure(widthMeasureSpec, heightMeasureSpec)
14 |
15 | val height = measuredHeight
16 | setMeasuredDimension(height, height)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/louiskirsch/quickdynalist/widget/ListAppWidgetConfigurationReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.louiskirsch.quickdynalist.widget
2 |
3 | import android.appwidget.AppWidgetManager
4 | import android.content.BroadcastReceiver
5 | import android.content.Context
6 | import android.content.Intent
7 | import com.louiskirsch.quickdynalist.DynalistApp
8 | import com.louiskirsch.quickdynalist.FilterLocation
9 | import com.louiskirsch.quickdynalist.ItemLocation
10 | import com.louiskirsch.quickdynalist.objectbox.DynalistItem
11 | import com.louiskirsch.quickdynalist.objectbox.DynalistItemFilter
12 | import io.objectbox.kotlin.boxFor
13 |
14 | class ListAppWidgetConfigurationReceiver : BroadcastReceiver() {
15 |
16 | override fun onReceive(context: Context, intent: Intent) {
17 | val widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0)
18 | val location = if (intent.hasExtra(DynalistApp.EXTRA_DISPLAY_ITEM_ID)) {
19 | val locationId = intent.getLongExtra(DynalistApp.EXTRA_DISPLAY_ITEM_ID, 1)
20 | val item = DynalistApp.instance.boxStore.boxFor().get(locationId)
21 | ItemLocation(item)
22 | } else {
23 | val locationId = intent.getLongExtra(DynalistApp.EXTRA_DISPLAY_FILTER_ID, 1)
24 | val filter = DynalistApp.instance.boxStore.boxFor().get(locationId)
25 | FilterLocation(filter, context)
26 | }
27 | ListAppWidgetConfigureActivity.saveWidgetInfo(context, widgetId, location)
28 | val appWidgetManager = AppWidgetManager.getInstance(context)
29 | ListAppWidget.updateAppWidget(context, appWidgetManager, widgetId)
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/dashed_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/dashed_border_activated.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/appwidget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/drawable-nodpi/appwidget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/activatable_selectable_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
-
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 | -
15 |
16 |
-
17 |
18 |
19 |
20 |
21 |
22 | -
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circular_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
11 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dashed_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dashed_border_activated.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dropoff_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
-
6 |
7 |
8 |
10 |
11 |
12 |
13 | -
14 |
15 |
-
16 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_advanced_item.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_change_color.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_clear.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_create_filter.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_create_shortcut.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_date.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_details.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_discard.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_duplicate.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_edit.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_edit_filter.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_goto_parent.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_help.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_item_list.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_jump_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_link.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_manage_tags.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_more.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_move.xml:
--------------------------------------------------------------------------------
1 |
4 |
7 |
10 |
13 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_move_inbox.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_open_large.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_open_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_rate_quickdynalist.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_record_speech.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_search_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_send_bug_report.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_send_item.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_share.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_share_quickdynalist.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_show_image.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_show_text.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_sync.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_backward_link.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chip_add.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder_open.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder_stateful.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_forward_link.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_quick_dialog_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_record_speech_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_search_item_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_sync_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_type_dialog.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_type_list.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_swipe_delete.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_swipe_edit.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_tile_quick_dialog.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/item_color_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-w900dp/activity_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_auth.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
22 |
23 |
32 |
33 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
23 |
24 |
33 |
34 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_wizard.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dropdown_menu_popup_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/emoji_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_dialog_setup.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
21 |
28 |
29 |
39 |
40 |
48 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_inbox_configuration.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
27 |
28 |
39 |
40 |
41 |
42 |
52 |
53 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_insert_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
24 |
25 |
34 |
35 |
47 |
48 |
49 |
50 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_item_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
18 |
19 |
27 |
28 |
36 |
37 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_sync_status.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
21 |
32 |
33 |
44 |
45 |
57 |
58 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tag_manager.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
26 |
27 |
34 |
35 |
44 |
45 |
50 |
51 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list_dropoff.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_app_widget.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
26 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_app_widget_configure.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_app_widget_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
25 |
26 |
34 |
35 |
45 |
46 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_separator.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/menu_color_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
24 |
25 |
32 |
33 |
40 |
41 |
48 |
49 |
56 |
57 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/search_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
20 |
21 |
27 |
28 |
36 |
37 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_edit_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_list_app_widget_configure.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_shortcut.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/advanced_item_activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/filter_item_list_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
14 |
15 |
18 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/item_list_activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
16 |
19 |
20 |
24 |
25 |
28 |
29 |
30 |
34 |
35 |
39 |
40 |
44 |
45 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/item_list_popup_image_extension.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/item_text_insert_context_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/item_text_selection_context_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
12 |
13 |
16 |
17 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/quick_dialog_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_quick_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_quick_dialog_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_record_speech.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_record_speech_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search_item_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_sync.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_sync_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_quick_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_quick_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_quick_dialog_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_quick_dialog_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_record_speech.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_record_speech.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_record_speech_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_record_speech_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_search_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_search_item.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_search_item_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_search_item_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_sync.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_shortcut_sync_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-hdpi/ic_shortcut_sync_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_quick_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_quick_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_quick_dialog_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_quick_dialog_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_record_speech.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_record_speech.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_record_speech_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_record_speech_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_search_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_search_item.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_search_item_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_search_item_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_sync.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_shortcut_sync_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-mdpi/ic_shortcut_sync_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_quick_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_quick_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_quick_dialog_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_quick_dialog_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_record_speech.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_record_speech.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_record_speech_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_record_speech_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_search_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_search_item.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_search_item_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_search_item_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_sync.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_shortcut_sync_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xhdpi/ic_shortcut_sync_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_quick_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_quick_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_quick_dialog_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_quick_dialog_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_record_speech.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_record_speech.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_record_speech_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_record_speech_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_search_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_search_item.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_search_item_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_search_item_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_sync.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_shortcut_sync_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxhdpi/ic_shortcut_sync_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_quick_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_quick_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_quick_dialog_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_quick_dialog_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_record_speech.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_record_speech.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_record_speech_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_record_speech_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_search_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_search_item.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_search_item_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_search_item_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_sync.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_sync_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/mipmap-xxxhdpi/ic_shortcut_sync_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/dialog_tutorial.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/app/src/main/res/raw/dialog_tutorial.webm
--------------------------------------------------------------------------------
/app/src/main/res/transition/change_view_bounds.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/transition/window_explode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/primary_material_dark
4 | @color/primary_dark_material_dark
5 | #90CAF9
6 |
7 | #90CAF9
8 | #A5D6A7
9 |
10 | #2e2e2e
11 | #424242
12 | 15
13 | #424242
14 | @color/primary_material_dark
15 |
16 | #80FFFFFF
17 | #80F76439
18 | #80F19537
19 | #80ECC937
20 | #805BF02E
21 | #80389BF7
22 | #806C34F7
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/background_material_dark
4 | @color/abc_primary_text_material_dark
5 | @color/abc_secondary_text_material_dark
6 | @drawable/abc_item_background_holo_dark
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v28/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - Use system default
5 | - Light
6 | - Dark
7 | - Set by Battery Saver
8 |
9 |
10 | - -1
11 | - 1
12 | - 2
13 | - 3
14 |
15 | -1
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w900dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | @dimen/abc_action_bar_default_height_material
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w900dp/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.louiskirsch.quickdynalist.RECORD_SPEECH
4 | com.louiskirsch.quickdynalist.ProcessTextActivity
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1565C0
4 | #0D47A1
5 | #FF008577
6 |
7 | #E0E0E0
8 | #FF0000
9 | #4FC3F7
10 |
11 | #E0E0E0
12 | #4CAF50
13 |
14 | #2196F3
15 | #4CAF50
16 |
17 | #F44336
18 | #4CAF50
19 |
20 | #fafafa
21 | #BDBDBD
22 | 0xE
23 | #EEEEEE
24 |
25 | @null
26 | #f9d0c4
27 | #fed8b1
28 | #fef2c0
29 | #c8e3c0
30 | #c5def5
31 | #d4c5f9
32 |
33 | - @color/itemColor0
34 | - @color/itemColor1
35 | - @color/itemColor2
36 | - @color/itemColor3
37 | - @color/itemColor4
38 | - @color/itemColor5
39 | - @color/itemColor6
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 70dp
7 | 0dp
8 | 8dp
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1976D2
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_shortcut_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F5F5F5
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_shortcut_quick_dialog_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F3F3F3
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - None
5 | - 3
6 | - 5
7 | - 10
8 | - All
9 |
10 |
11 | - 0
12 | - 3
13 | - 5
14 | - 10
15 | - -1
16 |
17 |
18 | - children
19 | - children of children
20 |
21 |
22 | - 0
23 | - 1
24 |
25 |
26 |
27 | - Light
28 | - Dark
29 | - Set by Battery Saver
30 |
31 |
32 | - 1
33 | - 2
34 | - 3
35 |
36 | 1
37 |
38 |
39 | - top
40 | - bottom
41 |
42 |
43 | - top
44 | - bottom
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/values/request_codes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
4 | 2
5 | 3
6 | 4
7 | 5
8 | 6
9 | 7
10 | 8
11 | 9
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/background_material_light
4 | #de000000
5 | #8a000000
6 | @drawable/abc_item_background_holo_light
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/chip.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/list_app_widget_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
17 |
18 |
19 |
20 |
27 |
31 |
32 |
33 |
34 |
41 |
45 |
46 |
47 |
48 |
55 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.7.21'
5 | ext.objectboxVersion = "3.6.0"
6 |
7 | repositories {
8 | google()
9 | mavenCentral()
10 | }
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:8.1.0'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
15 |
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle files
18 | }
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | google()
24 | mavenCentral()
25 | maven { url "https://jitpack.io" }
26 |
27 | }
28 | }
29 |
30 | tasks.register('clean', Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/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 | android.defaults.buildfeatures.buildconfig=true
10 | android.enableJetifier=true
11 | android.nonFinalResIds=false
12 | android.nonTransitiveRClass=false
13 | android.useAndroidX=true
14 | org.gradle.jvmargs=-Xmx1536m
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/louiskirsch/QuickDynalist/451cd22f69f2c467aeec22c012299d97af462cae/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Aug 18 18:15:22 CEST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/hashkode/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/hashkode/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'kotlin'
3 |
4 | dependencies {
5 | implementation fileTree(include: ['*.jar'], dir: 'libs')
6 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
7 | }
8 |
9 | java {
10 | sourceCompatibility JavaVersion.VERSION_17
11 | targetCompatibility JavaVersion.VERSION_17
12 | }
13 |
14 | buildscript {
15 | repositories {
16 | mavenCentral()
17 | }
18 | dependencies {
19 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
20 | }
21 | }
22 | repositories {
23 | mavenCentral()
24 | }
25 | compileKotlin {
26 | kotlinOptions {
27 | jvmTarget = "1.8"
28 | }
29 | }
30 | compileTestKotlin {
31 | kotlinOptions {
32 | jvmTarget = "1.8"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/hashkode/src/main/java/nl/pvdberg/hashkode/Equals.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 Pim van den Berg
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package nl.pvdberg.hashkode
26 |
27 | @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
28 | class EqualsContext(val one: T, val two: T) : HashKodeContext
29 | {
30 | var equal = true
31 |
32 | inline override infix fun Any.correspondsTo(other: Any?)
33 | {
34 | if (equal) equal = this == other
35 | }
36 |
37 | inline override fun compareBy(comparison: () -> Boolean)
38 | {
39 | if (equal) equal = comparison()
40 | }
41 |
42 | inline override fun compareField(getter: T.() -> Any?)
43 | {
44 | if (equal) equal = one.getter() == two.getter()
45 | }
46 | }
47 |
48 | /**
49 | * Tests equality of two objects
50 | * @receiver Object to compare another object to
51 | * @param other Object to compare to receiver
52 | * @param requirements Lambda that compares fields
53 | * @return True when objects are equal
54 | * @see Any.equals
55 | */
56 | inline fun T.compareFields(
57 | other: Any?,
58 | requirements: EqualsContext.() -> Unit
59 | ): Boolean
60 | {
61 | if (other == null) return false
62 | if (other === this) return true
63 | if (other !is T) return false
64 |
65 | return EqualsContext(this, other)
66 | .apply { requirements() }
67 | .equal
68 | }
69 |
--------------------------------------------------------------------------------
/hashkode/src/main/java/nl/pvdberg/hashkode/HashKode.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 Pim van den Berg
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package nl.pvdberg.hashkode
26 |
27 | object HashKode
28 | {
29 | var VERIFY_HASHKODE_PARAMETERS = true
30 | var DEFAULT_INITIAL_ODD_NUMBER = 17
31 | var DEFAULT_MULTIPLIER_PRIME = 37
32 | }
--------------------------------------------------------------------------------
/hashkode/src/main/java/nl/pvdberg/hashkode/HashKodeContext.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 Pim van den Berg
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package nl.pvdberg.hashkode
26 |
27 | interface HashKodeContext
28 | {
29 | /**
30 | * Tests equality of two objects and saves result in context
31 | * @receiver Object to compare another object to
32 | * @param other to compare to receiver
33 | * @see Any.equals
34 | */
35 | fun Any.correspondsTo(other: Any?)
36 |
37 | /**
38 | * Runs function
39 | * @param comparison Function which should do a comparison of two fields
40 | */
41 | fun compareBy(comparison: () -> Boolean)
42 |
43 | /**
44 | * Compares a field by using given getter lambda
45 | * @param getter Getter for a field
46 | */
47 | fun compareField(getter: T.() -> Any?)
48 | }
--------------------------------------------------------------------------------
/hashkode/src/main/java/nl/pvdberg/hashkode/Hashing.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 Pim van den Berg
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package nl.pvdberg.hashkode
26 |
27 | /**
28 | * Generates a hashcode for given fields
29 | * @param fields Fields to generate a hashcode from
30 | * @param initialOddNumber Odd number to start with
31 | * @param multiplierPrime Prime number to multiply hashes with
32 | * @return Hashcode
33 | * @see Any.hashCode
34 | */
35 | @Suppress("NOTHING_TO_INLINE")
36 | inline fun hashKode(
37 | vararg fields: Any?,
38 | initialOddNumber: Int = HashKode.DEFAULT_INITIAL_ODD_NUMBER,
39 | multiplierPrime: Int = HashKode.DEFAULT_MULTIPLIER_PRIME): Int
40 | {
41 | if (HashKode.VERIFY_HASHKODE_PARAMETERS &&
42 | (initialOddNumber != HashKode.DEFAULT_INITIAL_ODD_NUMBER ||
43 | multiplierPrime != HashKode.DEFAULT_MULTIPLIER_PRIME))
44 | {
45 | require(initialOddNumber % 2 != 0) {
46 | "InitialOddNumber must be an odd number"
47 | }
48 | require(multiplierPrime > 1 && (2..(multiplierPrime / 2)).all { multiplierPrime % it != 0 }) {
49 | "MultiplierPrime must be a prime number"
50 | }
51 | }
52 |
53 | var result = initialOddNumber
54 | fields.forEach { field ->
55 | val hash = field?.hashCode() ?: 0
56 | result = multiplierPrime * result + hash
57 | }
58 | return result
59 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':hashkode'
2 |
--------------------------------------------------------------------------------