├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── assets
└── finch.gif
├── build.gradle
├── common-loggers
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── common
│ └── loggers
│ ├── FinchLogger.kt
│ ├── FinchNetworkLogger.kt
│ ├── data
│ └── models
│ │ ├── HeaderHttpModel.kt
│ │ ├── MediaType.kt
│ │ └── NetworkLogEntity.kt
│ └── utils
│ ├── FormatUtil.kt
│ └── GsonUtil.kt
├── common
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ ├── common
│ ├── contracts
│ │ ├── Finch.kt
│ │ ├── FinchListItem.kt
│ │ └── component
│ │ │ ├── Cell.kt
│ │ │ ├── Component.kt
│ │ │ ├── ExpandableComponent.kt
│ │ │ ├── ValueWrapperComponent.kt
│ │ │ └── ViewHolder.kt
│ ├── listeners
│ │ ├── LogListener.kt
│ │ ├── NetworkLogListener.kt
│ │ ├── OverlayListener.kt
│ │ ├── UpdateListener.kt
│ │ └── VisibilityListener.kt
│ └── models
│ │ ├── Configuration.kt
│ │ ├── Inset.kt
│ │ ├── Position.kt
│ │ └── Text.kt
│ └── components
│ ├── CheckBox.kt
│ ├── Divider.kt
│ ├── ItemList.kt
│ ├── KeyValueList.kt
│ ├── Label.kt
│ ├── LongText.kt
│ ├── MultipleSelectionList.kt
│ ├── Padding.kt
│ ├── ProgressBar.kt
│ ├── SingleSelectionList.kt
│ ├── Slider.kt
│ ├── Switch.kt
│ ├── TextInput.kt
│ └── special
│ ├── AnimationSpeed.kt
│ ├── AppInfo.kt
│ ├── DesignOverlay.kt
│ ├── DeveloperOptions.kt
│ ├── DeviceInfo.kt
│ ├── ForceCrash.kt
│ ├── Gallery.kt
│ ├── Header.kt
│ ├── LifecycleLogs.kt
│ ├── Logs.kt
│ ├── LoremIpsumGenerator.kt
│ ├── NetworkLogs.kt
│ ├── ScreenCaptureToolbox.kt
│ ├── ScreenRecording.kt
│ └── Screenshot.kt
├── config
└── detekt
│ └── config.yml
├── core
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kernel
│ │ └── finch
│ │ ├── FinchCore.kt
│ │ └── core
│ │ ├── FinchImpl.kt
│ │ ├── OverlayFragment.kt
│ │ ├── data
│ │ ├── db
│ │ │ ├── FinchDatabase.kt
│ │ │ └── NetworkLogDao.kt
│ │ └── models
│ │ │ └── Period.kt
│ │ ├── list
│ │ ├── CellAdapter.kt
│ │ ├── cells
│ │ │ ├── ButtonCell.kt
│ │ │ ├── CheckBoxCell.kt
│ │ │ ├── DividerCell.kt
│ │ │ ├── ExpandableHeaderCell.kt
│ │ │ ├── ExpandedItemCheckBoxCell.kt
│ │ │ ├── ExpandedItemKeyValueCell.kt
│ │ │ ├── ExpandedItemRadioButtonCell.kt
│ │ │ ├── ExpandedItemTextCell.kt
│ │ │ ├── HeaderCell.kt
│ │ │ ├── PaddingCell.kt
│ │ │ ├── ProgressBarCell.kt
│ │ │ ├── SliderCell.kt
│ │ │ ├── SwitchCell.kt
│ │ │ └── TextCell.kt
│ │ └── delegates
│ │ │ ├── AnimationSpeedDelegate.kt
│ │ │ ├── AppInfoDelegate.kt
│ │ │ ├── CheckBoxDelegate.kt
│ │ │ ├── DesignOverlayDelegate.kt
│ │ │ ├── DeveloperOptionsDelegate.kt
│ │ │ ├── DeviceInfoDelegate.kt
│ │ │ ├── DividerDelegate.kt
│ │ │ ├── ForceCrashDelegate.kt
│ │ │ ├── GalleryDelegate.kt
│ │ │ ├── HeaderDelegate.kt
│ │ │ ├── ItemListDelegate.kt
│ │ │ ├── KeyValueListDelegate.kt
│ │ │ ├── LabelDelegate.kt
│ │ │ ├── LifecycleLogsDelegate.kt
│ │ │ ├── LogsDelegate.kt
│ │ │ ├── LongTextDelegate.kt
│ │ │ ├── LoremIpsumGeneratorDelegate.kt
│ │ │ ├── MultipleSelectionListDelegate.kt
│ │ │ ├── NetworkLogsDelegate.kt
│ │ │ ├── PaddingDelegate.kt
│ │ │ ├── ProgressBarDelegate.kt
│ │ │ ├── ScreenCaptureToolboxDelegate.kt
│ │ │ ├── ScreenRecordingDelegate.kt
│ │ │ ├── ScreenshotDelegate.kt
│ │ │ ├── SingleSelectionListDelegate.kt
│ │ │ ├── SliderDelegate.kt
│ │ │ ├── SwitchDelegate.kt
│ │ │ ├── TextInputDelegate.kt
│ │ │ └── shared
│ │ │ ├── ExpandableComponentDelegate.kt
│ │ │ └── ValueWrapperComponentDelegate.kt
│ │ ├── manager
│ │ ├── DebugMenuInjector.kt
│ │ ├── LifecycleLogManager.kt
│ │ ├── ListManager.kt
│ │ ├── LocalStorageManager.kt
│ │ ├── LogManager.kt
│ │ ├── MemoryStorageManager.kt
│ │ ├── NetworkLogManager.kt
│ │ ├── NotificationManager.kt
│ │ ├── RetentionManager.kt
│ │ ├── ScreenCaptureManager.kt
│ │ ├── ShakeDetectorManager.kt
│ │ ├── UiManager.kt
│ │ └── listener
│ │ │ ├── BaseListenerManager.kt
│ │ │ ├── LogListenerManager.kt
│ │ │ ├── NetworkLogListenerManager.kt
│ │ │ ├── OverlayListenerManager.kt
│ │ │ ├── UpdateListenerManager.kt
│ │ │ └── VisibilityListenerManager.kt
│ │ ├── presentation
│ │ ├── ChildHorizontalScrollView.kt
│ │ ├── InternalDebugMenuView.kt
│ │ ├── OverlayFrameLayout.kt
│ │ ├── TolerantScrollView.kt
│ │ ├── detail
│ │ │ ├── log
│ │ │ │ └── dialog
│ │ │ │ │ ├── LogDetailDialogFragment.kt
│ │ │ │ │ └── LogDetailDialogViewModel.kt
│ │ │ └── networklog
│ │ │ │ ├── BaseFinchActivity.kt
│ │ │ │ ├── ClearNetworkLogService.kt
│ │ │ │ ├── ContainerActivity.kt
│ │ │ │ ├── NetworkLogActivity.kt
│ │ │ │ ├── NetworkLogFragment.kt
│ │ │ │ ├── NetworkLogListFragment.kt
│ │ │ │ ├── NetworkLogOverviewFragment.kt
│ │ │ │ ├── NetworkLogPayloadFragment.kt
│ │ │ │ └── list
│ │ │ │ ├── NetworkLogAdapter.kt
│ │ │ │ └── NetworkLogViewHolder.kt
│ │ └── gallery
│ │ │ ├── DeleteConfirmationDialogFragment.kt
│ │ │ ├── GalleryActivity.kt
│ │ │ ├── GalleryViewModel.kt
│ │ │ ├── MediaPreviewDialogFragment.kt
│ │ │ └── list
│ │ │ ├── GalleryAdapter.kt
│ │ │ ├── GalleryListItem.kt
│ │ │ ├── ImageViewHolder.kt
│ │ │ ├── SectionHeaderViewHolder.kt
│ │ │ └── VideoViewHolder.kt
│ │ ├── provider
│ │ └── FinchFileProvider.kt
│ │ └── util
│ │ ├── FileUtil.kt
│ │ ├── FinchUtil.kt
│ │ ├── FormatterNetworkLog.kt
│ │ ├── Helpers.kt
│ │ ├── LifecycleLogEntry.kt
│ │ ├── LogEntry.kt
│ │ ├── ScreenCaptureService.kt
│ │ ├── ScreenshotWriter.kt
│ │ ├── SimpleActivityLifecycleCallbacks.kt
│ │ ├── Text.kt
│ │ └── extension
│ │ ├── Activity.kt
│ │ ├── CharSequence.kt
│ │ ├── Context.kt
│ │ ├── TextView.kt
│ │ ├── View.kt
│ │ └── ViewModelStoreOwner.kt
│ └── res
│ ├── anim
│ ├── finch_item_animation_fall_down.xml
│ └── finch_layout_animation_list.xml
│ ├── drawable
│ ├── finch_bg_gradient.xml
│ ├── finch_ic_bullet_point.xml
│ ├── finch_ic_close.xml
│ ├── finch_ic_collapse.xml
│ ├── finch_ic_delete.xml
│ ├── finch_ic_empty.xml
│ ├── finch_ic_expand.xml
│ ├── finch_ic_lock.xml
│ ├── finch_ic_notification.xml
│ ├── finch_ic_recording.xml
│ ├── finch_ic_search.xml
│ ├── finch_ic_share.xml
│ ├── finch_ic_toggle_details_off.xml
│ └── finch_ic_toggle_details_on.xml
│ ├── font
│ ├── finch_console.xml
│ └── finch_console_font.ttf
│ ├── layout
│ ├── finch_activity_container.xml
│ ├── finch_activity_gallery.xml
│ ├── finch_activity_network_log.xml
│ ├── finch_cell_button.xml
│ ├── finch_cell_check_box.xml
│ ├── finch_cell_divider.xml
│ ├── finch_cell_expandable_header.xml
│ ├── finch_cell_expanded_item_check_box.xml
│ ├── finch_cell_expanded_item_radio_button.xml
│ ├── finch_cell_expanded_item_text.xml
│ ├── finch_cell_header.xml
│ ├── finch_cell_padding.xml
│ ├── finch_cell_progress_bar.xml
│ ├── finch_cell_slider.xml
│ ├── finch_cell_switch.xml
│ ├── finch_cell_text.xml
│ ├── finch_dialog_fragment_log_detail.xml
│ ├── finch_dialog_fragment_log_detail_scrolling.xml
│ ├── finch_dialog_fragment_media_preview.xml
│ ├── finch_fragment_network_log_list.xml
│ ├── finch_fragment_network_log_overview.xml
│ ├── finch_fragment_network_log_payload.xml
│ ├── finch_item_gallery_image.xml
│ ├── finch_item_gallery_section_header.xml
│ ├── finch_item_gallery_video.xml
│ ├── finch_item_network_log.xml
│ └── finch_view_text_input_dialog.xml
│ ├── menu
│ ├── finch_gallery.xml
│ ├── finch_log_detail.xml
│ ├── finch_main.xml
│ └── finch_network_log.xml
│ ├── values-sw720dp
│ └── dimens.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── finch_provider_paths.xml
├── dependencies.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── log-grpc-noop
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── networklog
│ └── grpc
│ └── FinchGrpcLogger.kt
├── log-grpc
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── networklog
│ └── grpc
│ ├── FinchClientInterceptor.kt
│ ├── FinchGrpcLogger.kt
│ └── FinchGrpcLoggerImpl.kt
├── log-noop
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── log
│ └── FinchLogger.kt
├── log-okhttp-noop
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── networklog
│ └── okhttp
│ └── FinchOkHttpLogger.kt
├── log-okhttp
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── networklog
│ └── okhttp
│ ├── FinchInterceptor.kt
│ ├── FinchOkHttpLogger.kt
│ └── FinchOkHttpLoggerImpl.kt
├── log
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ └── log
│ ├── FinchLogger.kt
│ ├── LoggerImpl.kt
│ └── utils
│ ├── Log.kt
│ └── extensions
│ └── Log.kt
├── noop
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ ├── DebugMenuView.kt
│ └── Finch.kt
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kernel
│ │ └── finch
│ │ └── sample
│ │ ├── ApiService.kt
│ │ ├── App.kt
│ │ └── MainActivity.kt
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── settings.gradle
├── ui-activity
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kernel
│ │ └── finch
│ │ ├── Finch.kt
│ │ └── implementation
│ │ ├── ActivityUiManager.kt
│ │ └── DebugMenuActivity.kt
│ └── res
│ └── layout
│ └── finch_activity_debug_menu.xml
├── ui-bottom-sheet
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kernel
│ │ └── finch
│ │ ├── Finch.kt
│ │ └── implementation
│ │ ├── BottomSheetUiManager.kt
│ │ └── DebugMenuBottomSheet.kt
│ └── res
│ └── values
│ └── dimens.xml
├── ui-dialog
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ ├── Finch.kt
│ └── implementation
│ ├── DebugMenuDialog.kt
│ └── DialogUiManager.kt
├── ui-drawer
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kernel
│ │ └── finch
│ │ ├── Finch.kt
│ │ └── implementation
│ │ ├── DebugMenuDrawerLayout.kt
│ │ └── DrawerUiManager.kt
│ └── res
│ └── values
│ └── dimens.xml
├── ui-view
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── kernel
│ └── finch
│ ├── DebugMenuView.kt
│ └── Finch.kt
└── utils
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
└── java
└── com
└── kernel
└── finch
└── utils
├── Helpers.kt
├── extensions
├── Bundle.kt
├── Context.kt
└── View.kt
└── view
└── GestureBlockingRecyclerView.kt
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig: http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | insert_final_newline = true
6 |
7 | [*.{yml, json}]
8 | indent_style = space
9 | indent_size = 2
10 |
11 | [*.{kt, kts, java}]
12 | indent_size = 4
13 | max_line_length = 100
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.idea
3 | .gradle
4 | /local.properties
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 |
--------------------------------------------------------------------------------
/assets/finch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/assets/finch.gif
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: 'dependencies.gradle'
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.6.21'
5 | repositories {
6 | mavenCentral()
7 | google()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.0.2'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/common-loggers/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/common-loggers/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.library"
2 | apply plugin: "kotlin-android"
3 |
4 | android {
5 | compileSdkVersion versions.compileSdk
6 | defaultConfig {
7 | minSdkVersion versions.minSdk
8 | targetSdkVersion versions.targetSdk
9 | versionCode versions.libraryVersionCode
10 | versionName versions.libraryVersion
11 | consumerProguardFiles "consumer-rules.pro"
12 | }
13 | }
14 |
15 | dependencies {
16 | implementation fileTree(dir: 'libs', include: ['*.jar'])
17 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin"
18 |
19 | implementation "androidx.room:room-runtime:$versions.room"
20 | implementation "com.google.code.gson:gson:$versions.gson"
21 | }
22 |
23 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
24 | kotlinOptions {
25 | jvmTarget = "1.8"
26 | freeCompilerArgs = ["-Xjvm-default=enable"]
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common-loggers/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/common-loggers/consumer-rules.pro
--------------------------------------------------------------------------------
/common-loggers/proguard-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/common-loggers/proguard-rules.pro
--------------------------------------------------------------------------------
/common-loggers/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/common-loggers/src/main/java/com/kernel/finch/common/loggers/FinchLogger.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.loggers
2 |
3 | interface FinchLogger {
4 |
5 | fun log(message: CharSequence, label: String? = null, payload: CharSequence? = null) = Unit
6 |
7 | fun clearLogs(label: String? = null) = Unit
8 |
9 | fun register(
10 | onNewLog: (message: CharSequence, label: String?, payload: CharSequence?) -> Unit,
11 | clearLogs: (label: String?) -> Unit
12 | ) = Unit
13 | }
14 |
--------------------------------------------------------------------------------
/common-loggers/src/main/java/com/kernel/finch/common/loggers/FinchNetworkLogger.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.loggers
2 |
3 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity
4 |
5 | interface FinchNetworkLogger {
6 |
7 | val logger: Any? get() = null
8 |
9 | fun logNetworkEvent(networkLog: NetworkLogEntity) = Unit
10 |
11 | fun clearNetworkLogs() = Unit
12 |
13 | fun register(
14 | onNewLog: (networkLog: NetworkLogEntity) -> Unit,
15 | clearLogs: () -> Unit
16 | ) = Unit
17 | }
18 |
--------------------------------------------------------------------------------
/common-loggers/src/main/java/com/kernel/finch/common/loggers/data/models/HeaderHttpModel.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.loggers.data.models
2 |
3 | import androidx.annotation.Keep
4 |
5 | @Keep
6 | data class HeaderHttpModel(
7 | val name: String,
8 | val value: String
9 | )
10 |
--------------------------------------------------------------------------------
/common-loggers/src/main/java/com/kernel/finch/common/loggers/data/models/MediaType.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.loggers.data.models
2 |
3 | object MediaType {
4 | const val APPLICATION_XML = "application/xml"
5 | const val APPLICATION_JSON = "application/json"
6 | const val APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"
7 |
8 | const val TEXT_HTML = "text/html"
9 | const val TEXT_PLAIN = "text/plain"
10 |
11 | const val WILDCARD = "*/*"
12 | }
--------------------------------------------------------------------------------
/common-loggers/src/main/java/com/kernel/finch/common/loggers/utils/GsonUtil.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.loggers.utils
2 |
3 | import com.google.gson.Gson
4 | import com.google.gson.GsonBuilder
5 |
6 | object GsonUtil {
7 |
8 | private val gson: Gson by lazy {
9 | GsonBuilder()
10 | .disableHtmlEscaping()
11 | .setPrettyPrinting()
12 | .create()
13 | }
14 |
15 | val instance: Gson
16 | get() {
17 | return gson.newBuilder()
18 | .serializeNulls()
19 | .create()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/common/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.library"
2 | apply plugin: "kotlin-android"
3 | apply plugin: "kotlin-android-extensions"
4 |
5 | android {
6 | compileSdkVersion versions.compileSdk
7 | defaultConfig {
8 | minSdkVersion versions.minSdk
9 | targetSdkVersion versions.targetSdk
10 | versionCode versions.libraryVersionCode
11 | versionName versions.libraryVersion
12 | consumerProguardFiles "consumer-rules.pro"
13 | }
14 | }
15 |
16 | dependencies {
17 | implementation fileTree(dir: 'libs', include: ['*.jar'])
18 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin"
19 | implementation "androidx.annotation:annotation:$versions.annotations"
20 | implementation "androidx.appcompat:appcompat:$versions.appCompat"
21 | implementation "androidx.recyclerview:recyclerview:$versions.recyclerView"
22 | api project(":common-loggers")
23 | }
24 |
25 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
26 | kotlinOptions {
27 | jvmTarget = "1.8"
28 | freeCompilerArgs = ["-Xjvm-default=enable"]
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/common/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/common/consumer-rules.pro
--------------------------------------------------------------------------------
/common/proguard-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/common/proguard-rules.pro
--------------------------------------------------------------------------------
/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/contracts/FinchListItem.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.contracts
2 |
3 | import com.kernel.finch.common.models.Text
4 |
5 | interface FinchListItem {
6 |
7 | val title: Text
8 |
9 | val id: String
10 | get() = when (val title = title) {
11 | is Text.CharSequence -> title.charSequence.toString()
12 | is Text.ResourceId -> title.resId.toString()
13 | }
14 |
15 | override fun equals(other: Any?): Boolean
16 |
17 | override fun hashCode(): Int
18 | }
19 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/contracts/component/Cell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.contracts.component
2 |
3 | interface Cell> {
4 |
5 | val id: String
6 |
7 | fun createViewHolderDelegate(): ViewHolder.Delegate
8 |
9 | override fun equals(other: Any?): Boolean
10 |
11 | override fun hashCode(): Int
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/contracts/component/Component.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.contracts.component
2 |
3 | import androidx.annotation.RestrictTo
4 | import java.util.*
5 |
6 | interface Component> {
7 |
8 | val id: String
9 |
10 | fun createComponentDelegate(): Delegate =
11 | throw IllegalStateException("Built-in Components should never create their own Delegates.")
12 |
13 | override fun equals(other: Any?): Boolean
14 |
15 | override fun hashCode(): Int
16 |
17 | interface Delegate> {
18 |
19 | fun createCells(component: C): List>
20 |
21 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
22 | @Suppress("UNCHECKED_CAST")
23 | fun forceCreateCells(component: Component<*>) = createCells(component as C)
24 | }
25 |
26 | companion object {
27 | val randomId get() = UUID.randomUUID().toString()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/contracts/component/ExpandableComponent.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.contracts.component
2 |
3 | import com.kernel.finch.common.contracts.Finch
4 | import com.kernel.finch.common.models.Text
5 |
6 | interface ExpandableComponent> : Component {
7 |
8 | val isExpandedInitially: Boolean
9 |
10 | fun getHeaderTitle(finch: Finch): Text
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/contracts/component/ViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.contracts.component
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import androidx.annotation.RestrictTo
6 | import androidx.recyclerview.widget.RecyclerView
7 |
8 | abstract class ViewHolder>(view: View) : RecyclerView.ViewHolder(view) {
9 |
10 | abstract fun bind(model: T)
11 |
12 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
13 | @Suppress("UNCHECKED_CAST")
14 | fun forceBind(model: Cell<*>) = try {
15 | bind(model as T)
16 | } catch (_: ClassCastException) {
17 | }
18 |
19 | abstract class Delegate> {
20 |
21 | abstract fun createViewHolder(parent: ViewGroup): ViewHolder
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/listeners/LogListener.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.listeners
2 |
3 | interface LogListener {
4 | fun onAdded(tag: String?, message: CharSequence, payload: CharSequence?)
5 | }
6 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/listeners/NetworkLogListener.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.listeners
2 |
3 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity
4 |
5 | interface NetworkLogListener {
6 | fun onAdded(networkLog: NetworkLogEntity)
7 | }
8 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/listeners/OverlayListener.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.listeners
2 |
3 | import android.graphics.Canvas
4 | import com.kernel.finch.common.models.Inset
5 |
6 | interface OverlayListener {
7 | fun onDrawOver(canvas: Canvas, insets: Inset)
8 | }
9 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/listeners/UpdateListener.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.listeners
2 |
3 | interface UpdateListener {
4 | fun onContentsChanged()
5 | fun onAllPendingChangesApplied() = Unit
6 | }
7 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/listeners/VisibilityListener.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.listeners
2 |
3 | interface VisibilityListener {
4 | fun onShown() = Unit
5 | fun onHidden() = Unit
6 | }
7 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/models/Inset.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.models
2 |
3 | data class Inset(
4 | val left: Int = 0,
5 | val top: Int = 0,
6 | val right: Int = 0,
7 | val bottom: Int = 0
8 | )
9 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/models/Position.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.models
2 |
3 | sealed class Position {
4 |
5 | object Bottom : Position()
6 |
7 | object Top : Position()
8 |
9 | class Below(val id: String) : Position()
10 |
11 | class Above(val id: String) : Position()
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/common/models/Text.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.common.models
2 |
3 | import androidx.annotation.StringRes
4 |
5 | sealed class Text {
6 |
7 | data class CharSequence(val charSequence: kotlin.CharSequence) : Text()
8 |
9 | data class ResourceId(@StringRes val resId: Int) : Text()
10 |
11 | var suffix: kotlin.CharSequence = ""
12 | private set
13 |
14 | fun with(suffix: kotlin.CharSequence) = this.also {
15 | this.suffix = suffix
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/Divider.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components
2 |
3 | import com.kernel.finch.common.contracts.component.Component
4 |
5 | data class Divider(
6 | override val id: String = Component.randomId
7 | ) : Component
8 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/KeyValueList.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components
2 |
3 | import androidx.annotation.StringRes
4 | import com.kernel.finch.common.contracts.Finch
5 | import com.kernel.finch.common.contracts.component.Component
6 | import com.kernel.finch.common.contracts.component.ExpandableComponent
7 | import com.kernel.finch.common.models.Text
8 |
9 | @Suppress("Unused")
10 | data class KeyValueList(
11 | val title: Text,
12 | val pairs: List>,
13 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
14 | override val id: String = Component.randomId
15 | ) : ExpandableComponent {
16 |
17 | constructor(
18 | title: CharSequence,
19 | pairs: List>,
20 | isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
21 | id: String = Component.randomId
22 | ) : this(
23 | title = Text.CharSequence(title),
24 | pairs = pairs.map { Text.CharSequence(it.first) to Text.CharSequence(it.second) },
25 | isExpandedInitially = isExpandedInitially,
26 | id = id
27 | )
28 |
29 | constructor(
30 | @StringRes title: Int,
31 | pairs: List>,
32 | isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
33 | id: String = Component.randomId
34 | ) : this(
35 | title = Text.ResourceId(title),
36 | pairs = pairs.map { Text.CharSequence(it.first) to Text.CharSequence(it.second) },
37 | isExpandedInitially = isExpandedInitially,
38 | id = id
39 | )
40 |
41 | override fun getHeaderTitle(finch: Finch) = title
42 |
43 | companion object {
44 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/LongText.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components
2 |
3 | import androidx.annotation.StringRes
4 | import com.kernel.finch.common.contracts.Finch
5 | import com.kernel.finch.common.contracts.component.Component
6 | import com.kernel.finch.common.contracts.component.ExpandableComponent
7 | import com.kernel.finch.common.models.Text
8 |
9 | @Suppress("Unused")
10 | data class LongText(
11 | val title: Text,
12 | val text: Text,
13 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
14 | override val id: String = Component.randomId
15 | ) : ExpandableComponent {
16 |
17 | constructor(
18 | title: CharSequence,
19 | text: CharSequence,
20 | isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
21 | id: String = Component.randomId
22 | ) : this(
23 | title = Text.CharSequence(title),
24 | text = Text.CharSequence(text),
25 | isExpandedInitially = isExpandedInitially,
26 | id = id
27 | )
28 |
29 | constructor(
30 | @StringRes title: Int,
31 | @StringRes text: Int,
32 | isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY,
33 | id: String = Component.randomId
34 | ) : this(
35 | title = Text.ResourceId(title),
36 | text = Text.ResourceId(text),
37 | isExpandedInitially = isExpandedInitially,
38 | id = id
39 | )
40 |
41 | override fun getHeaderTitle(finch: Finch) = title
42 |
43 | companion object {
44 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/Padding.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components
2 |
3 | import com.kernel.finch.common.contracts.component.Component
4 |
5 | data class Padding(
6 | override val id: String = Component.randomId
7 | ) : Component
8 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/ProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components
2 |
3 | import com.kernel.finch.common.contracts.component.Component
4 |
5 | data class ProgressBar(
6 | override val id: String = Component.randomId
7 | ) : Component
8 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/AnimationSpeed.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import com.kernel.finch.common.contracts.component.ValueWrapperComponent
4 | import com.kernel.finch.common.models.Text
5 |
6 | data class AnimationSpeed(
7 | override val text: (Boolean) -> Text = { Text.CharSequence(DEFAULT_TEXT) },
8 | val multiplier: Float = DEFAULT_MULTIPLIER,
9 | override val initialValue: Boolean = DEFAULT_INITIAL_VALUE,
10 | override val isEnabled: Boolean = DEFAULT_IS_ENABLED,
11 | override val isValuePersisted: Boolean = DEFAULT_IS_VALUE_PERSISTED,
12 | override val onValueChanged: (Boolean) -> Unit = DEFAULT_ON_VALUE_CHANGED
13 | ) : ValueWrapperComponent {
14 |
15 | override val id: String = ID
16 | override val shouldRequireConfirmation = false
17 |
18 | companion object {
19 | const val ID = "animationSpeed"
20 | private const val DEFAULT_TEXT = "Slow animations"
21 | private const val DEFAULT_MULTIPLIER = 4f
22 | private const val DEFAULT_INITIAL_VALUE = false
23 | private const val DEFAULT_IS_ENABLED = true
24 | private const val DEFAULT_IS_VALUE_PERSISTED = false
25 | private val DEFAULT_ON_VALUE_CHANGED: (Boolean) -> Unit = {}
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/AppInfo.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class AppInfo(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val shouldOpenInNewTask: Boolean = DEFAULT_SHOULD_OPEN_IN_NEW_TASK,
11 | val type: Label.Type = DEFAULT_TYPE,
12 | @DrawableRes val icon: Int? = DEFAULT_ICON,
13 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
14 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
15 | ) : Component {
16 |
17 | override val id: String = ID
18 |
19 | companion object {
20 | const val ID = "appInfo"
21 | private const val DEFAULT_TEXT = "App info"
22 | private const val DEFAULT_SHOULD_OPEN_IN_NEW_TASK = false
23 | private val DEFAULT_TYPE = Label.Type.BUTTON
24 | private val DEFAULT_ICON: Int? = null
25 | private const val DEFAULT_IS_ENABLED = true
26 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/DesignOverlay.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.ColorInt
4 | import androidx.annotation.Dimension
5 | import com.kernel.finch.common.contracts.component.ValueWrapperComponent
6 | import com.kernel.finch.common.models.Inset
7 | import com.kernel.finch.common.models.Text
8 |
9 | data class DesignOverlay(
10 | override val text: (Boolean) -> Text = { Text.CharSequence(DEFAULT_TEXT) },
11 | @Dimension val grid: Int? = DEFAULT_GRID,
12 | @Dimension val overlayPrimary: Int? = DEFAULT_OVERLAY_PRIMARY,
13 | @Dimension val overlaySecondary: Int? = DEFAULT_OVERLAY_SECONDARY,
14 | @ColorInt val color: Int? = DEFAULT_COLOR,
15 | override val initialValue: Boolean = DEFAULT_INITIAL_VALUE,
16 | override val isEnabled: Boolean = DEFAULT_IS_ENABLED,
17 | override val isValuePersisted: Boolean = DEFAULT_IS_VALUE_PERSISTED,
18 | val applyInsets: ((windowInsets: Inset) -> Inset)? = DEFAULT_APPLY_INSETS,
19 | override val onValueChanged: (Boolean) -> Unit = DEFAULT_ON_VALUE_CHANGED
20 | ) : ValueWrapperComponent {
21 |
22 | override val id: String = ID
23 | override val shouldRequireConfirmation = false
24 |
25 | companion object {
26 | const val ID = "designOverlay"
27 | private const val DEFAULT_TEXT = "Design overlay"
28 | private val DEFAULT_GRID: Int? = null
29 | private val DEFAULT_OVERLAY_PRIMARY: Int? = null
30 | private val DEFAULT_OVERLAY_SECONDARY: Int? = null
31 | private val DEFAULT_COLOR: Int? = null
32 | private const val DEFAULT_INITIAL_VALUE = false
33 | private const val DEFAULT_IS_ENABLED = true
34 | private const val DEFAULT_IS_VALUE_PERSISTED = false
35 | private val DEFAULT_APPLY_INSETS: ((windowInsets: Inset) -> Inset)? = null
36 | private val DEFAULT_ON_VALUE_CHANGED: (Boolean) -> Unit = {}
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/DeveloperOptions.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class DeveloperOptions(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val shouldOpenInNewTask: Boolean = DEFAULT_SHOULD_OPEN_IN_NEW_TASK,
11 | val type: Label.Type = DEFAULT_TYPE,
12 | @DrawableRes val icon: Int? = DEFAULT_ICON,
13 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
14 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
15 | ) : Component {
16 |
17 | override val id: String = ID
18 |
19 | companion object {
20 | const val ID = "developerOptions"
21 | private const val DEFAULT_TEXT = "Developer options"
22 | private const val DEFAULT_SHOULD_OPEN_IN_NEW_TASK = false
23 | private val DEFAULT_TYPE = Label.Type.BUTTON
24 | private val DEFAULT_ICON: Int? = null
25 | private const val DEFAULT_IS_ENABLED = true
26 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/DeviceInfo.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import com.kernel.finch.common.contracts.Finch
4 | import com.kernel.finch.common.contracts.component.ExpandableComponent
5 | import com.kernel.finch.common.models.Text
6 |
7 | data class DeviceInfo(
8 | val title: Text = Text.CharSequence(DEFAULT_TITLE),
9 | val shouldShowManufacturer: Boolean = DEFAULT_SHOULD_SHOW_MANUFACTURER,
10 | val shouldShowModel: Boolean = DEFAULT_SHOULD_SHOW_MODEL,
11 | val shouldShowResolutionsPx: Boolean = DEFAULT_SHOULD_SHOW_RESOLUTION_PX,
12 | val shouldShowResolutionsDp: Boolean = DEFAULT_SHOULD_SHOW_RESOLUTION_DP,
13 | val shouldShowDensity: Boolean = DEFAULT_SHOULD_SHOW_DENSITY,
14 | val shouldShowAndroidVersion: Boolean = DEFAULT_SHOULD_SHOW_ANDROID_VERSION,
15 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY
16 | ) : ExpandableComponent {
17 |
18 | override val id: String = ID
19 |
20 | override fun getHeaderTitle(finch: Finch) = title
21 |
22 | companion object {
23 | const val ID = "deviceInfo"
24 | private const val DEFAULT_TITLE = "Device info"
25 | private const val DEFAULT_SHOULD_SHOW_MANUFACTURER = true
26 | private const val DEFAULT_SHOULD_SHOW_MODEL = true
27 | private const val DEFAULT_SHOULD_SHOW_RESOLUTION_PX = true
28 | private const val DEFAULT_SHOULD_SHOW_RESOLUTION_DP = true
29 | private const val DEFAULT_SHOULD_SHOW_DENSITY = true
30 | private const val DEFAULT_SHOULD_SHOW_ANDROID_VERSION = true
31 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/ForceCrash.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class ForceCrash(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val exception: RuntimeException = RuntimeException(DEFAULT_EXCEPTION_MESSAGE),
11 | val type: Label.Type = DEFAULT_TYPE,
12 | @DrawableRes val icon: Int? = DEFAULT_ICON,
13 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
14 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
15 | ) : Component {
16 |
17 | override val id: String = ID
18 |
19 | companion object {
20 | const val ID = "forceCrash"
21 | private const val DEFAULT_TEXT = "Force crash"
22 | private const val DEFAULT_EXCEPTION_MESSAGE = "Test crash"
23 | private val DEFAULT_TYPE = Label.Type.BUTTON
24 | private val DEFAULT_ICON: Int? = null
25 | private const val DEFAULT_IS_ENABLED = true
26 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/Gallery.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class Gallery(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val type: Label.Type = DEFAULT_TYPE,
11 | @DrawableRes val icon: Int? = DEFAULT_ICON,
12 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
13 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
14 | ) : Component {
15 |
16 | override val id: String = ID
17 |
18 | companion object {
19 | const val ID = "galleryButton"
20 | private const val DEFAULT_TEXT = "Open the gallery"
21 | private val DEFAULT_TYPE = Label.Type.BUTTON
22 | private val DEFAULT_ICON: Int? = null
23 | private const val DEFAULT_IS_ENABLED = true
24 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/Header.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.StringRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 |
7 | @Suppress("Unused")
8 | data class Header(
9 | val title: Text,
10 | val subtitle: Text? = DEFAULT_SUBTITLE?.let { Text.CharSequence(it) },
11 | val text: Text? = DEFAULT_TEXT?.let { Text.CharSequence(it) }
12 | ) : Component {
13 |
14 | constructor(
15 | title: CharSequence,
16 | subtitle: CharSequence? = DEFAULT_SUBTITLE,
17 | text: CharSequence? = DEFAULT_TEXT
18 | ) : this(
19 | title = Text.CharSequence(title),
20 | subtitle = subtitle?.let { Text.CharSequence(it) },
21 | text = text?.let { Text.CharSequence(it) }
22 | )
23 |
24 | constructor(
25 | @StringRes title: Int,
26 | @StringRes subtitle: Int? = DEFAULT_SUBTITLE_INT,
27 | @StringRes text: Int? = DEFAULT_TEXT_INT
28 | ) : this(
29 | title = Text.ResourceId(title),
30 | subtitle = subtitle?.let { Text.ResourceId(it) },
31 | text = text?.let { Text.ResourceId(it) }
32 | )
33 |
34 | override val id: String = ID
35 |
36 | companion object {
37 | const val ID = "header"
38 | private val DEFAULT_SUBTITLE: CharSequence? = null
39 | private val DEFAULT_SUBTITLE_INT: Int? = null
40 | private val DEFAULT_TEXT: CharSequence? = null
41 | private val DEFAULT_TEXT_INT: Int? = null
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/Logs.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import com.kernel.finch.common.contracts.Finch
4 | import com.kernel.finch.common.contracts.component.ExpandableComponent
5 | import com.kernel.finch.common.models.Text
6 | import java.text.SimpleDateFormat
7 | import java.util.*
8 |
9 | data class Logs(
10 | val title: Text = Text.CharSequence(DEFAULT_TITLE),
11 | val maxItemCount: Int = DEFAULT_MAX_ITEM_COUNT,
12 | val timeFormatter: ((Long) -> CharSequence) = { DEFAULT_DATE_FORMAT.format(it) },
13 | val label: String? = DEFAULT_LABEL,
14 | val isHorizontalScrollEnabled: Boolean = DEFAULT_IS_HORIZONTAL_SCROLL_ENABLED,
15 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY
16 | ) : ExpandableComponent {
17 |
18 | override val id = formatId(label)
19 |
20 | override fun getHeaderTitle(finch: Finch) = title
21 |
22 | companion object {
23 | private const val DEFAULT_TITLE = "Logs"
24 | private const val DEFAULT_MAX_ITEM_COUNT = 10
25 | private val DEFAULT_DATE_FORMAT by lazy {
26 | SimpleDateFormat(
27 | Finch.LOG_TIME_FORMAT,
28 | Locale.ENGLISH
29 | )
30 | }
31 | private val DEFAULT_LABEL: String? = null
32 | private const val DEFAULT_IS_HORIZONTAL_SCROLL_ENABLED = false
33 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
34 |
35 | fun formatId(label: String?) = "logList_$label"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/LoremIpsumGenerator.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class LoremIpsumGenerator(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val minimumWordCount: Int = DEFAULT_MINIMUM_WORD_COUNT,
11 | val maximumWordCount: Int = DEFAULT_MAXIMUM_WORD_COUNT,
12 | val shouldStartWithLoremIpsum: Boolean = DEFAULT_SHOULD_START_WITH_LOREM_IPSUM,
13 | val shouldGenerateSentence: Boolean = DEFAULT_SHOULD_GENERATE_SENTENCE,
14 | val type: Label.Type = DEFAULT_TYPE,
15 | @DrawableRes val icon: Int? = DEFAULT_ICON,
16 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
17 | val onLoremIpsumReady: (generatedText: String) -> Unit
18 | ) : Component {
19 |
20 | override val id: String = ID
21 |
22 | companion object {
23 | const val ID = "loremIpsumGenerator"
24 | private const val DEFAULT_TEXT = "Generate Lorem Ipsum"
25 | private const val DEFAULT_MINIMUM_WORD_COUNT = 5
26 | private const val DEFAULT_MAXIMUM_WORD_COUNT = 20
27 | private const val DEFAULT_SHOULD_START_WITH_LOREM_IPSUM = true
28 | private const val DEFAULT_SHOULD_GENERATE_SENTENCE = false
29 | private val DEFAULT_TYPE = Label.Type.BUTTON
30 | private val DEFAULT_ICON: Int? = null
31 | private const val DEFAULT_IS_ENABLED = true
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/NetworkLogs.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import com.kernel.finch.common.contracts.Finch
4 | import com.kernel.finch.common.contracts.component.ExpandableComponent
5 | import com.kernel.finch.common.models.Text
6 | import java.text.SimpleDateFormat
7 | import java.util.*
8 |
9 | data class NetworkLogs(
10 | val title: Text = Text.CharSequence(DEFAULT_TITLE),
11 | val baseUrl: String = DEFAULT_BASE_URL,
12 | val maxItemCount: Int = DEFAULT_MAX_ITEM_COUNT,
13 | val maxItemTitleLength: Int? = DEFAULT_MAX_ITEM_TITLE_LENGTH,
14 | val timeFormatter: ((Long) -> CharSequence) = { DEFAULT_TIME_FORMAT.format(it) },
15 | val dateTimeFormatter: ((Long) -> CharSequence) = { DEFAULT_DATETIME_FORMAT.format(it) },
16 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY
17 | ) : ExpandableComponent {
18 |
19 | override val id: String = ID
20 |
21 | override fun getHeaderTitle(finch: Finch) = title
22 |
23 | companion object {
24 | const val ID = "networkLogs"
25 | private const val DEFAULT_TITLE = "Network logs"
26 | private const val DEFAULT_BASE_URL = ""
27 | private const val DEFAULT_MAX_ITEM_COUNT = 10
28 | private val DEFAULT_MAX_ITEM_TITLE_LENGTH: Int? = null
29 | private val DEFAULT_TIME_FORMAT by lazy {
30 | SimpleDateFormat(
31 | Finch.LOG_TIME_FORMAT,
32 | Locale.ENGLISH
33 | )
34 | }
35 | private val DEFAULT_DATETIME_FORMAT by lazy {
36 | SimpleDateFormat(
37 | Finch.LOG_DATE_AND_TIME_FORMAT,
38 | Locale.ENGLISH
39 | )
40 | }
41 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/ScreenCaptureToolbox.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import com.kernel.finch.common.contracts.Finch
4 | import com.kernel.finch.common.contracts.component.ExpandableComponent
5 | import com.kernel.finch.common.models.Text
6 |
7 | data class ScreenCaptureToolbox(
8 | val title: Text = Text.CharSequence(DEFAULT_TITLE),
9 | val imageText: Text? = Text.CharSequence(DEFAULT_IMAGE_TEXT),
10 | val videoText: Text? = Text.CharSequence(DEFAULT_VIDEO_TEXT),
11 | val galleryText: Text = Text.CharSequence(DEFAULT_GALLERY_TEXT),
12 | override val isExpandedInitially: Boolean = DEFAULT_IS_EXPANDED_INITIALLY
13 | ) : ExpandableComponent {
14 |
15 | override val id: String = ID
16 |
17 | override fun getHeaderTitle(finch: Finch) = title
18 |
19 | companion object {
20 | const val ID = "screenCaptureToolbox"
21 | private const val DEFAULT_TITLE = "Screen capture tools"
22 | private const val DEFAULT_IMAGE_TEXT = "Take a screenshot"
23 | private const val DEFAULT_VIDEO_TEXT = "Record a video"
24 | private const val DEFAULT_GALLERY_TEXT = "Open the gallery"
25 | private const val DEFAULT_IS_EXPANDED_INITIALLY = false
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/ScreenRecording.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class ScreenRecording(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val type: Label.Type = DEFAULT_TYPE,
11 | @DrawableRes val icon: Int? = DEFAULT_ICON,
12 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
13 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
14 | ) : Component {
15 |
16 | override val id: String = ID
17 |
18 | companion object {
19 | const val ID = "screenRecording"
20 | private const val DEFAULT_TEXT = "Record a video"
21 | private val DEFAULT_TYPE = Label.Type.BUTTON
22 | private val DEFAULT_ICON: Int? = null
23 | private const val DEFAULT_IS_ENABLED = true
24 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/com/kernel/finch/components/special/Screenshot.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.components.special
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.common.models.Text
6 | import com.kernel.finch.components.Label
7 |
8 | data class Screenshot(
9 | val text: Text = Text.CharSequence(DEFAULT_TEXT),
10 | val type: Label.Type = DEFAULT_TYPE,
11 | @DrawableRes val icon: Int? = DEFAULT_ICON,
12 | val isEnabled: Boolean = DEFAULT_IS_ENABLED,
13 | val onButtonPressed: () -> Unit = DEFAULT_ON_BUTTON_PRESSED
14 | ) : Component {
15 |
16 | override val id: String = ID
17 |
18 | companion object {
19 | const val ID = "screenshot"
20 | private const val DEFAULT_TEXT = "Take a screenshot"
21 | private val DEFAULT_TYPE = Label.Type.BUTTON
22 | private val DEFAULT_ICON: Int? = null
23 | private const val DEFAULT_IS_ENABLED = true
24 | private val DEFAULT_ON_BUTTON_PRESSED: () -> Unit = {}
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.library"
2 | apply plugin: "kotlin-android"
3 | apply plugin: "kotlin-android-extensions"
4 | apply plugin: "kotlin-kapt"
5 |
6 | android {
7 | compileSdkVersion versions.compileSdk
8 | defaultConfig {
9 | minSdkVersion versions.minSdk
10 | targetSdkVersion versions.targetSdk
11 | versionCode versions.libraryVersionCode
12 | versionName versions.libraryVersion
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 | }
16 |
17 | dependencies {
18 | implementation fileTree(dir: 'libs', include: ['*.jar'])
19 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin"
20 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutines"
21 | implementation "androidx.appcompat:appcompat:$versions.appCompat"
22 | implementation "androidx.recyclerview:recyclerview:$versions.recyclerView"
23 | implementation "androidx.constraintlayout:constraintlayout:$versions.constraintLayout"
24 | implementation "com.google.android.material:material:$versions.material"
25 | implementation "androidx.lifecycle:lifecycle-extensions:$versions.lifecycle"
26 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
27 | implementation "io.coil-kt:coil:$versions.coil"
28 | implementation "io.coil-kt:coil-video:$versions.coil"
29 | implementation "androidx.room:room-runtime:$versions.room"
30 | kapt "androidx.room:room-compiler:$versions.room"
31 | implementation project(":utils")
32 | implementation project(":common")
33 | }
34 |
35 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
36 | kotlinOptions {
37 | jvmTarget = "1.8"
38 | freeCompilerArgs = ["-Xjvm-default=enable"]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/core/consumer-rules.pro
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kernel0x/finch/cceb0ea4fe67dfc3cda2bb927b8ab912b799b459/core/proguard-rules.pro
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
20 |
21 |
24 |
25 |
28 |
29 |
34 |
35 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/FinchCore.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch
2 |
3 | import com.kernel.finch.core.FinchImpl
4 |
5 | object FinchCore {
6 |
7 | lateinit var implementation: FinchImpl
8 | internal set
9 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/data/db/FinchDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.data.db
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity
8 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity.Companion.TABLE_NAME
9 |
10 | @Database(entities = [NetworkLogEntity::class], version = 1, exportSchema = false)
11 | internal abstract class FinchDatabase : RoomDatabase() {
12 |
13 | abstract fun networkLog(): NetworkLogDao
14 |
15 | companion object {
16 |
17 | @Volatile
18 | private var instance: FinchDatabase? = null
19 |
20 | fun getInstance(context: Context): FinchDatabase =
21 | instance ?: synchronized(this) {
22 | val newInstance = instance ?: Room.databaseBuilder(
23 | context.applicationContext,
24 | FinchDatabase::class.java,
25 | TABLE_NAME
26 | ).build().also { instance = it }
27 | newInstance
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/data/db/NetworkLogDao.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.data.db
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.room.*
5 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity
6 | import com.kernel.finch.common.loggers.data.models.NetworkLogEntity.Companion.TABLE_NAME
7 |
8 | @Dao
9 | internal interface NetworkLogDao {
10 |
11 | @Query("SELECT * FROM $TABLE_NAME ORDER BY requestDate DESC, id DESC")
12 | fun getAll(): LiveData>
13 |
14 | @Query("SELECT * FROM $TABLE_NAME WHERE path LIKE '%' || :search ||'%' ORDER BY requestDate DESC, id DESC")
15 | fun getAll(search: String): LiveData>
16 |
17 | @Query("SELECT * FROM $TABLE_NAME WHERE responseCode LIKE '%' || :responseCode ||'%' ORDER BY requestDate DESC, id DESC")
18 | fun getAll(responseCode: Int?): LiveData>
19 |
20 | @Query("SELECT * FROM $TABLE_NAME WHERE id = :id")
21 | fun getById(id: Long): LiveData
22 |
23 | @Query("DELETE FROM $TABLE_NAME WHERE id = :id")
24 | fun deleteById(id: Long): Int
25 |
26 | @Query("DELETE FROM $TABLE_NAME WHERE requestDate <= :threshold")
27 | fun deleteWhereRequestDate(threshold: Long)
28 |
29 | @Query("DELETE FROM $TABLE_NAME")
30 | fun deleteAll(): Int
31 |
32 | @Insert(onConflict = OnConflictStrategy.REPLACE)
33 | fun insert(entity: NetworkLogEntity): Long
34 |
35 | @Update
36 | fun update(entity: NetworkLogEntity): Int
37 |
38 | @Delete
39 | fun delete(entity: NetworkLogEntity): Int
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/data/models/Period.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.data.models
2 |
3 | internal enum class Period {
4 | ONE_HOUR,
5 | ONE_DAY,
6 | ONE_WEEK,
7 | FOREVER
8 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/CheckBoxCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import android.widget.CheckBox
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.ViewHolder
8 | import com.kernel.finch.common.models.Text
9 | import com.kernel.finch.core.R
10 | import com.kernel.finch.core.util.extension.setText
11 |
12 | internal data class CheckBoxCell(
13 | override val id: String,
14 | private val text: Text,
15 | private val isChecked: Boolean,
16 | private val isEnabled: Boolean,
17 | private val onValueChanged: (Boolean) -> Unit
18 | ) : Cell {
19 |
20 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
21 |
22 | override fun createViewHolder(parent: ViewGroup) = CheckBoxViewHolder(parent)
23 | }
24 |
25 | private class CheckBoxViewHolder(parent: ViewGroup) : ViewHolder(
26 | LayoutInflater.from(parent.context).inflate(R.layout.finch_cell_check_box, parent, false)
27 | ) {
28 |
29 | private val checkBox = itemView.findViewById(R.id.finch_check_box)
30 |
31 | override fun bind(model: CheckBoxCell) {
32 | checkBox.run {
33 | setText(model.text)
34 | setOnCheckedChangeListener(null)
35 | isChecked = model.isChecked
36 | isEnabled = model.isEnabled
37 | setOnCheckedChangeListener { _, isChecked -> model.onValueChanged(isChecked) }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/DividerCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.kernel.finch.common.contracts.component.Cell
6 | import com.kernel.finch.common.contracts.component.ViewHolder
7 | import com.kernel.finch.core.R
8 | import com.kernel.finch.utils.extensions.colorResource
9 |
10 | internal data class DividerCell(
11 | override val id: String
12 | ) : Cell {
13 |
14 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
15 |
16 | override fun createViewHolder(parent: ViewGroup) = DividerViewHolder(parent)
17 | }
18 |
19 | private class DividerViewHolder(parent: ViewGroup) : ViewHolder(
20 | LayoutInflater.from(parent.context).inflate(R.layout.finch_cell_divider, parent, false)
21 | ) {
22 |
23 | override fun bind(model: DividerCell) =
24 | itemView.setBackgroundColor(itemView.context.colorResource(android.R.attr.textColorPrimary))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/ExpandedItemCheckBoxCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import android.widget.CheckBox
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.ViewHolder
8 | import com.kernel.finch.common.models.Text
9 | import com.kernel.finch.core.R
10 | import com.kernel.finch.core.util.extension.setText
11 |
12 | internal data class ExpandedItemCheckBoxCell(
13 | override val id: String,
14 | private val text: Text,
15 | private val isChecked: Boolean,
16 | private val isEnabled: Boolean,
17 | private val onValueChanged: (Boolean) -> Unit
18 | ) : Cell {
19 |
20 | override fun createViewHolderDelegate() =
21 | object : ViewHolder.Delegate() {
22 |
23 | override fun createViewHolder(parent: ViewGroup) = CheckBoxViewHolder(parent)
24 | }
25 |
26 | private class CheckBoxViewHolder(parent: ViewGroup) :
27 | ViewHolder(
28 | LayoutInflater.from(parent.context)
29 | .inflate(R.layout.finch_cell_expanded_item_check_box, parent, false)
30 | ) {
31 |
32 | private val checkBox = itemView.findViewById(R.id.finch_check_box)
33 |
34 | override fun bind(model: ExpandedItemCheckBoxCell) {
35 | checkBox.run {
36 | setText(model.text)
37 | setOnCheckedChangeListener(null)
38 | isChecked = model.isChecked
39 | isEnabled = model.isEnabled
40 | setOnCheckedChangeListener { _, isChecked -> model.onValueChanged(isChecked) }
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/ExpandedItemRadioButtonCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import android.widget.RadioButton
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.ViewHolder
8 | import com.kernel.finch.common.models.Text
9 | import com.kernel.finch.core.R
10 | import com.kernel.finch.core.util.extension.setText
11 |
12 | internal data class ExpandedItemRadioButtonCell(
13 | override val id: String,
14 | private val text: Text,
15 | private val isChecked: Boolean,
16 | private val isEnabled: Boolean,
17 | private val onValueChanged: (Boolean) -> Unit
18 | ) : Cell {
19 |
20 | override fun createViewHolderDelegate() =
21 | object : ViewHolder.Delegate() {
22 |
23 | override fun createViewHolder(parent: ViewGroup) = SwitchViewHolder(parent)
24 | }
25 |
26 | private class SwitchViewHolder(parent: ViewGroup) : ViewHolder(
27 | LayoutInflater.from(parent.context)
28 | .inflate(R.layout.finch_cell_expanded_item_radio_button, parent, false)
29 | ) {
30 |
31 | private val radioButton = itemView.findViewById(R.id.finch_radio_button)
32 |
33 | override fun bind(model: ExpandedItemRadioButtonCell) = radioButton.run {
34 | setText(model.text)
35 | setOnCheckedChangeListener(null)
36 | isChecked = model.isChecked
37 | isEnabled = model.isEnabled
38 | setOnCheckedChangeListener { _, isChecked -> model.onValueChanged(isChecked) }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/HeaderCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import android.widget.TextView
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.ViewHolder
8 | import com.kernel.finch.common.models.Text
9 | import com.kernel.finch.core.R
10 | import com.kernel.finch.core.util.extension.setText
11 | import com.kernel.finch.core.util.extension.visible
12 |
13 | internal data class HeaderCell(
14 | override val id: String,
15 | private val title: Text,
16 | private val subtitle: Text?,
17 | private val text: Text?
18 | ) : Cell {
19 |
20 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
21 |
22 | override fun createViewHolder(parent: ViewGroup) = HeaderViewHolder(parent)
23 | }
24 |
25 | private class HeaderViewHolder(parent: ViewGroup) : ViewHolder(
26 | LayoutInflater.from(parent.context).inflate(R.layout.finch_cell_header, parent, false)
27 | ) {
28 |
29 | private val titleTextView = itemView.findViewById(R.id.finch_title)
30 | private val subtitleTextView = itemView.findViewById(R.id.finch_subtitle)
31 | private val textTextView = itemView.findViewById(R.id.finch_text)
32 |
33 | override fun bind(model: HeaderCell) {
34 | titleTextView.setText(model.title)
35 | subtitleTextView.visible = model.subtitle != null
36 | subtitleTextView.setText(model.subtitle)
37 | textTextView.visible = model.text != null
38 | textTextView.setText(model.text)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/PaddingCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.kernel.finch.common.contracts.component.Cell
6 | import com.kernel.finch.common.contracts.component.ViewHolder
7 | import com.kernel.finch.core.R
8 |
9 | internal data class PaddingCell(
10 | override val id: String
11 | ) : Cell {
12 |
13 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
14 |
15 | override fun createViewHolder(parent: ViewGroup) = PaddingViewHolder(parent)
16 | }
17 |
18 | private class PaddingViewHolder(parent: ViewGroup) :
19 | ViewHolder(
20 | LayoutInflater.from(parent.context).inflate(R.layout.finch_cell_padding, parent, false)
21 | ) {
22 |
23 | override fun bind(model: PaddingCell) = Unit
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/ProgressBarCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.kernel.finch.common.contracts.component.Cell
6 | import com.kernel.finch.common.contracts.component.ViewHolder
7 | import com.kernel.finch.core.R
8 |
9 | internal data class ProgressBarCell(
10 | override val id: String
11 | ) : Cell {
12 |
13 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
14 |
15 | override fun createViewHolder(parent: ViewGroup) = LoadingIndicatorViewHolder(parent)
16 | }
17 |
18 | private class LoadingIndicatorViewHolder(parent: ViewGroup) : ViewHolder(
19 | LayoutInflater.from(parent.context)
20 | .inflate(R.layout.finch_cell_progress_bar, parent, false)
21 | ) {
22 |
23 | override fun bind(model: ProgressBarCell) = Unit
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/cells/SwitchCell.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.cells
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.appcompat.widget.SwitchCompat
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.ViewHolder
8 | import com.kernel.finch.common.models.Text
9 | import com.kernel.finch.core.R
10 | import com.kernel.finch.core.util.extension.setText
11 |
12 | internal data class SwitchCell(
13 | override val id: String,
14 | private val text: Text,
15 | private val isChecked: Boolean,
16 | private val isEnabled: Boolean,
17 | private val onValueChanged: (Boolean) -> Unit
18 | ) : Cell {
19 |
20 | override fun createViewHolderDelegate() = object : ViewHolder.Delegate() {
21 |
22 | override fun createViewHolder(parent: ViewGroup) = SwitchViewHolder(parent)
23 | }
24 |
25 | private class SwitchViewHolder(parent: ViewGroup) : ViewHolder(
26 | LayoutInflater.from(parent.context).inflate(R.layout.finch_cell_switch, parent, false)
27 | ) {
28 |
29 | private val switch = itemView.findViewById(R.id.finch_switch)
30 |
31 | override fun bind(model: SwitchCell) = switch.run {
32 | setText(model.text)
33 | setOnCheckedChangeListener(null)
34 | isChecked = model.isChecked
35 | isEnabled = model.isEnabled
36 | setOnCheckedChangeListener { _, isChecked -> model.onValueChanged(isChecked) }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/AnimationSpeedDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import android.animation.ValueAnimator
4 | import com.kernel.finch.common.contracts.component.Cell
5 | import com.kernel.finch.components.special.AnimationSpeed
6 | import com.kernel.finch.core.list.cells.SwitchCell
7 | import com.kernel.finch.core.list.delegates.shared.ValueWrapperComponentDelegate
8 |
9 | internal class AnimationSpeedDelegate :
10 | ValueWrapperComponentDelegate.Boolean() {
11 |
12 | override fun createCells(component: AnimationSpeed): List> =
13 | getCurrentValue(component).let { currentValue ->
14 | listOf(
15 | SwitchCell(
16 | id = component.id,
17 | text = component.text(currentValue),
18 | isChecked = currentValue,
19 | isEnabled = component.isEnabled,
20 | onValueChanged = { newValue -> setCurrentValue(component, newValue) }
21 | )
22 | )
23 | }
24 |
25 | override fun callOnValueChanged(
26 | component: AnimationSpeed,
27 | newValue: kotlin.Boolean
28 | ) {
29 | try {
30 | ValueAnimator::class.java.methods.firstOrNull { it.name == "setDurationScale" }
31 | ?.invoke(null, if (newValue) component.multiplier else 1f)
32 | } catch (_: Throwable) {
33 | }
34 | super.callOnValueChanged(component, newValue)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/AppInfoDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.provider.Settings
6 | import com.kernel.finch.FinchCore
7 | import com.kernel.finch.common.contracts.component.Cell
8 | import com.kernel.finch.common.contracts.component.Component
9 | import com.kernel.finch.components.special.AppInfo
10 | import com.kernel.finch.core.util.createTextComponentFromType
11 |
12 | internal class AppInfoDelegate : Component.Delegate {
13 |
14 | override fun createCells(component: AppInfo): List> = listOf(
15 | createTextComponentFromType(
16 | type = component.type,
17 | id = component.id,
18 | text = component.text,
19 | isEnabled = component.isEnabled,
20 | icon = component.icon,
21 | onItemSelected = {
22 | FinchCore.implementation.currentActivity?.run {
23 | startActivity(Intent().apply {
24 | action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
25 | data = Uri.fromParts("package", packageName, null)
26 | if (component.shouldOpenInNewTask) {
27 | flags = Intent.FLAG_ACTIVITY_NEW_TASK
28 | }
29 | })
30 | }
31 | component.onButtonPressed()
32 | }
33 | )
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/CheckBoxDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.components.CheckBox
5 | import com.kernel.finch.core.list.cells.CheckBoxCell
6 | import com.kernel.finch.core.list.delegates.shared.ValueWrapperComponentDelegate
7 |
8 | internal class CheckBoxDelegate : ValueWrapperComponentDelegate.Boolean() {
9 |
10 | override fun createCells(component: CheckBox): List> =
11 | getUiValue(component).let { uiValue ->
12 | listOf(
13 | CheckBoxCell(
14 | id = component.id,
15 | text = component.text(uiValue).let { title ->
16 | if (component.shouldRequireConfirmation && hasPendingChanges(component))
17 | title.with("*")
18 | else
19 | title
20 | },
21 | isChecked = uiValue,
22 | isEnabled = component.isEnabled,
23 | onValueChanged = { setUiValue(component, it) })
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/DeveloperOptionsDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import android.content.Intent
4 | import android.provider.Settings
5 | import com.kernel.finch.FinchCore
6 | import com.kernel.finch.common.contracts.component.Cell
7 | import com.kernel.finch.common.contracts.component.Component
8 | import com.kernel.finch.components.special.DeveloperOptions
9 | import com.kernel.finch.core.util.createTextComponentFromType
10 |
11 | internal class DeveloperOptionsDelegate : Component.Delegate {
12 |
13 | override fun createCells(component: DeveloperOptions): List> = listOf(
14 | createTextComponentFromType(
15 | type = component.type,
16 | id = component.id,
17 | text = component.text,
18 | isEnabled = component.isEnabled,
19 | icon = component.icon,
20 | onItemSelected = {
21 | FinchCore.implementation.currentActivity?.run {
22 | startActivity(Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS).apply {
23 | if (component.shouldOpenInNewTask) {
24 | flags = Intent.FLAG_ACTIVITY_NEW_TASK
25 | }
26 | })
27 | }
28 | component.onButtonPressed()
29 | }
30 | )
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/DividerDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.components.Divider
6 | import com.kernel.finch.core.list.cells.DividerCell
7 |
8 | internal class DividerDelegate : Component.Delegate {
9 |
10 | override fun createCells(component: Divider): List> =
11 | listOf(DividerCell(id = component.id))
12 | }
13 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/ForceCrashDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.components.special.ForceCrash
6 | import com.kernel.finch.core.util.createTextComponentFromType
7 |
8 | internal class ForceCrashDelegate : Component.Delegate {
9 |
10 | override fun createCells(component: ForceCrash): List> = listOf(
11 | createTextComponentFromType(
12 | type = component.type,
13 | id = component.id,
14 | text = component.text,
15 | isEnabled = component.isEnabled,
16 | icon = component.icon,
17 | onItemSelected = {
18 | component.onButtonPressed()
19 | throw RuntimeException(component.exception)
20 | }
21 | )
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/GalleryDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.FinchCore
4 | import com.kernel.finch.common.contracts.component.Cell
5 | import com.kernel.finch.common.contracts.component.Component
6 | import com.kernel.finch.components.special.Gallery
7 | import com.kernel.finch.core.util.createTextComponentFromType
8 |
9 | internal class GalleryDelegate : Component.Delegate {
10 |
11 | override fun createCells(component: Gallery): List> = listOf(
12 | createTextComponentFromType(
13 | type = component.type,
14 | id = component.id,
15 | text = component.text,
16 | isEnabled = component.isEnabled,
17 | icon = component.icon,
18 | onItemSelected = {
19 | component.onButtonPressed()
20 | FinchCore.implementation.openGallery()
21 | }
22 | )
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/HeaderDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.components.special.Header
6 | import com.kernel.finch.core.list.cells.HeaderCell
7 |
8 | internal class HeaderDelegate : Component.Delegate {
9 |
10 | override fun createCells(component: Header): List> = listOf(
11 | HeaderCell(
12 | id = component.id,
13 | title = component.title,
14 | subtitle = component.subtitle,
15 | text = component.text
16 | )
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/ItemListDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.FinchListItem
4 | import com.kernel.finch.common.contracts.component.Cell
5 | import com.kernel.finch.components.ItemList
6 | import com.kernel.finch.core.list.cells.ExpandedItemTextCell
7 | import com.kernel.finch.core.list.delegates.shared.ExpandableComponentDelegate
8 |
9 | internal class ItemListDelegate : ExpandableComponentDelegate> {
10 |
11 | override fun canExpand(component: ItemList) = component.items.isNotEmpty()
12 |
13 | override fun MutableList>.addItems(component: ItemList) {
14 | addAll(component.items.map { item ->
15 | ExpandedItemTextCell(
16 | id = "${component.id}_${item.id}",
17 | text = item.title,
18 | isEnabled = true,
19 | onItemSelected = component.onItemSelected?.let { onItemSelected ->
20 | {
21 | component.items.firstOrNull { it.id == item.id }?.let { onItemSelected(it) }
22 | Unit
23 | }
24 | }
25 | )
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/KeyValueListDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.components.KeyValueList
5 | import com.kernel.finch.core.list.cells.ExpandedItemKeyValueCell
6 | import com.kernel.finch.core.list.delegates.shared.ExpandableComponentDelegate
7 |
8 | internal class KeyValueListDelegate : ExpandableComponentDelegate {
9 |
10 | override fun canExpand(component: KeyValueList) = component.pairs.isNotEmpty()
11 |
12 | override fun MutableList>.addItems(component: KeyValueList) {
13 | addAll(component.pairs.mapIndexed { index, item ->
14 | ExpandedItemKeyValueCell(
15 | id = "${component.id}_$index",
16 | key = item.first,
17 | value = item.second
18 | )
19 | })
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/kernel/finch/core/list/delegates/LabelDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.kernel.finch.core.list.delegates
2 |
3 | import com.kernel.finch.common.contracts.component.Cell
4 | import com.kernel.finch.common.contracts.component.Component
5 | import com.kernel.finch.components.Label
6 | import com.kernel.finch.core.util.createTextComponentFromType
7 |
8 | internal class LabelDelegate : Component.Delegate | | | | | | | | | | |