├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── dependabot.yml
└── workflows
│ ├── android.yml
│ └── codeql.yml
├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── deploymentTargetSelector.xml
├── migrations.xml
├── misc.xml
└── runConfigurations.xml
├── .tx
└── config
├── CONTRIBUTING.md
├── LICENSE
├── PRIVACY.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── it
│ │ │ └── niedermann
│ │ │ └── nextcloud
│ │ │ └── tables
│ │ │ ├── TablesApplication.java
│ │ │ ├── features
│ │ │ ├── about
│ │ │ │ ├── AboutActivity.java
│ │ │ │ ├── AboutFragmentContributingTab.java
│ │ │ │ ├── AboutFragmentCreditsTab.java
│ │ │ │ ├── AboutFragmentLicenseTab.java
│ │ │ │ └── AboutViewModel.java
│ │ │ ├── accountswitcher
│ │ │ │ ├── AccountSwitcherAdapter.java
│ │ │ │ ├── AccountSwitcherDialog.java
│ │ │ │ ├── AccountSwitcherViewHolder.java
│ │ │ │ └── AccountViewModel.java
│ │ │ ├── column
│ │ │ │ ├── edit
│ │ │ │ │ ├── EDataTypePicker.java
│ │ │ │ │ ├── EditColumnActivity.java
│ │ │ │ │ ├── EditColumnViewModel.java
│ │ │ │ │ ├── SearchProviderSupplier.java
│ │ │ │ │ └── types
│ │ │ │ │ │ ├── ColumnEditView.java
│ │ │ │ │ │ ├── ColumnEditViewFactory.java
│ │ │ │ │ │ ├── datetime
│ │ │ │ │ │ ├── DateManager.java
│ │ │ │ │ │ └── DateTimeManager.java
│ │ │ │ │ │ ├── number
│ │ │ │ │ │ ├── NumberManager.java
│ │ │ │ │ │ ├── ProgressManager.java
│ │ │ │ │ │ └── StarsManager.java
│ │ │ │ │ │ ├── selection
│ │ │ │ │ │ ├── SelectionCheckManager.java
│ │ │ │ │ │ ├── SelectionMultiManager.java
│ │ │ │ │ │ └── SelectionSingleManager.java
│ │ │ │ │ │ ├── text
│ │ │ │ │ │ ├── TextLineManager.java
│ │ │ │ │ │ ├── TextLinkManager.java
│ │ │ │ │ │ └── TextRichManager.java
│ │ │ │ │ │ ├── unknown
│ │ │ │ │ │ └── UnknownManager.java
│ │ │ │ │ │ └── usergroup
│ │ │ │ │ │ └── UserGroupManager.java
│ │ │ │ └── manage
│ │ │ │ │ ├── ManageColumnsActivity.java
│ │ │ │ │ ├── ManageColumnsAdapter.java
│ │ │ │ │ ├── ManageColumnsTouchHelper.java
│ │ │ │ │ ├── ManageColumnsViewHolder.java
│ │ │ │ │ └── ManageColumnsViewModel.java
│ │ │ ├── exception
│ │ │ │ ├── ExceptionActivity.java
│ │ │ │ ├── ExceptionDialogFragment.java
│ │ │ │ ├── ExceptionHandler.java
│ │ │ │ └── tips
│ │ │ │ │ ├── TipsAdapter.java
│ │ │ │ │ ├── TipsModel.java
│ │ │ │ │ └── TipsViewHolder.java
│ │ │ ├── importaccount
│ │ │ │ ├── ImportAccountActivity.java
│ │ │ │ └── ImportAccountViewModel.java
│ │ │ ├── main
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainViewModel.java
│ │ │ │ └── TableContextPopupMenu.java
│ │ │ ├── manageaccounts
│ │ │ │ ├── ManageAccountAdapter.java
│ │ │ │ ├── ManageAccountViewHolder.java
│ │ │ │ ├── ManageAccountsActivity.java
│ │ │ │ └── ManageAccountsViewModel.java
│ │ │ ├── row
│ │ │ │ ├── EditRowActivity.java
│ │ │ │ ├── EditRowViewModel.java
│ │ │ │ └── editor
│ │ │ │ │ ├── OnTextChangedListener.java
│ │ │ │ │ ├── ProposalProvider.java
│ │ │ │ │ └── type
│ │ │ │ │ ├── AutocompleteEditView.java
│ │ │ │ │ ├── AutocompleteEditViewWithDefaultDropdown.java
│ │ │ │ │ ├── DataEditView.java
│ │ │ │ │ ├── DataEditViewFactory.java
│ │ │ │ │ ├── datetime
│ │ │ │ │ ├── DateTimeDateEditor.java
│ │ │ │ │ ├── DateTimeEditor.java
│ │ │ │ │ └── DateTimeTimeEditor.java
│ │ │ │ │ ├── number
│ │ │ │ │ ├── NumberEditor.java
│ │ │ │ │ ├── NumberProgressEditor.java
│ │ │ │ │ └── NumberStarsEditor.java
│ │ │ │ │ ├── selection
│ │ │ │ │ ├── SelectionCheckEditor.java
│ │ │ │ │ ├── SelectionEditor.java
│ │ │ │ │ └── SelectionMultiEditor.java
│ │ │ │ │ ├── text
│ │ │ │ │ ├── TextEditor.java
│ │ │ │ │ ├── TextLineEditor.java
│ │ │ │ │ ├── TextLinkEditor.java
│ │ │ │ │ └── TextRichEditor.java
│ │ │ │ │ ├── unknown
│ │ │ │ │ └── UnknownEditor.java
│ │ │ │ │ └── usergroup
│ │ │ │ │ └── UserGroupEditor.java
│ │ │ ├── settings
│ │ │ │ ├── PreferencesActivity.java
│ │ │ │ └── PreferencesFragment.java
│ │ │ └── table
│ │ │ │ ├── edit
│ │ │ │ ├── EditTableActivity.java
│ │ │ │ └── EditTableViewModel.java
│ │ │ │ └── view
│ │ │ │ ├── DefaultTableViewListener.java
│ │ │ │ ├── TableViewAdapter.java
│ │ │ │ ├── ViewTableFragment.java
│ │ │ │ ├── ViewTableViewModel.java
│ │ │ │ └── viewholder
│ │ │ │ ├── CellViewHolder.java
│ │ │ │ ├── CellViewHolderFactory.java
│ │ │ │ ├── ColumnHeaderViewHolder.java
│ │ │ │ ├── RowHeaderViewHolder.java
│ │ │ │ ├── ViewHolderFactory.java
│ │ │ │ └── types
│ │ │ │ ├── datetime
│ │ │ │ ├── AbstractDateTimeCellViewHolder.java
│ │ │ │ ├── DateCellViewHolder.java
│ │ │ │ ├── DateTimeCellViewHolder.java
│ │ │ │ └── TimeCellViewHolder.java
│ │ │ │ ├── number
│ │ │ │ ├── NumberCellViewHolder.java
│ │ │ │ ├── ProgressCellViewHolder.java
│ │ │ │ └── StarsCellViewHolder.java
│ │ │ │ ├── selection
│ │ │ │ ├── SelectionCheckCellViewHolder.java
│ │ │ │ ├── SelectionMultiViewHolder.java
│ │ │ │ └── SelectionViewHolder.java
│ │ │ │ ├── text
│ │ │ │ ├── LinkCellViewHolder.java
│ │ │ │ ├── LongCellViewHolder.java
│ │ │ │ ├── RichViewHolder.java
│ │ │ │ └── TextCellViewHolder.java
│ │ │ │ └── usergroup
│ │ │ │ └── UserGroupViewHolder.java
│ │ │ └── util
│ │ │ ├── AvatarUtil.java
│ │ │ ├── CustomAppGlideModule.java
│ │ │ ├── DimensionUtil.java
│ │ │ ├── EmojiDrawable.java
│ │ │ ├── SpannableUtil.java
│ │ │ ├── TextLinkUtil.java
│ │ │ └── UserGroupUtil.java
│ └── res
│ │ ├── drawable
│ │ ├── app_icon.xml
│ │ ├── baseline_access_time_24.xml
│ │ ├── baseline_calendar_today_24.xml
│ │ ├── baseline_edit_24.xml
│ │ ├── baseline_link_24.xml
│ │ ├── baseline_numbers_24.xml
│ │ ├── baseline_playlist_add_24.xml
│ │ ├── baseline_post_add_24.xml
│ │ ├── baseline_question_mark_24.xml
│ │ ├── baseline_short_text_24.xml
│ │ ├── baseline_warning_amber_24.xml
│ │ ├── circle_alpha_check_36dp.xml
│ │ ├── ic_baseline_account_circle_24.xml
│ │ ├── ic_baseline_add_24.xml
│ │ ├── ic_baseline_arrow_back_24.xml
│ │ ├── ic_baseline_brightness_2_24.xml
│ │ ├── ic_baseline_check_24.xml
│ │ ├── ic_baseline_delete_24.xml
│ │ ├── ic_baseline_network_wifi_24.xml
│ │ ├── ic_baseline_person_24.xml
│ │ ├── ic_baseline_person_add_24.xml
│ │ ├── ic_baseline_settings_24.xml
│ │ ├── ic_baseline_sync_24.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_menu.xml
│ │ ├── ic_outline_info_24.xml
│ │ ├── ic_outline_lightbulb_24.xml
│ │ ├── selected_check.xml
│ │ └── shape_circular.xml
│ │ ├── layout
│ │ ├── activity_about.xml
│ │ ├── activity_edit_column.xml
│ │ ├── activity_edit_row.xml
│ │ ├── activity_edit_table.xml
│ │ ├── activity_exception.xml
│ │ ├── activity_import.xml
│ │ ├── activity_main.xml
│ │ ├── activity_manage_accounts.xml
│ │ ├── activity_manage_columns.xml
│ │ ├── activity_preferences.xml
│ │ ├── dialog_account_switcher.xml
│ │ ├── dialog_exception.xml
│ │ ├── edit_autocomplete.xml
│ │ ├── edit_datetime.xml
│ │ ├── edit_number_progress.xml
│ │ ├── edit_number_stars.xml
│ │ ├── edit_rich.xml
│ │ ├── edit_selection.xml
│ │ ├── edit_selection_check.xml
│ │ ├── edit_selection_multi.xml
│ │ ├── edit_textview.xml
│ │ ├── fragment_about_contribution_tab.xml
│ │ ├── fragment_about_credits_tab.xml
│ │ ├── fragment_about_license_tab.xml
│ │ ├── fragment_table.xml
│ │ ├── item_account_and_version.xml
│ │ ├── item_account_choose.xml
│ │ ├── item_autocomplete.xml
│ │ ├── item_column.xml
│ │ ├── item_manage_option_multi.xml
│ │ ├── item_manage_option_single.xml
│ │ ├── item_option.xml
│ │ ├── item_row.xml
│ │ ├── item_tip.xml
│ │ ├── manage_date.xml
│ │ ├── manage_datetime.xml
│ │ ├── manage_number.xml
│ │ ├── manage_number_progress.xml
│ │ ├── manage_number_stars.xml
│ │ ├── manage_selection_check.xml
│ │ ├── manage_selection_multi.xml
│ │ ├── manage_selection_single.xml
│ │ ├── manage_text_line.xml
│ │ ├── manage_text_link.xml
│ │ ├── manage_text_rich.xml
│ │ ├── manage_unknown.xml
│ │ ├── manage_usergroup.xml
│ │ ├── nav_header_main.xml
│ │ ├── tableview_cell.xml
│ │ ├── tableview_cell_check.xml
│ │ ├── tableview_cell_progress.xml
│ │ ├── tableview_cell_rich.xml
│ │ ├── tableview_cell_stars.xml
│ │ ├── tableview_column_header.xml
│ │ ├── tableview_corner.xml
│ │ └── tableview_row_header.xml
│ │ ├── menu
│ │ ├── context_menu_cell.xml
│ │ ├── context_menu_column.xml
│ │ ├── context_menu_table.xml
│ │ ├── menu_edit_column.xml
│ │ ├── menu_edit_row.xml
│ │ ├── menu_edit_table.xml
│ │ ├── menu_main_navigation.xml
│ │ └── menu_main_toolbar.xml
│ │ ├── mipmap
│ │ └── ic_launcher.xml
│ │ ├── values-ar
│ │ └── strings.xml
│ │ ├── values-ast
│ │ └── strings.xml
│ │ ├── values-b+en+001
│ │ └── strings.xml
│ │ ├── values-bg-rBG
│ │ └── strings.xml
│ │ ├── values-ca
│ │ └── strings.xml
│ │ ├── values-cs-rCZ
│ │ └── strings.xml
│ │ ├── values-da
│ │ └── strings.xml
│ │ ├── values-de
│ │ └── strings.xml
│ │ ├── values-el
│ │ └── strings.xml
│ │ ├── values-es-rEC
│ │ └── strings.xml
│ │ ├── values-es-rMX
│ │ └── strings.xml
│ │ ├── values-es
│ │ └── strings.xml
│ │ ├── values-et-rEE
│ │ └── strings.xml
│ │ ├── values-eu
│ │ └── strings.xml
│ │ ├── values-fa
│ │ └── strings.xml
│ │ ├── values-fi-rFI
│ │ └── strings.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-ga
│ │ └── strings.xml
│ │ ├── values-gl
│ │ └── strings.xml
│ │ ├── values-hr
│ │ └── strings.xml
│ │ ├── values-hu-rHU
│ │ └── strings.xml
│ │ ├── values-id
│ │ └── strings.xml
│ │ ├── values-is
│ │ └── strings.xml
│ │ ├── values-it
│ │ └── strings.xml
│ │ ├── values-ja-rJP
│ │ └── strings.xml
│ │ ├── values-ko
│ │ └── strings.xml
│ │ ├── values-lt-rLT
│ │ └── strings.xml
│ │ ├── values-nb-rNO
│ │ └── strings.xml
│ │ ├── values-night
│ │ ├── booleans.xml
│ │ └── colors.xml
│ │ ├── values-nl
│ │ └── strings.xml
│ │ ├── values-pl
│ │ └── strings.xml
│ │ ├── values-pt-rBR
│ │ └── strings.xml
│ │ ├── values-ro
│ │ └── strings.xml
│ │ ├── values-ru
│ │ └── strings.xml
│ │ ├── values-sc
│ │ └── strings.xml
│ │ ├── values-sk-rSK
│ │ └── strings.xml
│ │ ├── values-sl
│ │ └── strings.xml
│ │ ├── values-sr
│ │ └── strings.xml
│ │ ├── values-sv
│ │ └── strings.xml
│ │ ├── values-tr
│ │ └── strings.xml
│ │ ├── values-ug
│ │ └── strings.xml
│ │ ├── values-uk
│ │ └── strings.xml
│ │ ├── values-uz
│ │ └── strings.xml
│ │ ├── values-v27
│ │ └── themes.xml
│ │ ├── values-vi
│ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ ├── values-zh-rHK
│ │ └── strings.xml
│ │ ├── values-zh-rTW
│ │ └── strings.xml
│ │ ├── values
│ │ ├── booleans.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ └── preferences.xml
│ └── test
│ └── resources
│ └── robolectric.properties
├── build.gradle
├── database
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
├── schemas
│ └── it.niedermann.nextcloud.tables.database.TablesDatabase
│ │ ├── 1.json
│ │ ├── 2.json
│ │ ├── 3.json
│ │ ├── 4.json
│ │ ├── 5.json
│ │ └── 6.json
└── src
│ ├── androidTest
│ └── java
│ │ └── it
│ │ └── niedermann
│ │ └── nextcloud
│ │ └── tables
│ │ └── database
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── it
│ │ │ └── niedermann
│ │ │ └── nextcloud
│ │ │ └── tables
│ │ │ └── database
│ │ │ ├── DBStatus.java
│ │ │ ├── TablesDatabase.java
│ │ │ ├── converter
│ │ │ ├── DBStatusConverter.java
│ │ │ ├── EDataTypeConverter.java
│ │ │ ├── InstantConverter.java
│ │ │ ├── JsonElementConverter.java
│ │ │ ├── LocalDateConverter.java
│ │ │ ├── LocalTimeConverter.java
│ │ │ ├── UriConverter.java
│ │ │ ├── UserGroupTypeConverter.java
│ │ │ └── VersionConverter.java
│ │ │ ├── dao
│ │ │ ├── AccountDao.java
│ │ │ ├── ColumnDao.java
│ │ │ ├── DataDao.java
│ │ │ ├── DataSelectionOptionCrossRefDao.java
│ │ │ ├── DataUserGroupCrossRefDao.java
│ │ │ ├── DefaultValueSelectionOptionCrossRefDao.java
│ │ │ ├── GenericDao.java
│ │ │ ├── LinkValueDao.java
│ │ │ ├── RowDao.java
│ │ │ ├── SearchProviderDao.java
│ │ │ ├── SelectionOptionDao.java
│ │ │ ├── TableDao.java
│ │ │ └── UserGroupDao.java
│ │ │ ├── entity
│ │ │ ├── AbstractAccountRelatedEntity.java
│ │ │ ├── AbstractEntity.java
│ │ │ ├── AbstractRemoteEntity.java
│ │ │ ├── AbstractTableRelatedEntity.java
│ │ │ ├── Account.java
│ │ │ ├── Column.java
│ │ │ ├── Data.java
│ │ │ ├── DataSelectionOptionCrossRef.java
│ │ │ ├── DataUserGroupCrossRef.java
│ │ │ ├── DefaultValueSelectionOptionCrossRef.java
│ │ │ ├── DefaultValueUserGroupCrossRef.java
│ │ │ ├── LinkValue.java
│ │ │ ├── OnSharePermission.java
│ │ │ ├── Row.java
│ │ │ ├── SearchProvider.java
│ │ │ ├── SelectionOption.java
│ │ │ ├── SynchronizationContext.java
│ │ │ ├── Table.java
│ │ │ ├── TextAllowedPattern.java
│ │ │ ├── UserGroup.java
│ │ │ └── attributes
│ │ │ │ ├── DateTimeAttributes.java
│ │ │ │ ├── NumberAttributes.java
│ │ │ │ ├── SelectionAttributes.java
│ │ │ │ ├── TextAttributes.java
│ │ │ │ └── UserGroupAttributes.java
│ │ │ ├── migration
│ │ │ ├── Migration_1_2.java
│ │ │ ├── Migration_2_3.java
│ │ │ ├── Migration_3_4.java
│ │ │ ├── Migration_4_5.java
│ │ │ └── Migration_5_6.java
│ │ │ └── model
│ │ │ ├── DataTypeServiceRegistry.java
│ │ │ ├── EDataType.java
│ │ │ ├── EUserGroupType.java
│ │ │ ├── FullColumn.java
│ │ │ ├── FullData.java
│ │ │ ├── FullRow.java
│ │ │ ├── FullTable.java
│ │ │ ├── LinkValueWithProviderId.java
│ │ │ ├── NextcloudVersion.java
│ │ │ ├── TablesVersion.java
│ │ │ ├── Value.java
│ │ │ └── Version.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── it
│ └── niedermann
│ └── nextcloud
│ └── tables
│ └── database
│ └── ExampleUnitTest.java
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ ├── 1000000.txt
│ ├── 1000001.txt
│ ├── 1000002.txt
│ ├── 1000003.txt
│ ├── 1000004.txt
│ ├── 1000005.txt
│ ├── 1000006.txt
│ ├── 1000007.txt
│ ├── 1000008.txt
│ ├── 1001000.txt
│ ├── 1001001.txt
│ ├── 1001002.txt
│ ├── 1001003.txt
│ ├── 2000000.txt
│ ├── 2000001.txt
│ ├── 2000002.txt
│ ├── 2000003.txt
│ ├── 2000004.txt
│ ├── 2000005.txt
│ ├── 2000006.txt
│ ├── 2000007.txt
│ ├── 2000008.txt
│ ├── 2001000.txt
│ ├── 2001001.txt
│ ├── 2002000.txt
│ ├── 2002001.txt
│ ├── 2002002.txt
│ ├── 2002003.txt
│ ├── 2002004.txt
│ └── 2002005.txt
│ ├── full_description.txt
│ ├── images
│ ├── featureGraphic.jpg
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ └── 8.png
│ ├── short_description.txt
│ └── title.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── remote
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── it
│ │ └── niedermann
│ │ └── nextcloud
│ │ └── tables
│ │ └── remote
│ │ ├── ApiProvider.java
│ │ ├── RequestHelper.java
│ │ ├── ocs
│ │ ├── OcsAPI.java
│ │ ├── OcsApiProvider.java
│ │ ├── adapter
│ │ │ └── OcsAutocompleteSourceListAdapter.java
│ │ └── model
│ │ │ ├── CapabilitiesResponse.java
│ │ │ ├── OcsAutocompleteResult.java
│ │ │ ├── OcsSearchProvider.java
│ │ │ ├── OcsSearchResult.java
│ │ │ └── OcsSearchResultEntry.java
│ │ ├── shared
│ │ ├── model
│ │ │ ├── DataResponseDto.java
│ │ │ └── RemoteDto.java
│ │ └── util
│ │ │ └── JsonArrayCollector.java
│ │ ├── tablesV1
│ │ ├── TablesV1API.java
│ │ ├── TablesV1ApiProvider.java
│ │ ├── adapter
│ │ │ ├── BooleanV1Adapter.java
│ │ │ ├── EUserGroupTypeV1Adapter.java
│ │ │ ├── InstantV1Adapter.java
│ │ │ └── UserGroupV1ListAdapter.java
│ │ └── model
│ │ │ ├── ColumnRequestV1Dto.java
│ │ │ ├── EUserGroupTypeV1Dto.java
│ │ │ ├── FetchRowResponseV1Dto.java
│ │ │ ├── UpdateColumnResponseV1Dto.java
│ │ │ ├── UpdateRowRequestV1Dto.java
│ │ │ └── UpdateRowResponseV1Dto.java
│ │ └── tablesV2
│ │ ├── TablesV2API.java
│ │ ├── TablesV2ApiProvider.java
│ │ ├── adapter
│ │ ├── ENodeTypeV2Adapter.java
│ │ ├── EUserGroupV2Adapter.java
│ │ └── InstantV2Adapter.java
│ │ ├── creators
│ │ ├── ColumnCreator.java
│ │ ├── DataTypeCreatorServiceRegistry.java
│ │ ├── NoOpCreator.java
│ │ └── type
│ │ │ ├── DateTimeCreator.java
│ │ │ ├── NumberCreator.java
│ │ │ ├── SelectionCheckCreator.java
│ │ │ ├── SelectionCreator.java
│ │ │ ├── TextCreator.java
│ │ │ └── UserGroupCreator.java
│ │ └── model
│ │ ├── ColumnV2Dto.java
│ │ ├── CreateColumnResponseV2Dto.java
│ │ ├── CreateRowResponseV2Dto.java
│ │ ├── CreateRowV2Dto.java
│ │ ├── ENodeCollectionV2Dto.java
│ │ ├── ENodeTypeV2Dto.java
│ │ ├── EPermissionV2Dto.java
│ │ ├── EUserGroupTypeV2Dto.java
│ │ ├── OnSharePermissionV2Dto.java
│ │ ├── SelectionOptionV2Dto.java
│ │ ├── TableV2Dto.java
│ │ ├── UserGroupV2Dto.java
│ │ └── columns
│ │ ├── CreateColumnV2Dto.java
│ │ ├── CreateDateTimeColumnV2Dto.java
│ │ ├── CreateNumberColumnV2Dto.java
│ │ ├── CreateSelectionCheckColumnV2Dto.java
│ │ ├── CreateSelectionColumnV2Dto.java
│ │ ├── CreateTextColumnV2Dto.java
│ │ └── CreateUserGroupColumnV2Dto.java
│ └── res
│ └── values
│ └── strings.xml
├── repository
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── it
│ │ │ └── niedermann
│ │ │ └── nextcloud
│ │ │ └── tables
│ │ │ └── repository
│ │ │ ├── AbstractRepository.java
│ │ │ ├── AccountRepository.java
│ │ │ ├── PreferencesRepository.java
│ │ │ ├── SearchRepository.java
│ │ │ ├── ServerErrorHandler.java
│ │ │ ├── SyncWorker.java
│ │ │ ├── TablesRepository.java
│ │ │ ├── defaults
│ │ │ ├── DataTypeDefaultServiceRegistry.java
│ │ │ ├── DefaultValueSupplier.java
│ │ │ └── supplier
│ │ │ │ ├── NoOpDefaultSupplier.java
│ │ │ │ ├── datetime
│ │ │ │ ├── DateDefaultSupplier.java
│ │ │ │ ├── DateTimeDefaultSupplier.java
│ │ │ │ └── TimeDefaultSupplier.java
│ │ │ │ ├── number
│ │ │ │ ├── NumberDefaultSupplier.java
│ │ │ │ └── NumberStarsDefaultSupplier.java
│ │ │ │ ├── selection
│ │ │ │ ├── SelectionCheckDefaultSupplier.java
│ │ │ │ ├── SelectionDefaultSupplier.java
│ │ │ │ └── SelectionMultiDefaultSupplier.java
│ │ │ │ ├── text
│ │ │ │ └── TextDefaultSupplier.java
│ │ │ │ └── usergroup
│ │ │ │ └── UserGroupDefaultSupplier.java
│ │ │ ├── exception
│ │ │ ├── AccountAlreadyImportedException.java
│ │ │ ├── AccountNotCreatedException.java
│ │ │ ├── InsufficientPermissionException.java
│ │ │ └── ServerNotAvailableException.java
│ │ │ ├── sync
│ │ │ ├── SyncScheduler.java
│ │ │ ├── exception
│ │ │ │ └── SyncExceptionWithContext.java
│ │ │ ├── mapper
│ │ │ │ ├── RemoteMapper.java
│ │ │ │ ├── ocs
│ │ │ │ │ ├── OcsSearchProviderMapper.java
│ │ │ │ │ └── OcsVersionMapper.java
│ │ │ │ ├── shared
│ │ │ │ │ └── type
│ │ │ │ │ │ ├── DataV1Mapper.java
│ │ │ │ │ │ ├── datetime
│ │ │ │ │ │ ├── DateRemoteMapper.java
│ │ │ │ │ │ ├── DateTimeRemoteMapper.java
│ │ │ │ │ │ └── TimeRemoteMapper.java
│ │ │ │ │ │ ├── number
│ │ │ │ │ │ ├── NumberProgressRemoteMapper.java
│ │ │ │ │ │ ├── NumberRemoteMapper.java
│ │ │ │ │ │ └── NumberStarsRemoteMapper.java
│ │ │ │ │ │ ├── selection
│ │ │ │ │ │ ├── SelectionCheckDataV1Mapper.java
│ │ │ │ │ │ ├── SelectionMultiDataV1Mapper.java
│ │ │ │ │ │ └── SelectionSingleDataV1Mapper.java
│ │ │ │ │ │ ├── text
│ │ │ │ │ │ ├── TextLinkRemoteMapper.java
│ │ │ │ │ │ └── TextRemoteMapper.java
│ │ │ │ │ │ ├── unknown
│ │ │ │ │ │ └── UnknownRemoteMapper.java
│ │ │ │ │ │ └── usergroup
│ │ │ │ │ │ └── UserGroupDataV1Mapper.java
│ │ │ │ ├── tablesV1
│ │ │ │ │ ├── ColumnRequestV1Mapper.java
│ │ │ │ │ ├── FetchAndPutRowV1Mapper.java
│ │ │ │ │ └── TypeRemoteV1MapperServiceRegistry.java
│ │ │ │ └── tablesV2
│ │ │ │ │ ├── ColumnV2Mapper.java
│ │ │ │ │ ├── CreateRowResponseV2Mapper.java
│ │ │ │ │ ├── EUserGroupTypeV2Mapper.java
│ │ │ │ │ ├── OnSharePermissionV2Mapper.java
│ │ │ │ │ ├── SelectionDefaultV2Mapper.java
│ │ │ │ │ ├── SelectionOptionV2Mapper.java
│ │ │ │ │ ├── TableV2Mapper.java
│ │ │ │ │ └── UserGroupV2Mapper.java
│ │ │ ├── report
│ │ │ │ ├── LiveDataReporter.java
│ │ │ │ ├── SyncStatus.java
│ │ │ │ └── SyncStatusReporter.java
│ │ │ └── treesync
│ │ │ │ ├── AbstractPullOnlySyncAdapter.java
│ │ │ │ ├── AbstractSyncAdapter.java
│ │ │ │ ├── AccountSyncAdapter.java
│ │ │ │ ├── CapabilitiesSyncAdapter.java
│ │ │ │ ├── ColumnSyncAdapter.java
│ │ │ │ ├── RowSyncAdapter.java
│ │ │ │ ├── SearchProviderSyncAdapter.java
│ │ │ │ ├── SyncAdapter.java
│ │ │ │ ├── TableSyncAdapter.java
│ │ │ │ ├── TreeSyncExceptionWithContext.java
│ │ │ │ ├── TreeSyncScheduler.java
│ │ │ │ └── UserSyncAdapter.java
│ │ │ └── util
│ │ │ └── ColumnReorderUtil.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── it
│ └── niedermann
│ └── nextcloud
│ └── tables
│ └── repository
│ └── sync
│ ├── ColumnReorderUtilTest.java
│ └── mapper
│ ├── ocs
│ ├── OcsSearchProviderMapperTest.java
│ └── OcsVersionMapperTest.java
│ └── tablesV2
│ ├── EUserGroupTypeV2MapperTest.java
│ ├── OnSharePermissionV2MapperTest.java
│ ├── SelectionOptionV2MapperTest.java
│ ├── TableV2MapperTest.java
│ └── UserGroupV2MapperTest.java
├── settings.gradle
├── shared
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── it
│ └── niedermann
│ └── nextcloud
│ └── tables
│ └── shared
│ ├── Constants.java
│ ├── FeatureToggle.java
│ └── SharedExecutors.java
└── ui
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
├── androidTest
└── java
│ └── it
│ └── niedermann
│ └── nextcloud
│ └── tables
│ └── ui
│ └── ExampleInstrumentedTest.java
├── main
├── AndroidManifest.xml
├── java
│ └── it
│ │ └── niedermann
│ │ └── nextcloud
│ │ └── tables
│ │ └── ui
│ │ ├── LifecycleAwareFrameLayout.java
│ │ ├── emojipicker
│ │ └── EmojiPickerBottomSheet.java
│ │ ├── stars
│ │ └── Stars.java
│ │ └── twolevelselect
│ │ └── TwoLevelSelect.java
└── res
│ ├── drawable
│ ├── baseline_clear_24.xml
│ ├── baseline_restart_alt_24.xml
│ ├── baseline_star_24.xml
│ ├── baseline_star_border_24.xml
│ └── selectable_star.xml
│ ├── layout
│ ├── view_emojipicker.xml
│ ├── view_stars.xml
│ ├── view_stars_single.xml
│ └── view_two_level_select.xml
│ └── values
│ ├── attrs.xml
│ ├── dimens.xml
│ └── strings.xml
└── test
└── java
└── it
└── niedermann
└── nextcloud
└── tables
└── ui
└── ExampleUnitTest.java
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | liberapay: stefan-niedermann
4 | custom: https://www.paypal.com/donate/?hosted_button_id=8ERCNEZ6CQ666
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 💼 Volume licenses
4 | url: https://www.niedermann.it
5 | about: If you are a company, a club, a university or another organization, please contact us directly for volume licenses.
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gradle
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 | - package-ecosystem: github-actions
9 | directory: "/"
10 | schedule:
11 | interval: daily
12 | open-pull-requests-limit: 10
13 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: CodeQL security scan
2 |
3 | on:
4 | pull_request:
5 | schedule:
6 | - cron: '0 12 * * *'
7 |
8 | permissions:
9 | contents: read
10 | security-events: write
11 | pull-requests: read
12 |
13 | jobs:
14 | codeql:
15 | name: CodeQL security scan
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v4
20 | - uses: actions/setup-java@v4
21 | with:
22 | distribution: 'temurin'
23 | java-version: '17'
24 | check-latest: true
25 | cache: 'gradle'
26 | - name: Initialize CodeQL
27 | uses: github/codeql-action/init@v3
28 | with:
29 | languages: java
30 | - name: Build debug APK
31 | run: bash ./gradlew assembleDev --stacktrace
32 | - name: Perform CodeQL Analysis
33 | uses: github/codeql-action/analyze@v3
34 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Nextcloud Tables
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /play
3 | /fdroid
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.google.gson.** { *; }
2 |
3 | # Add project specific ProGuard rules here.
4 | # You can control the set of applied configuration files using the
5 | # proguardFiles setting in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # If your project uses WebView with JS, uncomment the following
11 | # and specify the fully qualified class name to the JavaScript interface
12 | # class:
13 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
14 | # public *;
15 | #}
16 |
17 | # Uncomment this to preserve the line number information for
18 | # debugging stack traces.
19 | #-keepattributes SourceFile,LineNumberTable
20 |
21 | # If you keep the line number information, uncomment this to
22 | # hide the original source file name.
23 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/accountswitcher/AccountViewModel.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.accountswitcher;
2 |
3 | import android.app.Application;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.lifecycle.AndroidViewModel;
7 | import androidx.lifecycle.LiveData;
8 | import androidx.lifecycle.Transformations;
9 |
10 | import java.util.List;
11 |
12 | import it.niedermann.nextcloud.tables.database.entity.Account;
13 | import it.niedermann.nextcloud.tables.repository.AccountRepository;
14 |
15 | public class AccountViewModel extends AndroidViewModel {
16 |
17 | private final AccountRepository accountRepository;
18 |
19 | public AccountViewModel(@NonNull Application application) {
20 | super(application);
21 | this.accountRepository = new AccountRepository(application);
22 | }
23 |
24 | public void setCurrentAccount(@NonNull Account account) {
25 | accountRepository.setCurrentAccount(account);
26 | }
27 |
28 | public LiveData getCurrentAccount() {
29 | return accountRepository.getCurrentAccount();
30 | }
31 |
32 | public LiveData> getAccounts() {
33 | return Transformations.switchMap(getCurrentAccount(), account -> accountRepository.getAccountsExcept$(account.getId()));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/column/edit/SearchProviderSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.column.edit;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.lifecycle.LiveData;
5 |
6 | import java.util.List;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.SearchProvider;
9 |
10 | @FunctionalInterface
11 | public interface SearchProviderSupplier {
12 |
13 | @NonNull
14 | LiveData> getSearchProvider(long accountId);
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/column/edit/types/unknown/UnknownManager.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.column.edit.types.unknown;
2 |
3 |
4 | import android.content.Context;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.fragment.app.FragmentManager;
11 |
12 | import it.niedermann.nextcloud.tables.databinding.ManageUnknownBinding;
13 | import it.niedermann.nextcloud.tables.features.column.edit.types.ColumnEditView;
14 |
15 | public class UnknownManager extends ColumnEditView {
16 |
17 | public UnknownManager(@NonNull Context context) {
18 | super(context);
19 | }
20 |
21 | public UnknownManager(@NonNull Context context, @NonNull AttributeSet attrs) {
22 | super(context, attrs);
23 | }
24 |
25 | public UnknownManager(@NonNull Context context,
26 | @Nullable FragmentManager fragmentManager) {
27 | super(context, ManageUnknownBinding.inflate(LayoutInflater.from(context)), fragmentManager);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/column/manage/ManageColumnsViewHolder.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.column.manage;
2 |
3 | import static java.util.function.Predicate.not;
4 |
5 | import android.text.TextUtils;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.recyclerview.widget.RecyclerView;
9 |
10 | import java.util.Optional;
11 | import java.util.function.Consumer;
12 |
13 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
14 | import it.niedermann.nextcloud.tables.databinding.ItemColumnBinding;
15 |
16 | public class ManageColumnsViewHolder extends RecyclerView.ViewHolder {
17 |
18 | private final ItemColumnBinding binding;
19 |
20 | public ManageColumnsViewHolder(@NonNull ItemColumnBinding binding) {
21 | super(binding.getRoot());
22 | this.binding = binding;
23 | }
24 |
25 | public void bind(@NonNull FullColumn fullColumn, @NonNull Consumer onEdit) {
26 | final var column = fullColumn.getColumn();
27 | final var description = Optional.ofNullable(column.getDescription())
28 | .filter(not(TextUtils::isEmpty))
29 | .orElse(column.getDataType().toHumanReadableString(binding.getRoot().getContext()));
30 |
31 | binding.title.setText(column.getTitle());
32 | binding.description.setText(description);
33 | binding.edit.setOnClickListener(v -> onEdit.accept(fullColumn));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/exception/ExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.exception;
2 |
3 | import android.app.Activity;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import java.util.logging.Level;
8 | import java.util.logging.Logger;
9 |
10 | public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
11 |
12 | private final Logger logger = Logger.getLogger(ExceptionHandler.class.getSimpleName());
13 |
14 | @NonNull
15 | private final Activity activity;
16 |
17 | public ExceptionHandler(@NonNull Activity activity) {
18 | this.activity = activity;
19 | }
20 |
21 | @Override
22 | public void uncaughtException(@NonNull Thread t, @NonNull Throwable throwable) {
23 | try {
24 | logger.log(Level.SEVERE, throwable.toString(), throwable);
25 | } catch (NullPointerException ignored) {
26 | }
27 |
28 | activity.getApplicationContext().startActivity(ExceptionActivity.createIntent(activity, throwable));
29 | activity.finish();
30 |
31 | // This prevents the new activity from being created since at least API 35, therefore commenting it
32 | // Runtime.getRuntime().exit(0);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/exception/tips/TipsModel.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.exception.tips;
2 |
3 | import android.content.Intent;
4 |
5 | import androidx.annotation.Nullable;
6 | import androidx.annotation.StringRes;
7 |
8 | @SuppressWarnings("WeakerAccess")
9 | public class TipsModel {
10 | @StringRes
11 | private final int text;
12 | @Nullable
13 | private final Intent actionIntent;
14 |
15 | TipsModel(@StringRes int text, @Nullable Intent actionIntent) {
16 | this.text = text;
17 | this.actionIntent = actionIntent;
18 | }
19 |
20 | @StringRes
21 | public int getText() {
22 | return this.text;
23 | }
24 |
25 | @Nullable
26 | public Intent getActionIntent() {
27 | return this.actionIntent;
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/row/editor/OnTextChangedListener.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.row.editor;
2 |
3 | import android.text.Editable;
4 | import android.text.TextWatcher;
5 |
6 | public interface OnTextChangedListener extends TextWatcher {
7 |
8 | @Override
9 | default void afterTextChanged(Editable s) {
10 | }
11 |
12 | @Override
13 | default void beforeTextChanged(CharSequence s, int start, int count, int after) {
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/row/editor/ProposalProvider.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.row.editor;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.lifecycle.LiveData;
5 |
6 | import java.util.Collection;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.Account;
9 | import it.niedermann.nextcloud.tables.database.entity.Column;
10 |
11 | @FunctionalInterface
12 | public interface ProposalProvider {
13 |
14 | @NonNull
15 | LiveData> getProposals(@NonNull Account account,
16 | @NonNull Column column,
17 | @NonNull String term);
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/row/editor/type/text/TextLineEditor.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.row.editor.type.text;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import it.niedermann.nextcloud.tables.database.entity.Column;
10 |
11 | public class TextLineEditor extends TextEditor {
12 |
13 | public TextLineEditor(@NonNull Context context) {
14 | super(context);
15 | }
16 |
17 | public TextLineEditor(@NonNull Context context, @Nullable AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | public TextLineEditor(@NonNull Context context,
22 | @NonNull Column column) {
23 | super(context, column);
24 |
25 | binding.editText.setMaxLines(1);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/edit/EditTableViewModel.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.edit;
2 |
3 | import android.app.Application;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.lifecycle.AndroidViewModel;
7 |
8 | import java.util.concurrent.CompletableFuture;
9 |
10 | import it.niedermann.nextcloud.tables.database.entity.Account;
11 | import it.niedermann.nextcloud.tables.database.entity.Table;
12 | import it.niedermann.nextcloud.tables.repository.TablesRepository;
13 |
14 | public class EditTableViewModel extends AndroidViewModel {
15 |
16 | private final TablesRepository tablesRepository;
17 |
18 | public EditTableViewModel(@NonNull Application application) {
19 | super(application);
20 | tablesRepository = new TablesRepository(application);
21 | }
22 |
23 | public CompletableFuture createTable(@NonNull Account account,
24 | @NonNull Table table) {
25 | return tablesRepository.createTable(account, table);
26 | }
27 |
28 | public CompletableFuture updateTable(@NonNull Account account,
29 | @NonNull Table table) {
30 | return tablesRepository.updateTable(account, table);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/view/viewholder/RowHeaderViewHolder.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.view.viewholder;
2 |
3 | import android.view.View;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;
8 |
9 | import it.niedermann.nextcloud.tables.database.DBStatus;
10 | import it.niedermann.nextcloud.tables.database.entity.Row;
11 | import it.niedermann.nextcloud.tables.databinding.TableviewRowHeaderBinding;
12 |
13 | public class RowHeaderViewHolder extends AbstractViewHolder {
14 | public final TableviewRowHeaderBinding binding;
15 |
16 | public RowHeaderViewHolder(@NonNull TableviewRowHeaderBinding binding) {
17 | super(binding.getRoot());
18 | this.binding = binding;
19 | }
20 |
21 | public void bind(@NonNull Row row) {
22 | this.binding.sync.setVisibility(row.getStatus() == DBStatus.VOID ? View.INVISIBLE : View.VISIBLE);
23 | itemView.requestLayout();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/view/viewholder/ViewHolderFactory.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.view.viewholder;
2 |
3 | import android.view.ViewGroup;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
8 |
9 | public abstract class ViewHolderFactory {
10 |
11 | @NonNull
12 | protected final DefaultValueSupplier defaultValueSupplier;
13 |
14 | protected ViewHolderFactory(@NonNull DefaultValueSupplier defaultValueSupplier) {
15 | this.defaultValueSupplier = defaultValueSupplier;
16 | }
17 |
18 | public abstract CellViewHolder create(@NonNull ViewGroup parent);
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/view/viewholder/types/datetime/DateCellViewHolder.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.view.viewholder.types.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.format.DateTimeFormatter;
6 | import java.time.format.FormatStyle;
7 | import java.util.Optional;
8 |
9 | import it.niedermann.nextcloud.tables.database.entity.Data;
10 | import it.niedermann.nextcloud.tables.database.model.Value;
11 | import it.niedermann.nextcloud.tables.databinding.TableviewCellBinding;
12 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
13 |
14 | public class DateCellViewHolder extends AbstractDateTimeCellViewHolder {
15 |
16 | public DateCellViewHolder(@NonNull TableviewCellBinding binding,
17 | @NonNull DefaultValueSupplier defaultValueSupplier) {
18 | super(binding, defaultValueSupplier);
19 | }
20 |
21 | @Override
22 | protected String formatValue(@NonNull Data data) {
23 | return Optional.of(data.getValue())
24 | .map(Value::getDateValue)
25 | .map(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)::format)
26 | .orElse(null);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/view/viewholder/types/datetime/DateTimeCellViewHolder.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.view.viewholder.types.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.ZoneId;
6 | import java.time.format.DateTimeFormatter;
7 | import java.time.format.DateTimeParseException;
8 | import java.time.format.FormatStyle;
9 | import java.util.Optional;
10 |
11 | import it.niedermann.nextcloud.tables.database.entity.Data;
12 | import it.niedermann.nextcloud.tables.database.model.Value;
13 | import it.niedermann.nextcloud.tables.databinding.TableviewCellBinding;
14 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
15 |
16 | public class DateTimeCellViewHolder extends AbstractDateTimeCellViewHolder {
17 |
18 | public DateTimeCellViewHolder(@NonNull TableviewCellBinding binding,
19 | @NonNull DefaultValueSupplier defaultValueSupplier) {
20 | super(binding, defaultValueSupplier);
21 | }
22 |
23 | @Override
24 | protected String formatValue(@NonNull Data data) throws DateTimeParseException {
25 | return Optional.of(data.getValue())
26 | .map(Value::getInstantValue)
27 | .map(instant -> instant.atZone(ZoneId.systemDefault()))
28 | .map(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)::format)
29 | .orElse(null);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/features/table/view/viewholder/types/datetime/TimeCellViewHolder.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.features.table.view.viewholder.types.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.format.DateTimeFormatter;
6 | import java.time.format.FormatStyle;
7 | import java.util.Optional;
8 |
9 | import it.niedermann.nextcloud.tables.database.entity.Data;
10 | import it.niedermann.nextcloud.tables.database.model.Value;
11 | import it.niedermann.nextcloud.tables.databinding.TableviewCellBinding;
12 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
13 |
14 | public class TimeCellViewHolder extends AbstractDateTimeCellViewHolder {
15 |
16 | public TimeCellViewHolder(@NonNull TableviewCellBinding binding,
17 | @NonNull DefaultValueSupplier defaultValueSupplier) {
18 | super(binding, defaultValueSupplier);
19 | }
20 |
21 | @Override
22 | protected String formatValue(@NonNull Data data) {
23 | return Optional.of(data.getValue())
24 | .map(Value::getTimeValue)
25 | .map(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)::format)
26 | .orElse(null);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/util/AvatarUtil.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.util;
2 |
3 | import android.net.Uri;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.Px;
7 |
8 | import com.bumptech.glide.Glide;
9 | import com.bumptech.glide.load.model.GlideUrl;
10 |
11 | import it.niedermann.nextcloud.sso.glide.SingleSignOnUrl;
12 | import it.niedermann.nextcloud.tables.database.entity.Account;
13 |
14 | public class AvatarUtil {
15 |
16 | /**
17 | * @return The {@link #getAvatarUrl(Account, int, String)} of this {@link Account}
18 | */
19 | public GlideUrl getAvatarUrl(@NonNull Account account, @Px int size) {
20 | return getAvatarUrl(account, size, account.getUserName());
21 | }
22 |
23 | /**
24 | * @return a {@link GlideUrl} to fetch the avatar of the given userName
from the instance of this {@link Account} via {@link Glide}.
25 | */
26 | public GlideUrl getAvatarUrl(@NonNull Account account, @Px int size, @NonNull String userName) {
27 | return new SingleSignOnUrl(account.getAccountName(), account.getUrl() + "/index.php/avatar/" + Uri.encode(userName) + "/" + size);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/util/DimensionUtil.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.util;
2 |
3 | import static androidx.core.util.TypedValueCompat.spToPx;
4 |
5 | import android.content.Context;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Px;
9 |
10 | public class DimensionUtil {
11 |
12 | private DimensionUtil() {
13 | // Util class
14 | }
15 |
16 | /// [Source](https://chrisdavies.github.io/sp-to-em/)
17 | @Px
18 | public static int emToPx(@NonNull Context context, float em) {
19 | return (int) (spToPx(em / 0.0624f, context.getResources().getDisplayMetrics()));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/util/EmojiDrawable.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.util;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.ColorFilter;
6 | import android.graphics.Paint;
7 | import android.graphics.PixelFormat;
8 | import android.graphics.drawable.Drawable;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.emoji2.widget.EmojiTextView;
12 |
13 | public class EmojiDrawable extends Drawable {
14 | private final String emoji;
15 | private final Paint paint;
16 |
17 | public EmojiDrawable(@NonNull Context context, @NonNull String emoji) {
18 | this.emoji = emoji;
19 | this.paint = new Paint(new EmojiTextView(context).getPaint());
20 | }
21 |
22 |
23 | @Override
24 | public void draw(@NonNull Canvas canvas) {
25 | canvas.drawText(emoji, 8, (float) getBounds().height() / 1.4f, paint);
26 | }
27 |
28 | @Override
29 | public void setAlpha(int alpha) {
30 | paint.setAlpha(alpha);
31 | }
32 |
33 | @Override
34 | public void setColorFilter(ColorFilter colorFilter) {
35 | paint.setColorFilter(colorFilter);
36 | }
37 |
38 | @Override
39 | public int getOpacity() {
40 | return switch (paint.getAlpha()) {
41 | case 0 -> PixelFormat.TRANSPARENT;
42 | case 255 -> PixelFormat.OPAQUE;
43 | default -> PixelFormat.TRANSLUCENT;
44 | };
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/util/TextLinkUtil.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.util;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import java.util.Optional;
10 |
11 | import it.niedermann.nextcloud.tables.R;
12 | import it.niedermann.nextcloud.tables.database.entity.LinkValue;
13 |
14 | public class TextLinkUtil {
15 |
16 | /// @noinspection DataFlowIssue
17 | @Nullable
18 | public static String getLinkAsDisplayValue(@NonNull Context context, @NonNull LinkValue linkValue) {
19 | final var value = Optional.of(linkValue)
20 | .map(LinkValue::getValue)
21 | .map(Uri::toString)
22 | .orElse(null);
23 |
24 | final var title = Optional.of(linkValue)
25 | .map(LinkValue::getTitle);
26 |
27 | return title
28 | .map(s -> context.getString(R.string.format_text_link, s, value))
29 | .orElse(value);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/it/niedermann/nextcloud/tables/util/UserGroupUtil.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.util;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import java.util.Optional;
10 |
11 | import it.niedermann.nextcloud.tables.R;
12 | import it.niedermann.nextcloud.tables.database.entity.LinkValue;
13 |
14 | public class UserGroupUtil {
15 |
16 | /// @noinspection DataFlowIssue
17 | @Nullable
18 | public static String getLinkAsDisplayValue(@NonNull Context context, @NonNull LinkValue linkValue) {
19 | final var value = Optional.of(linkValue)
20 | .map(LinkValue::getValue)
21 | .map(Uri::toString)
22 | .orElse(null);
23 |
24 | final var title = Optional.of(linkValue)
25 | .map(LinkValue::getTitle);
26 |
27 | return title
28 | .map(s -> context.getString(R.string.format_text_link, s, value))
29 | .orElse(value);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_access_time_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_calendar_today_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_edit_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_link_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_numbers_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_playlist_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_post_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_question_mark_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_short_text_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_warning_amber_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_alpha_check_36dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
6 |
7 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_account_circle_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_brightness_2_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_check_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_delete_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_network_wifi_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_person_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_person_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_settings_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_sync_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_info_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_lightbulb_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selected_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
-
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_circular.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
17 |
18 |
19 |
24 |
25 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_datetime.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_number_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_number_stars.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_rich.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_selection_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_selection_multi.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_textview.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_table.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_account_and_version.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_option.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_date.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_datetime.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_number_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_number_stars.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_selection_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_selection_multi.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_text_link.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
20 |
21 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_text_rich.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
16 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_unknown.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_cell.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_cell_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_cell_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_cell_rich.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_cell_stars.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_column_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tableview_row_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/context_menu_cell.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/context_menu_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/context_menu_table.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_edit_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_edit_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_edit_table.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/booleans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v27/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/booleans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 8dp
7 | 176dp
8 |
9 | 100dp
10 | 42dp
11 |
12 | 16dp
13 | 40dp
14 |
15 | 40dp
16 | 24dp
17 | 16sp
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/test/resources/robolectric.properties:
--------------------------------------------------------------------------------
1 | sdk=26, 33
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.version_desugar = '2.1.5'
5 | ext.version_nextcloud_common = '0.25.0'
6 | ext.version_nextcloud_commons = '2.3.7'
7 | ext.version_android_commons = '1.1.0'
8 | ext.version_sso = '1.3.2'
9 | ext.version_glide = '4.16.0'
10 | ext.version_emoji = '1.5.0'
11 | ext.version_retrofit = '2.11.0'
12 | ext.version_mapstruct = '1.6.3'
13 | }
14 |
15 | plugins {
16 | id 'com.android.application' version '8.10.1' apply false
17 | id 'com.android.library' version '8.10.1' apply false
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/database/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/database/consumer-rules.pro
--------------------------------------------------------------------------------
/database/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.google.gson.** { *; }
2 |
3 | # Add project specific ProGuard rules here.
4 | # You can control the set of applied configuration files using the
5 | # proguardFiles setting in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # If your project uses WebView with JS, uncomment the following
11 | # and specify the fully qualified class name to the JavaScript interface
12 | # class:
13 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
14 | # public *;
15 | #}
16 |
17 | # Uncomment this to preserve the line number information for
18 | # debugging stack traces.
19 | #-keepattributes SourceFile,LineNumberTable
20 |
21 | # If you keep the line number information, uncomment this to
22 | # hide the original source file name.
23 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/database/src/androidTest/java/it/niedermann/nextcloud/tables/database/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import android.content.Context;
6 |
7 | import androidx.test.ext.junit.runners.AndroidJUnit4;
8 | import androidx.test.platform.app.InstrumentationRegistry;
9 |
10 | import org.junit.Test;
11 | import org.junit.runner.RunWith;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("it.niedermann.nextcloud.types.database.test", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/database/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/DBStatus.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | public enum DBStatus {
6 |
7 | VOID(null),
8 | LOCAL_EDITED("LOCAL_EDITED"),
9 | LOCAL_DELETED("LOCAL_DELETED");
10 |
11 | @Nullable
12 | public final String title;
13 |
14 | DBStatus(@Nullable String title) {
15 | this.title = title;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/DBStatusConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import java.util.Objects;
7 |
8 | import it.niedermann.nextcloud.tables.database.DBStatus;
9 |
10 | public class DBStatusConverter {
11 |
12 | @TypeConverter
13 | public static DBStatus dbStatusFromString(@Nullable String value) {
14 | for (final var status : DBStatus.values()) {
15 | if (Objects.equals(status.title, value)) {
16 | return status;
17 | }
18 | }
19 |
20 | return DBStatus.VOID;
21 | }
22 |
23 | @TypeConverter
24 | public static String dbStatusToString(@Nullable DBStatus status) {
25 | return status == null ? null : status.title;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/EDataTypeConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import it.niedermann.nextcloud.tables.database.model.EDataType;
7 | import it.niedermann.nextcloud.tables.shared.FeatureToggle;
8 |
9 | public class EDataTypeConverter {
10 |
11 | @TypeConverter
12 | public static EDataType databaseTypeFromString(@Nullable Integer dataType) {
13 | if (dataType == null) {
14 | return EDataType.UNKNOWN;
15 | }
16 |
17 | try {
18 | return EDataType.findById(dataType);
19 |
20 | } catch (NumberFormatException e) {
21 | if (FeatureToggle.STRICT_MODE.enabled) {
22 | throw e;
23 | }
24 |
25 | return EDataType.UNKNOWN;
26 | }
27 | }
28 |
29 | @TypeConverter
30 | public static Integer databaseTypeToString(@Nullable EDataType dataType) {
31 | if (dataType == null || EDataType.UNKNOWN.equals(dataType)) {
32 | return null;
33 | }
34 |
35 | return dataType.getId();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/InstantConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import java.time.Instant;
7 | import java.util.Optional;
8 |
9 | public class InstantConverter {
10 |
11 | @TypeConverter
12 | public static Instant longToInstant(@Nullable Long instant) {
13 | return Optional.ofNullable(instant)
14 | .map(Instant::ofEpochMilli)
15 | .orElse(null);
16 | }
17 |
18 | @TypeConverter
19 | public static Long instantToLong(@Nullable Instant instant) {
20 | return Optional.ofNullable(instant)
21 | .map(Instant::toEpochMilli)
22 | .orElse(null);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/JsonElementConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import com.google.gson.JsonElement;
7 | import com.google.gson.JsonParser;
8 |
9 | public class JsonElementConverter {
10 |
11 | @TypeConverter
12 | public static JsonElement jsonElementFromString(@Nullable String value) {
13 | if (value == null) {
14 | return null;
15 | }
16 |
17 | return JsonParser.parseString(value);
18 | }
19 |
20 | @TypeConverter
21 | public static String jsonElementToString(@Nullable JsonElement value) {
22 | if (value == null) {
23 | return null;
24 | }
25 |
26 | return value.toString();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/LocalDateConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import java.time.LocalDate;
7 | import java.util.Optional;
8 |
9 | public class LocalDateConverter {
10 |
11 | @TypeConverter
12 | public static LocalDate longToLocalDate(@Nullable Long src) {
13 | return Optional.ofNullable(src)
14 | .map(LocalDate::ofEpochDay)
15 | .orElse(null);
16 | }
17 |
18 | @TypeConverter
19 | public static Long localDateToLong(@Nullable LocalDate src) {
20 | return Optional.ofNullable(src)
21 | .map(LocalDate::toEpochDay)
22 | .orElse(null);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/LocalTimeConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import java.time.LocalTime;
7 | import java.util.Optional;
8 |
9 | public class LocalTimeConverter {
10 |
11 | @TypeConverter
12 | public static LocalTime longToLocalTime(@Nullable Integer src) {
13 | return Optional.ofNullable(src)
14 | .map(LocalTime::ofSecondOfDay)
15 | .orElse(null);
16 | }
17 |
18 | @TypeConverter
19 | public static Integer instantToInteger(@Nullable LocalTime src) {
20 | return Optional.ofNullable(src)
21 | .map(LocalTime::toSecondOfDay)
22 | .orElse(null);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/UriConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import android.net.Uri;
4 |
5 | import androidx.annotation.Nullable;
6 | import androidx.room.TypeConverter;
7 |
8 | import java.util.Optional;
9 |
10 | public class UriConverter {
11 |
12 | @TypeConverter
13 | public static Uri dbStatusFromString(@Nullable String link) {
14 | return Uri.parse(link);
15 | }
16 |
17 | @TypeConverter
18 | public static String dbStatusToString(@Nullable Uri link) {
19 | return Optional
20 | .ofNullable(link)
21 | .map(Uri::toString)
22 | .orElse(null);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/converter/UserGroupTypeConverter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.converter;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.TypeConverter;
5 |
6 | import it.niedermann.nextcloud.tables.database.model.EUserGroupType;
7 |
8 | public class UserGroupTypeConverter {
9 |
10 | @TypeConverter
11 | public static EUserGroupType userGroupTypeFromInteger(@Nullable Integer type) {
12 | if (type == null) {
13 | return EUserGroupType.UNKNOWN;
14 | }
15 |
16 | return EUserGroupType.findByRemoteId(type);
17 | }
18 |
19 | @TypeConverter
20 | public static Integer userGroupTypeToInteger(@Nullable EUserGroupType type) {
21 | if (type == null || EUserGroupType.UNKNOWN.equals(type)) {
22 | return null;
23 | }
24 |
25 | return type.getRemoteType();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/dao/DataSelectionOptionCrossRefDao.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.dao;
2 |
3 | import androidx.room.Dao;
4 | import androidx.room.Delete;
5 | import androidx.room.Insert;
6 | import androidx.room.Query;
7 | import androidx.room.Upsert;
8 |
9 | import java.util.List;
10 |
11 | import it.niedermann.nextcloud.tables.database.entity.DataSelectionOptionCrossRef;
12 |
13 | @Dao
14 | public interface DataSelectionOptionCrossRefDao {
15 |
16 | @Insert
17 | long insert(DataSelectionOptionCrossRef entity);
18 |
19 | @Insert
20 | long[] insert(DataSelectionOptionCrossRef... entity);
21 |
22 | @Upsert
23 | long upsert(DataSelectionOptionCrossRef entity);
24 |
25 | @Delete
26 | void delete(DataSelectionOptionCrossRef... entity);
27 |
28 | @Query("""
29 | SELECT crossRef.*
30 | FROM DataSelectionOptionCrossRef crossRef
31 | WHERE crossRef.dataId = :dataId
32 | """)
33 | List getCrossRefs(long dataId);
34 | }
35 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/dao/DataUserGroupCrossRefDao.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.dao;
2 |
3 | import androidx.room.Dao;
4 | import androidx.room.Delete;
5 | import androidx.room.Insert;
6 | import androidx.room.Query;
7 | import androidx.room.Upsert;
8 |
9 | import java.util.List;
10 |
11 | import it.niedermann.nextcloud.tables.database.entity.DataUserGroupCrossRef;
12 |
13 | @Dao
14 | public interface DataUserGroupCrossRefDao {
15 |
16 | @Insert
17 | long insert(DataUserGroupCrossRef entity);
18 |
19 | @Upsert
20 | long upsert(DataUserGroupCrossRef entity);
21 |
22 | @Insert
23 | long[] insert(DataUserGroupCrossRef... entity);
24 |
25 | @Delete
26 | void delete(DataUserGroupCrossRef... entity);
27 |
28 | @Query("""
29 | DELETE FROM DataUserGroupCrossRef
30 | WHERE DataUserGroupCrossRef.dataId = :dataId
31 | """)
32 | void delete(long dataId);
33 |
34 | @Query("""
35 | SELECT crossRef.*
36 | FROM DataUserGroupCrossRef crossRef
37 | WHERE crossRef.dataId = :dataId
38 | """)
39 | List getCrossRefs(long dataId);
40 | }
41 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/dao/DefaultValueSelectionOptionCrossRefDao.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.dao;
2 |
3 | import androidx.room.Dao;
4 | import androidx.room.Delete;
5 | import androidx.room.Insert;
6 | import androidx.room.Query;
7 | import androidx.room.Upsert;
8 |
9 | import java.util.Collection;
10 |
11 | import it.niedermann.nextcloud.tables.database.entity.DefaultValueSelectionOptionCrossRef;
12 |
13 | @Dao
14 | public interface DefaultValueSelectionOptionCrossRefDao {
15 |
16 | @Insert
17 | long insert(DefaultValueSelectionOptionCrossRef entity);
18 |
19 | @Insert
20 | long[] insert(DefaultValueSelectionOptionCrossRef... entity);
21 |
22 | @Upsert
23 | long upsert(DefaultValueSelectionOptionCrossRef entity);
24 |
25 | @Delete
26 | void deleteExcept(DefaultValueSelectionOptionCrossRef... entity);
27 |
28 | @Query("""
29 | DELETE FROM DefaultValueSelectionOptionCrossRef
30 | WHERE columnId = :columnId
31 | AND selectionOptionId IN (:selectionOptionIds)
32 | """)
33 | void delete(long columnId, Collection selectionOptionIds);
34 |
35 | @Query("""
36 | DELETE FROM DefaultValueSelectionOptionCrossRef
37 | WHERE columnId = :columnId
38 | AND selectionOptionId NOT IN (:selectionOptionIds)
39 | """)
40 | void deleteExcept(long columnId, Collection selectionOptionIds);
41 | }
42 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/dao/GenericDao.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.dao;
2 |
3 | import androidx.room.Delete;
4 | import androidx.room.Insert;
5 | import androidx.room.Update;
6 | import androidx.room.Upsert;
7 |
8 | public interface GenericDao {
9 |
10 | @Insert
11 | long insert(T entity);
12 |
13 | @SuppressWarnings("unchecked")
14 | @Insert
15 | long[] insert(T... entity);
16 |
17 | @SuppressWarnings("unchecked")
18 | @Update
19 | void update(T... entity);
20 |
21 | /**
22 | * @noinspection unchecked
23 | */
24 | @Upsert
25 | void upsert(T... entity);
26 |
27 | @SuppressWarnings("unchecked")
28 | @Delete
29 | void delete(T... entity);
30 | }
31 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/dao/UserGroupDao.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.dao;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.room.Dao;
5 | import androidx.room.Query;
6 | import androidx.room.Transaction;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.UserGroup;
9 |
10 | @Dao
11 | public interface UserGroupDao extends GenericDao {
12 |
13 | @Transaction
14 | @Query("""
15 | SELECT EXISTS(
16 | SELECT u.id
17 | FROM UserGroup u
18 | WHERE u.accountId = :accountId
19 | AND u.remoteId = :remoteId
20 | LIMIT 1
21 | )
22 | """)
23 | boolean exists(long accountId, String remoteId);
24 |
25 | @Query("""
26 | SELECT u.id
27 | FROM UserGroup u
28 | WHERE u.accountId = :accountId
29 | AND u.remoteId = :remoteId
30 | """)
31 | Long getIdByRemoteId(long accountId, String remoteId);
32 |
33 | @Transaction
34 | default Long upsertAndGetId(@NonNull UserGroup userGroup) {
35 | upsert(userGroup);
36 | return getIdByRemoteId(userGroup.getAccountId(), userGroup.getRemoteId());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/AbstractEntity.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.room.Entity;
5 | import androidx.room.Ignore;
6 | import androidx.room.PrimaryKey;
7 |
8 | import java.io.Serializable;
9 | import java.util.Objects;
10 |
11 | @Entity()
12 | public abstract class AbstractEntity implements Serializable {
13 |
14 | @PrimaryKey(autoGenerate = true)
15 | protected long id;
16 |
17 |
18 | public AbstractEntity() {
19 | // Default constructor
20 | }
21 |
22 | @Ignore
23 | public AbstractEntity(@NonNull AbstractEntity entity) {
24 | this.id = entity.getId();
25 | }
26 |
27 | public long getId() {
28 | return id;
29 | }
30 |
31 | public void setId(long id) {
32 | this.id = id;
33 | }
34 |
35 | @Override
36 | public boolean equals(Object o) {
37 | if (this == o) return true;
38 | if (o == null || getClass() != o.getClass()) return false;
39 | AbstractEntity that = (AbstractEntity) o;
40 | return id == that.id;
41 | }
42 |
43 | @Override
44 | public int hashCode() {
45 | return Objects.hash(id);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/DataSelectionOptionCrossRef.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity;
2 |
3 | import androidx.room.Entity;
4 | import androidx.room.ForeignKey;
5 | import androidx.room.Index;
6 |
7 | @Entity(
8 | primaryKeys = {"dataId", "selectionOptionId"},
9 | foreignKeys = {
10 | @ForeignKey(
11 | entity = Data.class,
12 | parentColumns = "id",
13 | childColumns = "dataId",
14 | onDelete = ForeignKey.CASCADE
15 | ),
16 | @ForeignKey(
17 | entity = SelectionOption.class,
18 | parentColumns = "id",
19 | childColumns = "selectionOptionId",
20 | onDelete = ForeignKey.CASCADE
21 | )
22 | },
23 | indices = {
24 | @Index(value = {"dataId"}),
25 | @Index(value = {"selectionOptionId"})
26 | }
27 | )
28 | public record DataSelectionOptionCrossRef(
29 | long dataId,
30 | long selectionOptionId
31 | ) {
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/DataUserGroupCrossRef.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity;
2 |
3 | import androidx.room.Entity;
4 | import androidx.room.ForeignKey;
5 | import androidx.room.Index;
6 |
7 |
8 | @Entity(
9 | primaryKeys = {"dataId", "userGroupId"},
10 | foreignKeys = {
11 | @ForeignKey(
12 | entity = Data.class,
13 | parentColumns = "id",
14 | childColumns = "dataId",
15 | onDelete = ForeignKey.CASCADE
16 | ),
17 | @ForeignKey(
18 | entity = UserGroup.class,
19 | parentColumns = "id",
20 | childColumns = "userGroupId",
21 | onDelete = ForeignKey.CASCADE
22 | )
23 | },
24 | indices = {
25 | @Index(value = {"dataId"}),
26 | @Index(value = {"userGroupId"})
27 | }
28 | )
29 | public record DataUserGroupCrossRef(
30 | long dataId,
31 | long userGroupId
32 | ) {
33 | }
34 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/SynchronizationContext.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 | import androidx.room.Ignore;
6 |
7 | import java.io.Serializable;
8 |
9 | import it.niedermann.nextcloud.tables.database.DBStatus;
10 |
11 | public record SynchronizationContext(
12 | @Nullable DBStatus status,
13 | @Nullable String eTag
14 | ) implements Serializable {
15 |
16 | @Ignore
17 | public SynchronizationContext() {
18 | this(DBStatus.VOID, null);
19 | }
20 |
21 | @Ignore
22 | public SynchronizationContext(@NonNull SynchronizationContext remoteContext) {
23 | this(remoteContext.status, remoteContext.eTag);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/TextAllowedPattern.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.room.Entity;
5 | import androidx.room.Ignore;
6 |
7 | import java.util.Objects;
8 |
9 | @Entity(
10 | inheritSuperIndices = true
11 | )
12 | public class TextAllowedPattern extends AbstractEntity {
13 |
14 | private String pattern;
15 |
16 | public TextAllowedPattern() {
17 | // Default constructor
18 | }
19 |
20 | @Ignore
21 | public TextAllowedPattern(@NonNull TextAllowedPattern textAllowedPattern) {
22 | super(textAllowedPattern);
23 | this.pattern = textAllowedPattern.pattern;
24 | }
25 |
26 | public String getPattern() {
27 | return pattern;
28 | }
29 |
30 | public void setPattern(String pattern) {
31 | this.pattern = pattern;
32 | }
33 |
34 | @Override
35 | public boolean equals(Object o) {
36 | if (this == o) return true;
37 | if (o == null || getClass() != o.getClass()) return false;
38 | if (!super.equals(o)) return false;
39 | TextAllowedPattern that = (TextAllowedPattern) o;
40 | return Objects.equals(pattern, that.pattern);
41 | }
42 |
43 | @Override
44 | public int hashCode() {
45 | return Objects.hash(super.hashCode(), pattern);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/attributes/DateTimeAttributes.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity.attributes;
2 |
3 | import java.io.Serializable;
4 |
5 | public record DateTimeAttributes(
6 | ) implements Serializable {
7 | }
8 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/attributes/NumberAttributes.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity.attributes;
2 |
3 | import androidx.annotation.Nullable;
4 | import androidx.room.Ignore;
5 |
6 | import java.io.Serializable;
7 |
8 | public record NumberAttributes(
9 | @Nullable Double numberMin,
10 | @Nullable Double numberMax,
11 | @Nullable Integer numberDecimals,
12 | @Nullable String numberPrefix,
13 | @Nullable String numberSuffix
14 | ) implements Serializable {
15 |
16 | @Ignore
17 | public NumberAttributes() {
18 | this(null, null, null, null, null);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/attributes/SelectionAttributes.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity.attributes;
2 |
3 | import java.io.Serializable;
4 |
5 | public record SelectionAttributes(
6 | ) implements Serializable {
7 | }
8 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/attributes/TextAttributes.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity.attributes;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 | import androidx.room.Ignore;
6 |
7 | import java.io.Serializable;
8 |
9 | public record TextAttributes(
10 | @Nullable String textAllowedPattern,
11 | @Nullable Integer textMaxLength
12 | ) implements Serializable {
13 |
14 | @Ignore
15 | public TextAttributes() {
16 | this(null, null);
17 | }
18 |
19 | @Ignore
20 | public TextAttributes(@NonNull TextAttributes textAttributes) {
21 | this(textAttributes.textAllowedPattern, textAttributes.textMaxLength);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/entity/attributes/UserGroupAttributes.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.entity.attributes;
2 |
3 | import androidx.room.ColumnInfo;
4 | import androidx.room.Ignore;
5 |
6 | import java.io.Serializable;
7 |
8 | public record UserGroupAttributes(
9 | boolean usergroupMultipleItems,
10 | boolean usergroupSelectUsers,
11 | boolean usergroupSelectGroups,
12 | @ColumnInfo(defaultValue = "0")
13 | boolean usergroupSelectTeams,
14 | boolean showUserStatus
15 | ) implements Serializable {
16 |
17 | @Ignore
18 | public UserGroupAttributes() {
19 | this(false, false, false, false, false);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/migration/Migration_3_4.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.migration;
2 |
3 | import androidx.room.DeleteColumn;
4 | import androidx.room.migration.AutoMigrationSpec;
5 |
6 | @DeleteColumn.Entries(
7 | @DeleteColumn(
8 | tableName = "UserGroup",
9 | columnName = "key"
10 | )
11 | )
12 | public class Migration_3_4 implements AutoMigrationSpec {
13 | }
14 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/migration/Migration_4_5.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.migration;
2 |
3 | import androidx.room.migration.AutoMigrationSpec;
4 |
5 | /// Adds `archived` and `favorite` columns to `Table` entity
6 | public class Migration_4_5 implements AutoMigrationSpec {
7 | }
8 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/model/EUserGroupType.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.model;
2 |
3 | public enum EUserGroupType {
4 | UNKNOWN(-1),
5 | USER(0),
6 | GROUP(1),
7 | TEAM(7),
8 | ;
9 |
10 | private final int remoteType;
11 |
12 | EUserGroupType(int remoteType) {
13 | this.remoteType = remoteType;
14 | }
15 |
16 | public static EUserGroupType findByRemoteId(int remoteType) {
17 | for (final var value : values()) {
18 | if (value.remoteType == remoteType) {
19 | return value;
20 | }
21 | }
22 |
23 | return UNKNOWN;
24 | }
25 |
26 | public int getRemoteType() {
27 | return remoteType;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/model/NextcloudVersion.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | public class NextcloudVersion extends Version {
6 |
7 | private static final Version V_25_0_0 = new Version("25.0.0", 25, 0, 0);
8 |
9 | public NextcloudVersion(@NonNull String version, int major, int minor, int patch) {
10 | super(version, major, minor, patch);
11 | }
12 |
13 | public static NextcloudVersion parse(@NonNull String version) {
14 | return of(Version.parse(version));
15 | }
16 |
17 | public static NextcloudVersion of(@NonNull Version version) {
18 | return new NextcloudVersion(version.getVersion(), version.getMajor(), version.getMinor(), version.getPatch());
19 | }
20 |
21 | public boolean isSupported() {
22 | return isGreaterThanOrEqual(V_25_0_0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/src/main/java/it/niedermann/nextcloud/tables/database/model/TablesVersion.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | public class TablesVersion extends Version {
6 |
7 | public static final TablesVersion V_0_5_0 = new TablesVersion("0.5.0", 0, 5, 0);
8 | public static final TablesVersion V_0_8_0 = new TablesVersion("0.8.0", 0, 8, 0);
9 |
10 | public TablesVersion(@NonNull String version, int major, int minor, int patch) {
11 | super(version, major, minor, patch);
12 | }
13 |
14 | public static TablesVersion parse(@NonNull String version) {
15 | return of(Version.parse(version));
16 | }
17 |
18 | public static TablesVersion of(@NonNull Version version) {
19 | return new TablesVersion(version.getVersion(), version.getMajor(), version.getMinor(), version.getPatch());
20 | }
21 |
22 | public boolean isSupported() {
23 | return isGreaterThanOrEqual(V_0_8_0);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/database/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Unknown
4 | Text
5 | Number
6 | Selection
7 | Date and time
8 | Users and groups
9 |
10 | Long
11 | Line
12 | Rich
13 | Link
14 | Default
15 | Stars rating
16 | Progress bar
17 | Single
18 | Multi
19 | Check
20 | Date and time
21 | Date
22 | Time
23 |
--------------------------------------------------------------------------------
/database/src/test/java/it/niedermann/nextcloud/tables/database/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.database;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000000.txt:
--------------------------------------------------------------------------------
1 | Initial release ✨
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000001.txt:
--------------------------------------------------------------------------------
1 | - feat: Enable selection editor
2 | - feat: Rich text viewer
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000002.txt:
--------------------------------------------------------------------------------
1 | - i18n: Add translations from transifex
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000003.txt:
--------------------------------------------------------------------------------
1 | - feat: Rich text editor
2 | - fix: Make row editor scrollable
3 | - fix: Preserve state when rotating device while editing row
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000004.txt:
--------------------------------------------------------------------------------
1 | - feat(ui): Directly display selection values in table view
2 | - feat(permissions): Respect permissions for shared tables
3 | - feat(sync): Synchronize account on app start
4 | - feat(preferences): Allow synchronizing on Wi-Fi only
5 | - enh(sync): Better handling of network errors
6 | - feat(ui): Add monochrome launcher icon
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000005.txt:
--------------------------------------------------------------------------------
1 | - enh: Show existing value if column type is not supported
2 | - fix: Prevent crash for numbers with constraints
3 | - fix: Prevent crash when opening account switcher dialog before importing any account
4 | - fix: Prevent crash when min or max is not configured for number columns
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000006.txt:
--------------------------------------------------------------------------------
1 | - fix: Prevent crash for selections in special circumstances
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000007.txt:
--------------------------------------------------------------------------------
1 | - fix: Make viewing and editing data more robust
2 | - fix: Fix wrong displayed selection text in special circumstances
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1000008.txt:
--------------------------------------------------------------------------------
1 | - fix: Star editor displayed wrong number of stars (#7)
2 | - fix: SQLiteException: too many SQL variables (#8)
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1001000.txt:
--------------------------------------------------------------------------------
1 | - feat: Edit columns (experimental feature)
2 | - feat: Reorder columns (experimental feature)
3 | - feat: Delete columns
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1001001.txt:
--------------------------------------------------------------------------------
1 | - enh: Disable mandatory property in column editor
2 | - fix: Allow entering decimals for number fields
3 | - fix: Hide complete table when no rows are present as workaround for crash
4 | - fix: Do not show deleted selection options in editor
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1001002.txt:
--------------------------------------------------------------------------------
1 | - enh: Disable mandatory property in column editor
2 | - fix: Allow entering decimals for number fields
3 | - fix: Hide complete table when no rows are present as workaround for crash
4 | - fix: Do not show deleted selection options in editor
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1001003.txt:
--------------------------------------------------------------------------------
1 | - fix: Prevents crash when table emoji is null
2 | - fix: Treat "null" as null for selection default
3 | - fix: Fix logging of Tables server app version
4 | - fix: Compatibility with "none" as default value for datetimes
5 | - fix: Prevents crash after deleting a table
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000000.txt:
--------------------------------------------------------------------------------
1 | Tables Android 2.0 is a complete rewrite with a maintainable and extensible long term architecture in mind.
2 | We believe that we roughly reached feature parity with Tables Android 1.0, so don't expect many new features in this release, but you can look forward to more frequent releases in the future.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000001.txt:
--------------------------------------------------------------------------------
1 | fix(sync): Prevent endless loading spinner
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000002.txt:
--------------------------------------------------------------------------------
1 | fix(ui): Fix missing create row button and invisible table content off screen
2 | fix(edit): Fix change detection of number editor, so it does not ask to save unchanged values everytime
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000003.txt:
--------------------------------------------------------------------------------
1 | fix(database)!: ⚠️ Enforce foreign key constraints (Not yet synchronized changes will be lost on update!)
2 | feat(usergroup): Synchronize and display usergroup values
3 | fix(ui): Order tables in sidebar by createdAt rather than title to match Tables server app (#147)
4 | fix(text-link): Fix updated links not being saved
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000004.txt:
--------------------------------------------------------------------------------
1 | feat: Enhanced performance by only querying the displayed data from the database
2 | fix(datetime): Fix editing and viewing datetime cells
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000005.txt:
--------------------------------------------------------------------------------
1 | fix: Extend visible range of rows by 10 before querying rows from db
2 | fix: Make use of bindPending method for rows that are not loaded from the db yet
3 | fix(sync): Decimal number is rounded up when updating (#153)
4 | fix(ui): Display column default as fallback if number/progress has no value instead of an indeterminate animation
5 | fix(ui): Use minimal possible value as fallback if number/progress has no value and the corresponding colum has no default value
6 | chore(ui): Introduce databinding in AboutActivity
7 | docs: Add CONTRIBUTING.md
8 | feat(logging): Enrich synchronization exceptions with contextual information
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000006.txt:
--------------------------------------------------------------------------------
1 | fix(sync): Remove debug code causing NumberFormatException
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000007.txt:
--------------------------------------------------------------------------------
1 | fix(ui): Fix showing / hiding FAB depending on create permission for the current table
2 | chore(deps): Update AGP to 8.8.1
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2000008.txt:
--------------------------------------------------------------------------------
1 | fix: Make SyncExceptionWithContext implement Serializable to avoid crash
2 | fix: Fix syntax error
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2001000.txt:
--------------------------------------------------------------------------------
1 | feat(table): Allow changing the emoji of tables
2 | feat(columns): Allow adding and editing columns (except single selections and user groups)
3 | feat(rows): Display default values as fallback for selection cells
4 | feat(number): Introduce internationalization to number input editor (e. g. use appropriate decimal separator)
5 | fix(number-progress): Show save prompt only when there are unsaved changes
6 | fix(import): Prevent undefined state after pressing back while importing an account
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2001001.txt:
--------------------------------------------------------------------------------
1 | fix(sharing): Fix permissions for shared tables (#179)
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002000.txt:
--------------------------------------------------------------------------------
1 | fix: Avoid endless spinner when switching to the same table that is currently active
2 | feat(table): Add support for archived and favorite tables
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002001.txt:
--------------------------------------------------------------------------------
1 | fix: Fix scrolling / swipe to refresh conflict
2 | fix: Fix crash on startup after update caused by database migration
3 | fix(number): Fix not editable numbers when min or decimals are not present in column settings
4 | fix(sync): Fix potential foreign key constraint violation at selection options
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002002.txt:
--------------------------------------------------------------------------------
1 | fix(edit): Fix pristine state of date and time editors
2 | fix(edit): Fix NullPointerException when editing number columns with nullish attributes
3 | fix(sync): Fix potential foreign key constraint violation when synchronizing selection option relations
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002003.txt:
--------------------------------------------------------------------------------
1 | fix: Crash after updating to 2.2.1
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002004.txt:
--------------------------------------------------------------------------------
1 | fix(number): Fix locale depending separator character for editing number decimals
2 | fix(perf): Don't let synchronization plugging user interactions
3 | fix(perf): Do only establish connections to the files app for APIs that will actually be used
4 | fix(perf): Limit reporter synchronization to current reporter instance
5 | fix(import): Fix displaying progress while importing an account
6 | fix(import): Pressing back when importing another account returns to main view instead of closing the app
7 | fix(logging): Enhance logging context
8 | chore(logging): Replace Android Logging with Java Util Logging
9 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2002005.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/changelogs/2002005.txt
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | An Android client for Nextcloud Tables App¹.
2 |
3 | ⚠️ Warning ⚠️
4 | This app is currently under heavy development. It is not yet ready to view or manage data in a production environment. Data loss may be possible. Use at your own risc!
5 | For limitations see https://github.com/stefan-niedermann/nextcloud-tables/#readme
6 |
7 | 🚀 Features
8 | * Multiple accounts 👥
9 | * Works offline 🔌
10 | * Manage tables, columns and rows 📝
11 | * Dark mode 🌙
12 | * Translated in many languages 🌎
13 |
14 | 🔗 Requirements
15 | * Nextcloud¹ instance running
16 | * Nextcloud Android² app installed (version 3.2.2 or later)
17 | * Nextcloud Tables app enabled (version 0.5.0 or later)
18 |
19 | 📓 License
20 | All contributions to this repository are considered to be licensed under the [GNU GENERAL PUBLIC LICENSE 3+](/LICENSE).
21 |
22 | ¹ https://github.com/nextcloud/android
23 | ² https://nextcloud.com/
24 | ³ https://github.com/nextcloud/tables/
25 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/featureGraphic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/featureGraphic.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Companion app for Nextcloud Tables
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Nextcloud Tables
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
2 | org.gradle.configuration-cache=true
3 | android.useAndroidX=true
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/remote/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/remote/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/remote/consumer-rules.pro
--------------------------------------------------------------------------------
/remote/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.google.gson.** { *; }
2 |
3 | # Add project specific ProGuard rules here.
4 | # You can control the set of applied configuration files using the
5 | # proguardFiles setting in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # If your project uses WebView with JS, uncomment the following
11 | # and specify the fully qualified class name to the JavaScript interface
12 | # class:
13 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
14 | # public *;
15 | #}
16 |
17 | # Uncomment this to preserve the line number information for
18 | # debugging stack traces.
19 | #-keepattributes SourceFile,LineNumberTable
20 |
21 | # If you keep the line number information, uncomment this to
22 | # hide the original source file name.
23 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/remote/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/adapter/OcsAutocompleteSourceListAdapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.adapter;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonNull;
5 | import com.google.gson.JsonSerializationContext;
6 | import com.google.gson.JsonSerializer;
7 |
8 | import java.lang.reflect.Type;
9 | import java.util.List;
10 |
11 | import it.niedermann.nextcloud.tables.remote.ocs.model.OcsAutocompleteResult;
12 | import it.niedermann.nextcloud.tables.remote.shared.util.JsonArrayCollector;
13 |
14 | public class OcsAutocompleteSourceListAdapter implements JsonSerializer> {
15 |
16 | @Override
17 | public JsonElement serialize(List src, Type typeOfSrc, JsonSerializationContext context) {
18 | if (src == null) {
19 | return JsonNull.INSTANCE;
20 | }
21 |
22 | return src
23 | .stream()
24 | .map(context::serialize)
25 | .collect(new JsonArrayCollector());
26 | }
27 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/model/CapabilitiesResponse.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.model;
2 |
3 | import com.nextcloud.android.sso.model.ocs.OcsCapabilitiesResponse;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Utilizing {@link OcsCapabilitiesResponse} classes combined with own tables specific information
9 | */
10 | public record CapabilitiesResponse(
11 | OcsCapabilitiesResponse.OcsVersion version,
12 | OcsCapabilities capabilities
13 | ) implements Serializable {
14 | public record OcsCapabilities(
15 | OcsCapabilitiesResponse.OcsCapabilities.OcsTheming theming,
16 | Tables tables
17 | ) implements Serializable {
18 | public record Tables(
19 | boolean enabled,
20 | String version
21 | ) implements Serializable {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/model/OcsAutocompleteResult.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.model;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.io.Serializable;
9 |
10 | /// [Documentation](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-api-overview.html#auto-complete-and-user-search)
11 | public record OcsAutocompleteResult(
12 | @NonNull String id,
13 | @NonNull String label,
14 | @Nullable String icon,
15 | @NonNull OcsAutocompleteSource source,
16 | @Nullable String subline,
17 | @Nullable String shareWithDisplayNameUnique
18 | ) implements Serializable {
19 |
20 | public enum OcsAutocompleteSource {
21 | @SerializedName(value = "0", alternate = "users")
22 | USERS(0),
23 | @SerializedName(value = "1", alternate = "groups")
24 | GROUPS(1),
25 | @SerializedName(value = "7", alternate = "teams")
26 | TEAMS(7),
27 | ;
28 |
29 | public final int shareType;
30 |
31 | OcsAutocompleteSource(int shareType) {
32 | this.shareType = shareType;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/model/OcsSearchProvider.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 |
9 | /// @see Source
10 | public record OcsSearchProvider(
11 | @SerializedName("id")
12 | @Nullable String remoteId,
13 | @Nullable String appId,
14 | @Nullable String name,
15 | @Nullable String icon,
16 | int order,
17 | boolean inAppSearch
18 | ) implements Serializable {
19 | }
20 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/model/OcsSearchResult.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.model;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | public record OcsSearchResult(
10 | @Nullable String name,
11 | boolean isPaginated,
12 | @NonNull List entries,
13 | @Nullable Integer cursor
14 | ) implements Serializable {
15 | }
16 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/ocs/model/OcsSearchResultEntry.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.ocs.model;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.io.Serializable;
7 | import java.util.Map;
8 |
9 | /// @see Source
10 | public record OcsSearchResultEntry(
11 | /// @since 20.0.0
12 | @Nullable String thumbnailUrl,
13 | /// @since 20.0.0
14 | @Nullable String title,
15 | /// @since 20.0.0
16 | @Nullable String subline,
17 | /// @since 20.0.0
18 | @Nullable String resourceUrl,
19 | /// @since 20.0.0
20 | @Nullable String icon,
21 | /// @since 20.0.0
22 | boolean rounded,
23 | ///@since 20.0.0
24 | @NonNull Map attributes
25 | ) implements Serializable {
26 | }
27 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/shared/model/DataResponseDto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.shared.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.io.Serializable;
9 |
10 | public record DataResponseDto(
11 | @SerializedName("columnId")
12 | @Nullable Long remoteColumnId,
13 | @Nullable JsonElement value
14 | ) implements Serializable {
15 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/shared/model/RemoteDto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.shared.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | public interface RemoteDto {
6 |
7 | @Nullable
8 | Long remoteId();
9 | }
10 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/shared/util/JsonArrayCollector.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.shared.util;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonElement;
5 |
6 | import java.util.Collections;
7 | import java.util.Set;
8 | import java.util.function.BiConsumer;
9 | import java.util.function.BinaryOperator;
10 | import java.util.function.Function;
11 | import java.util.function.Supplier;
12 | import java.util.stream.Collector;
13 |
14 | public class JsonArrayCollector implements Collector {
15 |
16 | @Override
17 | public Supplier supplier() {
18 | return JsonArray::new;
19 | }
20 |
21 | @Override
22 | public BiConsumer accumulator() {
23 | return JsonArray::add;
24 | }
25 |
26 | @Override
27 | public BinaryOperator combiner() {
28 | return ((jsonArray, jsonArray2) -> {
29 | final var result = new JsonArray();
30 | result.addAll(jsonArray);
31 | result.addAll(jsonArray2);
32 | return result;
33 | });
34 | }
35 |
36 | @Override
37 | public Function finisher() {
38 | return result -> result;
39 | }
40 |
41 | @Override
42 | public Set characteristics() {
43 | return Collections.emptySet();
44 | }
45 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/adapter/BooleanV1Adapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.adapter;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonPrimitive;
7 | import com.google.gson.JsonSerializationContext;
8 | import com.google.gson.JsonSerializer;
9 |
10 | import java.lang.reflect.Type;
11 |
12 | public class BooleanV1Adapter implements JsonSerializer, JsonDeserializer {
13 |
14 | private static final JsonPrimitive TRUE = new JsonPrimitive(1);
15 | private static final JsonPrimitive FALSE = new JsonPrimitive(0);
16 |
17 | @Override
18 | public synchronized JsonElement serialize(Boolean src, Type type, JsonSerializationContext jsonSerializationContext) {
19 | return Boolean.TRUE.equals(src) ? TRUE : FALSE;
20 | }
21 |
22 | @Override
23 | public synchronized Boolean deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) {
24 | if (jsonElement == null) {
25 | return false;
26 | }
27 |
28 | try {
29 | return jsonElement.getAsBoolean();
30 | } catch (UnsupportedOperationException | IllegalStateException e) {
31 | return false;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/adapter/EUserGroupTypeV1Adapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.adapter;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 | import com.google.gson.JsonPrimitive;
8 | import com.google.gson.JsonSerializationContext;
9 | import com.google.gson.JsonSerializer;
10 |
11 | import java.lang.reflect.Type;
12 | import java.util.Optional;
13 |
14 | import it.niedermann.nextcloud.tables.remote.tablesV1.model.EUserGroupTypeV1Dto;
15 |
16 | public class EUserGroupTypeV1Adapter implements JsonSerializer, JsonDeserializer {
17 |
18 | @Override
19 | public EUserGroupTypeV1Dto deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
20 | return Optional.ofNullable(json)
21 | .map(JsonElement::getAsInt)
22 | .map(EUserGroupTypeV1Dto::findByRemoteId)
23 | .orElse(null);
24 | }
25 |
26 | @Override
27 | public JsonElement serialize(EUserGroupTypeV1Dto src, Type typeOfSrc, JsonSerializationContext context) {
28 | return Optional.ofNullable(src)
29 | .map(EUserGroupTypeV1Dto::getRemoteId)
30 | .map(JsonPrimitive::new)
31 | .orElse(null);
32 | }
33 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/adapter/UserGroupV1ListAdapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.adapter;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonNull;
5 | import com.google.gson.JsonPrimitive;
6 | import com.google.gson.JsonSerializationContext;
7 | import com.google.gson.JsonSerializer;
8 |
9 | import java.lang.reflect.Type;
10 | import java.util.List;
11 | import java.util.Optional;
12 |
13 | import it.niedermann.nextcloud.tables.remote.tablesV1.model.ColumnRequestV1Dto;
14 |
15 | public class UserGroupV1ListAdapter implements JsonSerializer> {
16 |
17 | @Override
18 | public JsonElement serialize(List src, Type typeOfSrc, JsonSerializationContext context) {
19 | return Optional.ofNullable(src)
20 | .map(context::serialize)
21 | .map(JsonElement::toString)
22 | .map(JsonPrimitive::new)
23 | .map(JsonElement.class::cast)
24 | .orElse(JsonNull.INSTANCE);
25 | }
26 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/model/EUserGroupTypeV1Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.util.NoSuchElementException;
8 |
9 | public enum EUserGroupTypeV1Dto {
10 | USER(0),
11 | GROUP(1),
12 | CIRCLE(7),
13 | ;
14 |
15 | @SerializedName("id")
16 | private final int remoteId;
17 |
18 | EUserGroupTypeV1Dto(int remoteId) {
19 | this.remoteId = remoteId;
20 | }
21 |
22 | public int getRemoteId() {
23 | return remoteId;
24 | }
25 |
26 | @NonNull
27 | public static EUserGroupTypeV1Dto findByRemoteId(int remoteId) {
28 | for (final var value : values()) {
29 | if (value.getRemoteId() == remoteId) {
30 | return value;
31 | }
32 | }
33 |
34 | throw new NoSuchElementException("Could not find " + EUserGroupTypeV1Dto.class.getSimpleName() + " with remoteId " + remoteId);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/model/FetchRowResponseV1Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 | import java.time.Instant;
9 | import java.util.List;
10 |
11 | import it.niedermann.nextcloud.tables.remote.shared.model.DataResponseDto;
12 |
13 | public record FetchRowResponseV1Dto(
14 | @SerializedName("id")
15 | @Nullable Long remoteId,
16 | @Nullable String createdBy,
17 | @Nullable Instant createdAt,
18 | @Nullable String lastEditBy,
19 | @Nullable Instant lastEditAt,
20 | @Nullable List data
21 | ) implements Serializable {
22 | }
23 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/model/UpdateColumnResponseV1Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.io.Serializable;
6 |
7 | import it.niedermann.nextcloud.tables.remote.shared.model.RemoteDto;
8 |
9 | public record UpdateColumnResponseV1Dto(
10 | @SerializedName("id")
11 | Long remoteId
12 | ) implements Serializable, RemoteDto {
13 | }
14 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/model/UpdateRowRequestV1Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.google.gson.JsonElement;
6 |
7 | import java.io.Serializable;
8 | import java.util.Map;
9 |
10 | public record UpdateRowRequestV1Dto(
11 | @NonNull Map data
12 | ) implements Serializable {
13 | }
14 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV1/model/UpdateRowResponseV1Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV1.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public record UpdateRowResponseV1Dto(
6 | @SerializedName("id")
7 | long remoteId
8 | ) {
9 | }
10 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/adapter/ENodeTypeV2Adapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.adapter;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 | import com.google.gson.JsonPrimitive;
8 | import com.google.gson.JsonSerializationContext;
9 | import com.google.gson.JsonSerializer;
10 |
11 | import java.lang.reflect.Type;
12 | import java.util.Optional;
13 |
14 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.ENodeTypeV2Dto;
15 |
16 |
17 | public class ENodeTypeV2Adapter implements JsonSerializer, JsonDeserializer {
18 |
19 | @Override
20 | public ENodeTypeV2Dto deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
21 | return Optional.ofNullable(json)
22 | .map(JsonElement::getAsString)
23 | .map(ENodeTypeV2Dto::findByString)
24 | .orElse(null);
25 | }
26 |
27 | @Override
28 | public JsonElement serialize(ENodeTypeV2Dto src, Type typeOfSrc, JsonSerializationContext context) {
29 | return Optional.ofNullable(src)
30 | .map(ENodeTypeV2Dto::toString)
31 | .map(JsonPrimitive::new)
32 | .orElse(null);
33 | }
34 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/adapter/EUserGroupV2Adapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.adapter;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 | import com.google.gson.JsonPrimitive;
8 | import com.google.gson.JsonSerializationContext;
9 | import com.google.gson.JsonSerializer;
10 |
11 | import java.lang.reflect.Type;
12 | import java.util.Optional;
13 |
14 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.EUserGroupTypeV2Dto;
15 |
16 | public class EUserGroupV2Adapter implements JsonSerializer, JsonDeserializer {
17 |
18 | @Override
19 | public EUserGroupTypeV2Dto deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
20 | return Optional.ofNullable(json)
21 | .map(JsonElement::getAsInt)
22 | .map(EUserGroupTypeV2Dto::findByRemoteId)
23 | .orElse(null);
24 | }
25 |
26 | @Override
27 | public JsonElement serialize(EUserGroupTypeV2Dto src, Type typeOfSrc, JsonSerializationContext context) {
28 | return Optional.ofNullable(src)
29 | .map(EUserGroupTypeV2Dto::getRemoteId)
30 | .map(JsonPrimitive::new)
31 | .orElse(null);
32 | }
33 | }
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/creators/ColumnCreator.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.creators;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.nextcloud.android.sso.model.ocs.OcsResponse;
6 |
7 | import it.niedermann.nextcloud.tables.remote.tablesV2.TablesV2API;
8 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.ColumnV2Dto;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.CreateColumnResponseV2Dto;
10 | import retrofit2.Call;
11 |
12 | public interface ColumnCreator {
13 |
14 | Call> createColumn(@NonNull TablesV2API tablesV2API,
15 | long tableRemoteId,
16 | @NonNull ColumnV2Dto column);
17 | }
18 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/creators/NoOpCreator.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.creators;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.nextcloud.android.sso.model.ocs.OcsResponse;
6 |
7 | import it.niedermann.nextcloud.tables.remote.tablesV2.TablesV2API;
8 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.ColumnV2Dto;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.CreateColumnResponseV2Dto;
10 | import retrofit2.Call;
11 |
12 | public class NoOpCreator implements ColumnCreator {
13 |
14 | @Override
15 | public Call> createColumn(@NonNull TablesV2API tablesV2API,
16 | long tableRemoteId,
17 | @NonNull ColumnV2Dto column) {
18 | throw new UnsupportedOperationException("Can not create columns for the given type.");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/CreateColumnResponseV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 |
9 | import it.niedermann.nextcloud.tables.remote.shared.model.RemoteDto;
10 |
11 | public record CreateColumnResponseV2Dto(
12 | @SerializedName("id")
13 | @Nullable Long remoteId
14 | ) implements Serializable, RemoteDto {
15 | }
16 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/CreateRowResponseV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 | import java.time.Instant;
9 | import java.util.List;
10 |
11 | import it.niedermann.nextcloud.tables.remote.shared.model.DataResponseDto;
12 |
13 | public record CreateRowResponseV2Dto(
14 | @SerializedName("id")
15 | @Nullable Long remoteId,
16 | @Nullable String createdBy,
17 | @Nullable Instant createdAt,
18 | @Nullable String lastEditBy,
19 | @Nullable Instant lastEditAt,
20 | @Nullable List data
21 | ) implements Serializable {
22 | }
23 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/CreateRowV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.google.gson.JsonElement;
6 |
7 | import java.io.Serializable;
8 | import java.util.Map;
9 |
10 | public record CreateRowV2Dto(
11 | @NonNull Map data
12 | ) implements Serializable {
13 | }
14 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/ENodeCollectionV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | public enum ENodeCollectionV2Dto {
6 | TABLES("tables"),
7 | ;
8 |
9 | private final String nodeCollection;
10 |
11 | ENodeCollectionV2Dto(@NonNull String nodeCollection) {
12 | this.nodeCollection = nodeCollection;
13 | }
14 |
15 | @NonNull
16 | @Override
17 | public String toString() {
18 | return this.nodeCollection;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/ENodeTypeV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.util.NoSuchElementException;
7 |
8 | public enum ENodeTypeV2Dto {
9 | TABLE("table", 0),
10 | VIEW("view", 1),
11 | ;
12 |
13 | public final String nodeType;
14 | public final int id;
15 |
16 | ENodeTypeV2Dto(@NonNull String nodeType, int id) {
17 | this.nodeType = nodeType;
18 | this.id = id;
19 | }
20 |
21 | @NonNull
22 | @Override
23 | public String toString() {
24 | return this.nodeType;
25 | }
26 |
27 | public static ENodeTypeV2Dto findByString(@Nullable String stringRepresentation) {
28 | for (final var value : values()) {
29 | if (value.nodeType.equals(stringRepresentation)) {
30 | return value;
31 | }
32 | }
33 |
34 | throw new NoSuchElementException("Unknown " + ENodeTypeV2Dto.class.getSimpleName() + ": \"" + stringRepresentation + "\"");
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/EPermissionV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | public enum EPermissionV2Dto {
4 | READ,
5 | CREATE,
6 | UPDATE,
7 | DELETE,
8 | MANAGE,
9 | }
10 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/EUserGroupTypeV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import java.util.NoSuchElementException;
4 |
5 | public enum EUserGroupTypeV2Dto {
6 | USER(0),
7 | GROUP(1),
8 | TEAMS(7),
9 | ;
10 |
11 | private final int remoteId;
12 |
13 | EUserGroupTypeV2Dto(int remoteId) {
14 | this.remoteId = remoteId;
15 | }
16 |
17 | public int getRemoteId() {
18 | return remoteId;
19 | }
20 |
21 | public static EUserGroupTypeV2Dto findByRemoteId(int remoteId) {
22 | for (final var value : values()) {
23 | if (value.remoteId == remoteId) {
24 | return value;
25 | }
26 | }
27 |
28 | throw new NoSuchElementException("Could not find " + EUserGroupTypeV2Dto.class.getSimpleName() + " with remoteId " + remoteId);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/OnSharePermissionV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import java.io.Serializable;
6 |
7 | public record OnSharePermissionV2Dto(
8 | @Nullable Boolean read,
9 | @Nullable Boolean create,
10 | @Nullable Boolean update,
11 | @Nullable Boolean delete,
12 | @Nullable Boolean manage
13 | ) implements Serializable {
14 | }
15 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/SelectionOptionV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 |
9 | public record SelectionOptionV2Dto(
10 | @SerializedName("id")
11 | @Nullable Long remoteId,
12 | @Nullable String label
13 | ) implements Serializable {
14 | }
15 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/TableV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import com.google.gson.annotations.SerializedName;
7 |
8 | import java.io.Serializable;
9 | import java.time.Instant;
10 | import java.util.Locale;
11 |
12 | import it.niedermann.nextcloud.tables.remote.shared.model.RemoteDto;
13 |
14 | public record TableV2Dto(
15 | @SerializedName("id")
16 | @Nullable Long remoteId,
17 | @NonNull String title,
18 | @NonNull String emoji,
19 | @Nullable String description,
20 | @Nullable String ownership,
21 | @Nullable String ownerDisplayName,
22 | @Nullable String createdBy,
23 | @Nullable Instant createdAt,
24 | @Nullable String lastEditBy,
25 | @Nullable Instant lastEditAt,
26 | @Nullable Boolean archived,
27 | @Nullable Boolean favorite,
28 | @Nullable Boolean isShared,
29 | @Nullable OnSharePermissionV2Dto onSharePermissions
30 | ) implements Serializable, RemoteDto {
31 |
32 | @NonNull
33 | @Override
34 | public String toString() {
35 | return String.format(Locale.getDefault(), "%s %s", emoji(), title()).trim();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/UserGroupV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.io.Serializable;
8 |
9 | public record UserGroupV2Dto(
10 | @SerializedName("id")
11 | String remoteId,
12 | @NonNull
13 | String key,
14 | EUserGroupTypeV2Dto type
15 | ) implements Serializable {
16 | }
17 |
--------------------------------------------------------------------------------
/remote/src/main/java/it/niedermann/nextcloud/tables/remote/tablesV2/model/columns/CreateDateTimeColumnV2Dto.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.remote.tablesV2.model.columns;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Objects;
6 |
7 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.ColumnV2Dto;
8 |
9 | public class CreateDateTimeColumnV2Dto extends CreateColumnV2Dto {
10 |
11 | private final String datetimeDefault;
12 |
13 | public CreateDateTimeColumnV2Dto(long tableRemoteId, @NonNull ColumnV2Dto column) {
14 | super(tableRemoteId, column);
15 | this.datetimeDefault = column.datetimeDefault();
16 | }
17 |
18 | public String getDatetimeDefault() {
19 | return datetimeDefault;
20 | }
21 |
22 | @Override
23 | public boolean equals(Object o) {
24 | if (this == o) return true;
25 | if (o == null || getClass() != o.getClass()) return false;
26 | if (!super.equals(o)) return false;
27 | CreateDateTimeColumnV2Dto that = (CreateDateTimeColumnV2Dto) o;
28 | return Objects.equals(datetimeDefault, that.datetimeDefault);
29 | }
30 |
31 | @Override
32 | public int hashCode() {
33 | return Objects.hash(super.hashCode(), datetimeDefault);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/remote/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nextcloud Tables is not installed
4 | Nextcloud Tables is not enabled
5 | Your Nextcloud instance is currently in maintenance mode
6 | Your server responded with an invalid response
7 | Your Nextcloud Tables app version is not supported
8 | Your Nextcloud version is not supported
9 | An unknown error occurred
10 | You are currently offline.
11 |
--------------------------------------------------------------------------------
/repository/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/repository/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/repository/consumer-rules.pro
--------------------------------------------------------------------------------
/repository/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.google.gson.** { *; }
2 |
3 | # Add project specific ProGuard rules here.
4 | # You can control the set of applied configuration files using the
5 | # proguardFiles setting in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # If your project uses WebView with JS, uncomment the following
11 | # and specify the fully qualified class name to the JavaScript interface
12 | # class:
13 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
14 | # public *;
15 | #}
16 |
17 | # Uncomment this to preserve the line number information for
18 | # debugging stack traces.
19 | #-keepattributes SourceFile,LineNumberTable
20 |
21 | # If you keep the line number information, uncomment this to
22 | # hide the original source file name.
23 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/repository/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/NoOpDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
6 | import it.niedermann.nextcloud.tables.database.model.FullData;
7 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
8 |
9 | public class NoOpDefaultSupplier extends DefaultValueSupplier {
10 |
11 | @Override
12 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
13 | // No op
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/datetime/DateDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.LocalDate;
6 | import java.util.Optional;
7 |
8 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
9 | import it.niedermann.nextcloud.tables.database.model.FullData;
10 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
11 |
12 | public class DateDefaultSupplier extends DefaultValueSupplier {
13 |
14 | private static final String DEFAULT_TODAY = "today";
15 |
16 | @Override
17 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
18 | final var value = fullData.getData().getValue().getDateValue();
19 |
20 | if (value == null) {
21 | final var defaultValue = fullColumn.getColumn().getDefaultValue().getStringValue();
22 | Optional.ofNullable(defaultValue)
23 | .filter(DEFAULT_TODAY::equals)
24 | .map(str -> LocalDate.now())
25 | .ifPresent(fullData.getData().getValue()::setDateValue);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/datetime/DateTimeDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.Instant;
6 | import java.util.Optional;
7 |
8 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
9 | import it.niedermann.nextcloud.tables.database.model.FullData;
10 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
11 |
12 | public class DateTimeDefaultSupplier extends DefaultValueSupplier {
13 |
14 | private static final String DEFAULT_NOW = "now";
15 |
16 | @Override
17 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
18 | final var value = fullData.getData().getValue().getInstantValue();
19 |
20 | if (value == null) {
21 | final var defaultValue = fullColumn.getColumn().getDefaultValue().getStringValue();
22 | Optional.ofNullable(defaultValue)
23 | .filter(DEFAULT_NOW::equals)
24 | .map(str -> Instant.now())
25 | .ifPresent(fullData.getData().getValue()::setInstantValue);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/datetime/TimeDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.datetime;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.time.LocalTime;
6 | import java.util.Optional;
7 |
8 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
9 | import it.niedermann.nextcloud.tables.database.model.FullData;
10 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
11 |
12 | public class TimeDefaultSupplier extends DefaultValueSupplier {
13 |
14 | private static final String DEFAULT_NOW = "now";
15 |
16 | @Override
17 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
18 | final var value = fullData.getData().getValue().getTimeValue();
19 |
20 | if (value == null) {
21 | final var defaultValue = fullColumn.getColumn().getDefaultValue().getStringValue();
22 | Optional.ofNullable(defaultValue)
23 | .filter(DEFAULT_NOW::equals)
24 | .map(str -> LocalTime.now())
25 | .ifPresent(fullData.getData().getValue()::setTimeValue);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/number/NumberDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.number;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
6 | import it.niedermann.nextcloud.tables.database.model.FullData;
7 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
8 |
9 | public class NumberDefaultSupplier extends DefaultValueSupplier {
10 |
11 | @Override
12 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
13 | final var value = fullData.getData().getValue().getDoubleValue();
14 |
15 | if (value == null) {
16 | final var defaultValue = fullColumn.getColumn().getDefaultValue().getDoubleValue();
17 | fullData.getData().getValue().setDoubleValue(defaultValue);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/number/NumberStarsDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.number;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Optional;
6 |
7 | import it.niedermann.nextcloud.tables.database.entity.Column;
8 | import it.niedermann.nextcloud.tables.database.entity.Data;
9 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
10 | import it.niedermann.nextcloud.tables.database.model.FullData;
11 | import it.niedermann.nextcloud.tables.database.model.Value;
12 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
13 |
14 | public class NumberStarsDefaultSupplier extends DefaultValueSupplier {
15 |
16 | @Override
17 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
18 | final var value = Optional
19 | .of(fullData.getData())
20 | .map(Data::getValue)
21 | .map(Value::getDoubleValue);
22 |
23 | if (value.isEmpty()) {
24 | Optional
25 | .of(fullColumn.getColumn())
26 | .map(Column::getDefaultValue)
27 | .map(Value::getDoubleValue)
28 | .map(Math::ceil)
29 | .ifPresent(fullData.getData().getValue()::setDoubleValue);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/selection/SelectionCheckDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.selection;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Optional;
6 |
7 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
8 | import it.niedermann.nextcloud.tables.database.model.FullData;
9 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
10 |
11 | public class SelectionCheckDefaultSupplier extends DefaultValueSupplier {
12 |
13 | @Override
14 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
15 | final var value = fullData.getData().getValue().getBooleanValue();
16 |
17 | if (value == null) {
18 | final var defaultValue = fullColumn.getColumn().getDefaultValue().getBooleanValue();
19 | Optional.ofNullable(defaultValue)
20 | .ifPresent(fullData.getData().getValue()::setBooleanValue);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/selection/SelectionDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.selection;
2 |
3 | import static java.util.function.Predicate.not;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import java.util.List;
8 | import java.util.Optional;
9 |
10 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
11 | import it.niedermann.nextcloud.tables.database.model.FullData;
12 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
13 |
14 | public class SelectionDefaultSupplier extends DefaultValueSupplier {
15 |
16 | @Override
17 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
18 | final var value = fullData.getSelectionOptions();
19 |
20 | if (value == null || value.isEmpty()) {
21 | final var defaultValue = fullColumn.getDefaultSelectionOptions();
22 | Optional.of(defaultValue)
23 | .filter(not(List::isEmpty))
24 | .flatMap(selectionOptions -> selectionOptions.stream().findAny())
25 | .map(List::of)
26 | .ifPresent(fullData::setSelectionOptions);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/selection/SelectionMultiDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.selection;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Optional;
6 |
7 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
8 | import it.niedermann.nextcloud.tables.database.model.FullData;
9 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
10 |
11 | public class SelectionMultiDefaultSupplier extends DefaultValueSupplier {
12 |
13 | @Override
14 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
15 | final var value = fullData.getSelectionOptions();
16 |
17 | if (value == null || value.isEmpty()) {
18 | final var defaultValue = fullColumn.getDefaultSelectionOptions();
19 | Optional.ofNullable(defaultValue)
20 | .ifPresent(fullData::setSelectionOptions);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/defaults/supplier/text/TextDefaultSupplier.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.defaults.supplier.text;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Optional;
6 |
7 | import it.niedermann.nextcloud.tables.database.entity.Column;
8 | import it.niedermann.nextcloud.tables.database.model.FullColumn;
9 | import it.niedermann.nextcloud.tables.database.model.FullData;
10 | import it.niedermann.nextcloud.tables.database.model.Value;
11 | import it.niedermann.nextcloud.tables.repository.defaults.DefaultValueSupplier;
12 |
13 | public class TextDefaultSupplier extends DefaultValueSupplier {
14 |
15 | @Override
16 | protected void applyDefaultValue(@NonNull FullColumn fullColumn, @NonNull FullData fullData) {
17 | final var value = fullData.getData().getValue();
18 | final var strValue = Optional.ofNullable(value.getStringValue());
19 |
20 | if (strValue.isEmpty()) {
21 | Optional.of(fullColumn.getColumn())
22 | .map(Column::getDefaultValue)
23 | .map(Value::getStringValue)
24 | .ifPresent(value::setStringValue);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/exception/AccountAlreadyImportedException.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.exception;
2 |
3 | import android.database.sqlite.SQLiteConstraintException;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | public class AccountAlreadyImportedException extends AccountNotCreatedException {
8 |
9 | public AccountAlreadyImportedException(@NonNull SQLiteConstraintException cause) {
10 | super(cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/exception/AccountNotCreatedException.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.exception;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | public class AccountNotCreatedException extends RuntimeException {
6 |
7 | public AccountNotCreatedException() {
8 | super();
9 | }
10 |
11 | public AccountNotCreatedException(@Nullable Throwable cause) {
12 | super(cause);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/exception/InsufficientPermissionException.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.exception;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.EPermissionV2Dto;
7 |
8 | public class InsufficientPermissionException extends Exception {
9 |
10 | private final EPermissionV2Dto missingPermission;
11 |
12 | public InsufficientPermissionException(@NonNull EPermissionV2Dto missingPermission) {
13 | this.missingPermission = missingPermission;
14 | }
15 |
16 | @NonNull
17 | public EPermissionV2Dto getMissingPermission() {
18 | return missingPermission;
19 | }
20 |
21 | @Nullable
22 | @Override
23 | public String getMessage() {
24 | return String.valueOf(missingPermission);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/SyncScheduler.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.annotation.AnyThread;
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import java.util.concurrent.CompletableFuture;
10 |
11 | import it.niedermann.nextcloud.tables.database.entity.Account;
12 | import it.niedermann.nextcloud.tables.repository.sync.report.SyncStatusReporter;
13 | import it.niedermann.nextcloud.tables.repository.sync.treesync.TreeSyncScheduler;
14 |
15 | public interface SyncScheduler {
16 |
17 | @AnyThread
18 | CompletableFuture scheduleSynchronization(@NonNull Account account,
19 | @NonNull Scope scope,
20 | @Nullable SyncStatusReporter reporter);
21 |
22 | class Factory {
23 |
24 | private final SyncScheduler defaultSyncScheduler;
25 |
26 | public Factory(@NonNull Context context) {
27 | defaultSyncScheduler = new TreeSyncScheduler(context.getApplicationContext());
28 | }
29 |
30 | @NonNull
31 | public SyncScheduler create() {
32 | return defaultSyncScheduler;
33 | }
34 | }
35 |
36 | enum Scope {
37 | PUSH_ONLY,
38 | PUSH_AND_PULL
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/RemoteMapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.Collection;
6 | import java.util.List;
7 | import java.util.Objects;
8 |
9 | public interface RemoteMapper {
10 |
11 | DtoType toDto(EntityType entity);
12 |
13 | EntityType toEntity(DtoType dto);
14 |
15 | @NonNull
16 | default List toDtoList(@NonNull Collection entities) {
17 | return entities
18 | .stream()
19 | .filter(Objects::nonNull)
20 | .map(this::toDto)
21 | .toList();
22 | }
23 |
24 | @NonNull
25 | default List toEntityList(@NonNull Collection dtos) {
26 | return dtos
27 | .stream()
28 | .filter(Objects::nonNull)
29 | .map(this::toEntity)
30 | .toList();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/ocs/OcsSearchProviderMapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.ocs;
2 |
3 | import org.mapstruct.Mapper;
4 | import org.mapstruct.Mapping;
5 | import org.mapstruct.factory.Mappers;
6 |
7 | import it.niedermann.nextcloud.tables.database.entity.SearchProvider;
8 | import it.niedermann.nextcloud.tables.remote.ocs.model.OcsSearchProvider;
9 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
10 |
11 | @Mapper
12 | public interface OcsSearchProviderMapper extends RemoteMapper {
13 |
14 | OcsSearchProviderMapper INSTANCE = Mappers.getMapper(OcsSearchProviderMapper.class);
15 |
16 | @Override
17 | OcsSearchProvider toDto(SearchProvider entity);
18 |
19 | @Mapping(target = "id", ignore = true)
20 | @Mapping(target = "accountId", ignore = true)
21 | @Override
22 | SearchProvider toEntity(OcsSearchProvider dto);
23 | }
24 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/ocs/OcsVersionMapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.ocs;
2 |
3 | import com.nextcloud.android.sso.model.ocs.OcsCapabilitiesResponse.OcsVersion;
4 |
5 | import org.mapstruct.InheritInverseConfiguration;
6 | import org.mapstruct.Mapper;
7 | import org.mapstruct.Mapping;
8 | import org.mapstruct.factory.Mappers;
9 |
10 | import it.niedermann.nextcloud.tables.database.model.Version;
11 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
12 |
13 | @Mapper
14 | public interface OcsVersionMapper extends RemoteMapper {
15 |
16 | OcsVersionMapper INSTANCE = Mappers.getMapper(OcsVersionMapper.class);
17 |
18 | @Mapping(source = "version", target = "string")
19 | @Mapping(source = "patch", target = "macro")
20 | @Mapping(target = "edition", ignore = true)
21 | @Mapping(target = "extendedSupport", ignore = true)
22 | OcsVersion toDto(Version entity);
23 |
24 | @InheritInverseConfiguration
25 | Version toEntity(OcsVersion dto);
26 | }
27 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/EUserGroupTypeV2Mapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import org.mapstruct.InheritInverseConfiguration;
4 | import org.mapstruct.Mapper;
5 | import org.mapstruct.MappingConstants;
6 | import org.mapstruct.ValueMapping;
7 | import org.mapstruct.factory.Mappers;
8 |
9 | import it.niedermann.nextcloud.tables.database.model.EUserGroupType;
10 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.EUserGroupTypeV2Dto;
11 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
12 |
13 | @Mapper
14 | public interface EUserGroupTypeV2Mapper extends RemoteMapper {
15 |
16 | EUserGroupTypeV2Mapper INSTANCE = Mappers.getMapper(EUserGroupTypeV2Mapper.class);
17 |
18 | @ValueMapping(source = "TEAM", target = "TEAMS")
19 | @ValueMapping(source = MappingConstants.ANY_REMAINING, target = MappingConstants.THROW_EXCEPTION)
20 | @ValueMapping(source = MappingConstants.NULL, target = MappingConstants.THROW_EXCEPTION)
21 | @Override
22 | EUserGroupTypeV2Dto toDto(EUserGroupType entity);
23 |
24 | @InheritInverseConfiguration
25 | @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "UNKNOWN")
26 | @ValueMapping(source = MappingConstants.NULL, target = "UNKNOWN")
27 | @Override
28 | EUserGroupType toEntity(EUserGroupTypeV2Dto dto);
29 | }
30 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/OnSharePermissionV2Mapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import org.mapstruct.Mapper;
4 | import org.mapstruct.NullValueMappingStrategy;
5 | import org.mapstruct.factory.Mappers;
6 |
7 | import it.niedermann.nextcloud.tables.database.entity.OnSharePermission;
8 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.OnSharePermissionV2Dto;
9 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
10 |
11 | @Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
12 | public interface OnSharePermissionV2Mapper extends RemoteMapper {
13 |
14 | OnSharePermissionV2Mapper INSTANCE = Mappers.getMapper(OnSharePermissionV2Mapper.class);
15 |
16 | @Override
17 | OnSharePermissionV2Dto toDto(OnSharePermission entity);
18 |
19 | @Override
20 | OnSharePermission toEntity(OnSharePermissionV2Dto dto);
21 | }
22 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/SelectionOptionV2Mapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import org.mapstruct.InheritInverseConfiguration;
4 | import org.mapstruct.Mapper;
5 | import org.mapstruct.Mapping;
6 | import org.mapstruct.factory.Mappers;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.SelectionOption;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.SelectionOptionV2Dto;
10 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
11 |
12 | @Mapper
13 | public interface SelectionOptionV2Mapper extends RemoteMapper {
14 |
15 | SelectionOptionV2Mapper INSTANCE = Mappers.getMapper(SelectionOptionV2Mapper.class);
16 |
17 | @Override
18 | SelectionOptionV2Dto toDto(SelectionOption entity);
19 |
20 | @Mapping(target = "id", ignore = true)
21 | @Mapping(target = "columnId", ignore = true)
22 | @InheritInverseConfiguration
23 | SelectionOption toEntity(SelectionOptionV2Dto dto);
24 | }
25 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/TableV2Mapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import org.mapstruct.InheritInverseConfiguration;
4 | import org.mapstruct.Mapper;
5 | import org.mapstruct.Mapping;
6 | import org.mapstruct.factory.Mappers;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.Table;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.TableV2Dto;
10 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
11 |
12 | @Mapper(uses = OnSharePermissionV2Mapper.class)
13 | public interface TableV2Mapper extends RemoteMapper {
14 |
15 | TableV2Mapper INSTANCE = Mappers.getMapper(TableV2Mapper.class);
16 |
17 | @Mapping(source = "shared", target = "isShared")
18 | @Mapping(source = "onSharePermission", target = "onSharePermissions")
19 | @Override
20 | TableV2Dto toDto(Table entity);
21 |
22 | @Mapping(target = "id", ignore = true)
23 | @Mapping(target = "accountId", ignore = true)
24 | @Mapping(target = "status", ignore = true)
25 | @Mapping(target = "ETag", ignore = true)
26 | @Mapping(target = "synchronizationContext", ignore = true)
27 | @Mapping(target = "currentRow", ignore = true)
28 | @InheritInverseConfiguration
29 | @Override
30 | Table toEntity(TableV2Dto dto);
31 | }
32 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/UserGroupV2Mapper.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import org.mapstruct.InheritInverseConfiguration;
4 | import org.mapstruct.Mapper;
5 | import org.mapstruct.Mapping;
6 | import org.mapstruct.factory.Mappers;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.UserGroup;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.UserGroupV2Dto;
10 | import it.niedermann.nextcloud.tables.repository.sync.mapper.RemoteMapper;
11 |
12 | @Mapper(uses = EUserGroupTypeV2Mapper.class)
13 | public interface UserGroupV2Mapper extends RemoteMapper {
14 |
15 | UserGroupV2Mapper INSTANCE = Mappers.getMapper(UserGroupV2Mapper.class);
16 |
17 | @Mapping(source = "displayName", target = "key")
18 | @Override
19 | UserGroupV2Dto toDto(UserGroup entity);
20 |
21 | @Mapping(target = "id", ignore = true)
22 | @Mapping(target = "accountId", ignore = true)
23 | @InheritInverseConfiguration
24 | @Override
25 | UserGroup toEntity(UserGroupV2Dto dto);
26 | }
27 |
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/report/LiveDataReporter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.report;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.lifecycle.LiveData;
5 |
6 | import it.niedermann.nextcloud.tables.database.entity.Account;
7 |
8 | public class LiveDataReporter extends LiveData implements SyncStatusReporter {
9 |
10 | /// Given [#setValue] can only happen on the main thread and [#postValue] can omit intermediate status,
11 | /// we will ensure that we always rely on the latest [SyncStatus] before applying the [Reducer] logic
12 | /// by storing a duplicate of the [SyncStatus] locally to apply the [Reducer] logic on, but not emitting all intermediates.
13 | private SyncStatus currentSyncStatus;
14 |
15 | public LiveDataReporter(@NonNull Account account) {
16 | super(new SyncStatus(account));
17 | this.currentSyncStatus = getValue();
18 | }
19 |
20 | @Override
21 | public boolean report(@NonNull Reducer reducer) {
22 | synchronized (this) {
23 | if (currentSyncStatus.isFinished()) {
24 | return false;
25 | }
26 |
27 | currentSyncStatus = reducer.apply(currentSyncStatus);
28 | postValue(currentSyncStatus);
29 | }
30 |
31 | return true;
32 | }
33 | }
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/report/SyncStatusReporter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.report;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.function.Function;
6 |
7 | @FunctionalInterface
8 | public interface SyncStatusReporter {
9 | /// @return whether or not the report got reduced
10 | boolean report(@NonNull Reducer reducer);
11 |
12 | @FunctionalInterface
13 | interface Reducer extends Function {
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/repository/src/main/java/it/niedermann/nextcloud/tables/repository/sync/treesync/SyncAdapter.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.treesync;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.util.concurrent.CompletableFuture;
6 |
7 | import it.niedermann.nextcloud.tables.database.entity.AbstractEntity;
8 | import it.niedermann.nextcloud.tables.database.entity.Account;
9 |
10 | interface SyncAdapter {
11 |
12 | @NonNull
13 | CompletableFuture pushLocalCreations(@NonNull Account account, @NonNull TParentEntity parentEntity);
14 |
15 | @NonNull
16 | CompletableFuture pushLocalUpdates(@NonNull Account account, @NonNull TParentEntity parentEntity);
17 |
18 | @NonNull
19 | CompletableFuture pushLocalDeletions(@NonNull Account account, @NonNull TParentEntity parentEntity);
20 |
21 | @NonNull
22 | CompletableFuture pushChildChangesWithoutChangedParent(@NonNull Account account);
23 |
24 | @NonNull
25 | CompletableFuture pullRemoteChanges(@NonNull Account account, @NonNull TParentEntity parentEntity);
26 | }
27 |
--------------------------------------------------------------------------------
/repository/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sync only on Wi-Fi
4 | Background synchronization
5 | Theme
6 |
7 | sync_on_wifi_only
8 | background_sync
9 | background_sync_last
10 | theme
11 |
12 |
13 | - -1
14 | - 1
15 | - 2
16 |
17 |
18 |
19 | - System Default
20 | - Light
21 | - Dark
22 |
23 |
--------------------------------------------------------------------------------
/repository/src/test/java/it/niedermann/nextcloud/tables/repository/sync/mapper/tablesV2/SelectionOptionV2MapperTest.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.repository.sync.mapper.tablesV2;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import it.niedermann.nextcloud.tables.database.entity.SelectionOption;
9 | import it.niedermann.nextcloud.tables.remote.tablesV2.model.SelectionOptionV2Dto;
10 |
11 | public class SelectionOptionV2MapperTest {
12 |
13 | private SelectionOptionV2Mapper mapper;
14 |
15 | @Before
16 | public void setup() {
17 | this.mapper = SelectionOptionV2Mapper.INSTANCE;
18 | }
19 |
20 | @Test
21 | public void toDto() {
22 |
23 | final var entity = new SelectionOption();
24 | entity.setRemoteId(4711L);
25 | entity.setLabel("foo");
26 |
27 | final var dto = mapper.toDto(entity);
28 |
29 | assertEquals(Long.valueOf(4711L), dto.remoteId());
30 | assertEquals("foo", dto.label());
31 | }
32 |
33 | @Test
34 | public void toEntity() {
35 |
36 | final var dto = new SelectionOptionV2Dto(4711L, "foo");
37 |
38 | final var entity = mapper.toEntity(dto);
39 |
40 | assertEquals(Long.valueOf(4711L), entity.getRemoteId());
41 | assertEquals("foo", entity.getLabel());
42 | }
43 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url "https://jitpack.io" }
14 | }
15 | }
16 | rootProject.name = "Nextcloud Tables"
17 | include ':app'
18 | include ':ui'
19 | include ':repository'
20 | include ':remote'
21 | include ':database'
22 | include ':shared'
23 |
--------------------------------------------------------------------------------
/shared/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/shared/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | namespace 'it.niedermann.nextcloud.tables.shared'
7 | compileSdk 35
8 |
9 | defaultConfig {
10 | minSdk 24
11 |
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | coreLibraryDesugaringEnabled true
24 | sourceCompatibility JavaVersion.VERSION_17
25 | targetCompatibility JavaVersion.VERSION_17
26 | }
27 | buildFeatures {
28 | buildConfig true
29 | }
30 | }
31 |
32 | dependencies {
33 | coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$version_desugar"
34 |
35 | implementation 'androidx.appcompat:appcompat:1.7.0'
36 |
37 | testImplementation 'junit:junit:4.13.2'
38 | androidTestImplementation 'androidx.test.ext:junit:1.2.1'
39 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
40 | }
--------------------------------------------------------------------------------
/shared/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
--------------------------------------------------------------------------------
/shared/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/shared/src/main/java/it/niedermann/nextcloud/tables/shared/Constants.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.shared;
2 |
3 | public class Constants {
4 |
5 | public static final int PROBABLE_ACCOUNT_COUNT = 1;
6 | }
7 |
--------------------------------------------------------------------------------
/shared/src/main/java/it/niedermann/nextcloud/tables/shared/FeatureToggle.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.shared;
2 |
3 | public enum FeatureToggle {
4 |
5 | /// Some exceptions only affect a part of the app. Enabling [#STRICT_MODE] will always
6 | /// throw all exceptions to make the user aware of the fact that something went wrong.
7 | /// Disabling this [FeatureToggle] can lead to wrongly displayed data.
8 | STRICT_MODE(BuildConfig.DEBUG),
9 | EDIT_COLUMN(true),
10 | EDIT_USER_GROUPS(BuildConfig.DEBUG),
11 | CREATE_COLUMN(true),
12 | DELETE_COLUMN(true),
13 | SHARE_TABLE(BuildConfig.DEBUG),
14 | SEARCH_IN_TABLE(false),
15 | ;
16 |
17 | public final boolean enabled;
18 |
19 | FeatureToggle(boolean enabled) {
20 | this.enabled = enabled;
21 | }
22 | }
--------------------------------------------------------------------------------
/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/ui/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefan-niedermann/nextcloud-tables/2a0816eb4fa810ec1a8f715ca3480e639adac954/ui/consumer-rules.pro
--------------------------------------------------------------------------------
/ui/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
--------------------------------------------------------------------------------
/ui/src/androidTest/java/it/niedermann/nextcloud/tables/ui/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.ui;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import android.content.Context;
6 |
7 | import androidx.test.ext.junit.runners.AndroidJUnit4;
8 | import androidx.test.platform.app.InstrumentationRegistry;
9 |
10 | import org.junit.Test;
11 | import org.junit.runner.RunWith;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("it.niedermann.nextcloud.tables.ui.test", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/baseline_clear_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/baseline_restart_alt_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/baseline_star_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/baseline_star_border_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/selectable_star.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/view_emojipicker.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/view_stars.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
21 |
22 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/view_stars_single.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4dp
4 | 8dp
5 | 16dp
6 | 20dp
7 | 24dp
8 | 32dp
9 | 40dp
10 | 48dp
11 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Clear stars
4 | Star %1$d of %2$d
5 |
--------------------------------------------------------------------------------
/ui/src/test/java/it/niedermann/nextcloud/tables/ui/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package it.niedermann.nextcloud.tables.ui;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------