├── .gitignore ├── Flym.iml ├── LICENSE ├── LICENSE_GPLv3 ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro ├── schemas │ └── org.decsync.flym.data.AppDatabase │ │ ├── 1.json │ │ ├── 2.json │ │ ├── 3.json │ │ └── 4.json └── src │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── org │ │ │ └── decsync │ │ │ └── flym │ │ │ ├── App.kt │ │ │ ├── MyAppGlideModule.kt │ │ │ ├── data │ │ │ ├── AppDatabase.kt │ │ │ ├── converters │ │ │ │ └── Converters.kt │ │ │ ├── dao │ │ │ │ ├── EntryDao.kt │ │ │ │ ├── FeedDao.kt │ │ │ │ └── TaskDao.kt │ │ │ ├── entities │ │ │ │ ├── DecsyncArticle.kt │ │ │ │ ├── DecsyncFeed.kt │ │ │ │ ├── Entry.kt │ │ │ │ ├── EntryWithFeed.kt │ │ │ │ ├── Feed.kt │ │ │ │ ├── FeedWithCount.kt │ │ │ │ ├── SearchFeedResult.kt │ │ │ │ └── Task.kt │ │ │ └── utils │ │ │ │ └── PrefConstants.kt │ │ │ ├── service │ │ │ ├── AutoRefreshJobService.kt │ │ │ └── FetcherService.kt │ │ │ ├── ui │ │ │ ├── about │ │ │ │ └── AboutActivity.kt │ │ │ ├── discover │ │ │ │ ├── DiscoverActivity.kt │ │ │ │ ├── DiscoverFragment.kt │ │ │ │ ├── FeedManagementInterface.kt │ │ │ │ ├── FeedSearchFragment.kt │ │ │ │ └── SquareGridItemLayout.kt │ │ │ ├── entries │ │ │ │ ├── EntriesFragment.kt │ │ │ │ └── EntryAdapter.kt │ │ │ ├── entrydetails │ │ │ │ ├── EntryDetailsActivity.kt │ │ │ │ ├── EntryDetailsFragment.kt │ │ │ │ └── EntryDetailsView.kt │ │ │ ├── feeds │ │ │ │ ├── BaseFeedAdapter.kt │ │ │ │ ├── DrawerFeedAdapter.kt │ │ │ │ ├── EditFeedAdapter.kt │ │ │ │ ├── FeedGroup.kt │ │ │ │ ├── FeedListEditActivity.kt │ │ │ │ └── FeedListEditFragment.kt │ │ │ ├── intro │ │ │ │ ├── IntroActivity.kt │ │ │ │ └── SafUpdateActivity.kt │ │ │ ├── main │ │ │ │ ├── ContainersLayout.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainNavigator.kt │ │ │ ├── settings │ │ │ │ ├── SettingsActivity.kt │ │ │ │ └── SettingsFragment.kt │ │ │ └── views │ │ │ │ ├── AutoSummaryListPreference.kt │ │ │ │ ├── BakedBezierInterpolator.java │ │ │ │ ├── DragNDropListener.kt │ │ │ │ ├── DragNDropRecyclerView.kt │ │ │ │ ├── EmptyRecyclerView.kt │ │ │ │ ├── SwipeProgressBar.java │ │ │ │ └── SwipeRefreshLayout.java │ │ │ └── utils │ │ │ ├── ActivityExtensions.kt │ │ │ ├── ContextExtensions.kt │ │ │ ├── DecsyncListeners.kt │ │ │ ├── DecsyncUtils.kt │ │ │ ├── HtmlUtils.kt │ │ │ ├── StringExtensions.kt │ │ │ └── ViewExtensions.kt │ └── res │ │ ├── anim │ │ ├── grid_layout_animation_from_bottom.xml │ │ └── item_animation_from_bottom.xml │ │ ├── animator │ │ └── appbar_always_elevated.xml │ │ ├── color │ │ ├── bottom_navigation_item.xml │ │ ├── colored_read_state.xml │ │ ├── colored_read_state_black.xml │ │ ├── colored_read_state_light.xml │ │ ├── read_state.xml │ │ ├── read_state_black.xml │ │ └── read_state_light.xml │ │ ├── drawable-nodpi │ │ └── header_background.png │ │ ├── drawable-w840dp │ │ └── selected_item_background.xml │ │ ├── drawable-xhdpi │ │ ├── folder.xml │ │ └── ic_statusbar_rss.png │ │ ├── drawable │ │ ├── ic_add_white_24dp.xml │ │ ├── ic_all_green_108dp.xml │ │ ├── ic_all_white_24dp.xml │ │ ├── ic_back_white_24dp.xml │ │ ├── ic_baseline_add_24.xml │ │ ├── ic_baseline_check_24.xml │ │ ├── ic_create_new_folder_white_24dp.xml │ │ ├── ic_drag_handle_white_24dp.xml │ │ ├── ic_empty_gray_100dp.xml │ │ ├── ic_fulltext_white_24dp.xml │ │ ├── ic_keyboard_arrow_down_black_24dp.xml │ │ ├── ic_keyboard_arrow_down_white_24dp.xml │ │ ├── ic_keyboard_arrow_up_black_24dp.xml │ │ ├── ic_keyboard_arrow_up_white_24dp.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_list_black_24dp.xml │ │ ├── ic_list_white_24dp.xml │ │ ├── ic_menu_24dp.xml │ │ ├── ic_menu_red_highlight_24dp.xml │ │ ├── ic_more_vert_white_24dp.xml │ │ ├── ic_navigate_before_black_24dp.xml │ │ ├── ic_navigate_before_white_24dp.xml │ │ ├── ic_navigate_next_black_24dp.xml │ │ ├── ic_navigate_next_white_24dp.xml │ │ ├── ic_open_in_browser_white_24dp.xml │ │ ├── ic_original_text_white_24dp.xml │ │ ├── ic_read_all_white_24dp.xml │ │ ├── ic_search_white_24dp.xml │ │ ├── ic_share_white_24dp.xml │ │ ├── ic_star_24dp.xml │ │ ├── ic_star_border_24dp.xml │ │ ├── ic_star_border_white_24dp.xml │ │ ├── ic_star_green_108dp.xml │ │ ├── ic_star_white_24dp.xml │ │ ├── ic_unread_green_108dp.xml │ │ ├── ic_unread_white_24dp.xml │ │ ├── selected_feed_background.xml │ │ └── selected_item_background.xml │ │ ├── layout-w840dp │ │ └── view_main_containers.xml │ │ ├── layout │ │ ├── activity_feed_list_edit.xml │ │ ├── activity_feed_search.xml │ │ ├── activity_intro_directory.xml │ │ ├── activity_intro_welcome.xml │ │ ├── activity_main.xml │ │ ├── activity_saf_update.xml │ │ ├── activity_settings.xml │ │ ├── dialog_edit_feed.xml │ │ ├── fragment_discover.xml │ │ ├── fragment_entries.xml │ │ ├── fragment_entry_details.xml │ │ ├── fragment_entry_details_noswipe.xml │ │ ├── fragment_feed_list_edit.xml │ │ ├── fragment_feed_search.xml │ │ ├── item_discover_topic.xml │ │ ├── item_feed_search_result.xml │ │ ├── view_entry.xml │ │ ├── view_feed.xml │ │ ├── view_feed_edit.xml │ │ ├── view_main_containers.xml │ │ └── view_main_drawer_header.xml │ │ ├── menu │ │ ├── menu_bottom_navigation_items.xml │ │ ├── menu_drawer_feed.xml │ │ ├── menu_drawer_header.xml │ │ ├── menu_fragment_entries.xml │ │ ├── menu_fragment_entry_details.xml │ │ └── menu_fragment_feed_list_edit.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_all.xml │ │ ├── ic_favorites.xml │ │ ├── ic_launcher.xml │ │ ├── ic_launcher_round.xml │ │ └── ic_unreads.xml │ │ ├── mipmap-hdpi │ │ ├── ic_all.png │ │ ├── ic_favorites.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_unreads.png │ │ ├── mipmap-mdpi │ │ ├── ic_all.png │ │ ├── ic_favorites.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_unreads.png │ │ ├── mipmap-xhdpi │ │ ├── ic_all.png │ │ ├── ic_favorites.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_unreads.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_all.png │ │ ├── ic_favorites.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_unreads.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_all.png │ │ ├── ic_favorites.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_unreads.png │ │ ├── values-af │ │ └── strings.xml │ │ ├── values-ar │ │ └── strings.xml │ │ ├── values-b+pt+BR │ │ └── strings.xml │ │ ├── values-b+sr+Latn │ │ └── strings.xml │ │ ├── values-b+zh+TW │ │ └── strings.xml │ │ ├── values-bn │ │ └── strings.xml │ │ ├── values-ca │ │ └── strings.xml │ │ ├── values-cs │ │ └── strings.xml │ │ ├── values-da │ │ └── strings.xml │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-el │ │ └── strings.xml │ │ ├── values-es │ │ └── strings.xml │ │ ├── values-eu │ │ └── strings.xml │ │ ├── values-fi │ │ └── strings.xml │ │ ├── values-fr │ │ └── strings.xml │ │ ├── values-he │ │ └── strings.xml │ │ ├── values-hu │ │ └── strings.xml │ │ ├── values-in │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-ja │ │ └── strings.xml │ │ ├── values-ko │ │ └── strings.xml │ │ ├── values-nl │ │ └── strings.xml │ │ ├── values-no │ │ └── strings.xml │ │ ├── values-pl │ │ └── strings.xml │ │ ├── values-pt │ │ └── strings.xml │ │ ├── values-ro │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-sk │ │ └── strings.xml │ │ ├── values-sr │ │ └── strings.xml │ │ ├── values-sv │ │ └── strings.xml │ │ ├── values-tr │ │ └── strings.xml │ │ ├── values-uk │ │ └── strings.xml │ │ ├── values-vi │ │ └── strings.xml │ │ ├── values-w376dp │ │ └── dimens.xml │ │ ├── values-w600dp │ │ └── integers.xml │ │ ├── values-w840dp │ │ ├── dimens.xml │ │ └── styles.xml │ │ ├── values-zh │ │ └── strings.xml │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── integers.xml │ │ ├── not_translatable_strings.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ ├── xml-v25 │ │ └── shortcuts.xml │ │ └── xml │ │ ├── file_paths.xml │ │ ├── network_security_config.xml │ │ ├── settings.xml │ │ └── shortcuts.xml │ └── test │ └── java │ └── org │ └── decsync │ └── flym │ └── data │ └── entities │ └── FeedTest.kt ├── build.gradle ├── crowdin.yml ├── fastlane └── metadata │ └── android │ └── en-US │ ├── changelogs │ ├── 41.txt │ ├── 43.txt │ ├── 44.txt │ ├── 45.txt │ └── 46.txt │ ├── full_description.txt │ ├── images │ ├── featureGraphic.jpg │ ├── icon.png │ ├── phoneScreenshots │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ └── 4.png │ └── sevenInchScreenshots │ │ └── 1.png │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── graphics ├── flame.svg ├── logo.svg ├── status_icon.svg └── white_flame.png ├── lint.xml ├── settings.gradle └── tools └── flym_v1_to_v2.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # OS junk files 2 | [Tt]humbs.db 3 | *.DS_Store 4 | 5 | # Built application files 6 | *.apk 7 | *.ap_ 8 | 9 | # Files for the dex VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | proguard/ 19 | 20 | # Local configuration file (sdk path, keystore, etc) 21 | local.properties 22 | 23 | # IDE project files 24 | .idea/ 25 | .gradle/ 26 | .settings/ 27 | .metadata 28 | .externalNativeBuild 29 | build 30 | captures 31 | *.log 32 | *.iml 33 | 34 | # Junk generated by editors 35 | *~ 36 | *.swp 37 | *.bak 38 | -------------------------------------------------------------------------------- /Flym.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Flym 2 | 3 | Copyright (c) 2012-2015 Frederic Julian 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | 18 | 19 | Some parts of this software are based on "Sparse rss" under the MIT license (see 20 | below). Please refers to the original project to identify which parts are under the 21 | MIT license. 22 | 23 | Copyright (c) 2010-2012 Stefan Handschuh 24 | 25 | Permission is hereby granted, free of charge, to any person obtaining a copy 26 | of this software and associated documentation files (the "Software"), to deal 27 | in the Software without restriction, including without limitation the rights 28 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 29 | copies of the Software, and to permit persons to whom the Software is 30 | furnished to do so, subject to the following conditions: 31 | 32 | The above copyright notice and this permission notice shall be included in 33 | all copies or substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 38 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 39 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 40 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 41 | THE SOFTWARE. 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Flym DecSync 2 | ============ 3 | 4 | [Get it on F-Droid](https://f-droid.org/app/org.decsync.flym) 7 | 8 | Flym DecSync is a fork of [Flym](https://github.com/FredJul/Flym) which adds synchronization using [DecSync](https://github.com/39aldo39/DecSync). To start synchronizing, all you have to do is synchronize your selected DecSync directory, using for example [Syncthing](https://syncthing.net). 9 | 10 | Donations 11 | --------- 12 | 13 | ### PayPal 14 | [![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4V96AFD3S4TPJ) 15 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | androidExtensions { 7 | experimental = true 8 | } 9 | 10 | android { 11 | compileSdkVersion 31 12 | defaultConfig { 13 | applicationId "org.decsync.flym" 14 | minSdkVersion 21 15 | targetSdkVersion 31 16 | versionCode 46 17 | versionName "2.7.2" 18 | } 19 | 20 | compileOptions { 21 | sourceCompatibility JavaVersion.VERSION_1_8 22 | targetCompatibility JavaVersion.VERSION_1_8 23 | 24 | kotlinOptions { 25 | jvmTarget = "1.8" 26 | } 27 | } 28 | 29 | lintOptions { 30 | // if true, stop the gradle build if errors are found 31 | abortOnError true 32 | } 33 | 34 | File localProps = project.rootProject.file('local.properties') 35 | Properties properties = new Properties() 36 | if (localProps.exists()) { 37 | properties.load(localProps.newDataInputStream()) 38 | } 39 | 40 | signingConfigs { 41 | debug { 42 | if (properties.getProperty("KEYSTORE_PATH") != null) { 43 | storeFile file(properties.getProperty("KEYSTORE_PATH")) 44 | storePassword properties.getProperty("KEYSTORE_PASSWORD") 45 | keyAlias properties.getProperty("KEY_ALIAS") 46 | keyPassword properties.getProperty("KEY_PASSWORD") 47 | } 48 | } 49 | release { 50 | if (properties.getProperty("KEYSTORE_PATH") != null) { 51 | storeFile file(properties.getProperty("KEYSTORE_PATH")) 52 | storePassword properties.getProperty("KEYSTORE_PASSWORD") 53 | keyAlias properties.getProperty("KEY_ALIAS") 54 | keyPassword properties.getProperty("KEY_PASSWORD") 55 | } 56 | } 57 | } 58 | 59 | buildTypes { 60 | release { 61 | minifyEnabled true 62 | shrinkResources true 63 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 64 | if (properties.getProperty("KEYSTORE_PATH") != null) { 65 | signingConfig signingConfigs.release 66 | } 67 | } 68 | } 69 | 70 | sourceSets { 71 | main.java.srcDirs += 'src/main/kotlin' 72 | } 73 | } 74 | 75 | kapt { 76 | arguments { 77 | arg("room.schemaLocation", "$projectDir/schemas") 78 | } 79 | } 80 | 81 | dependencies { 82 | implementation fileTree(dir: 'libs', include: ['*.jar']) 83 | 84 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 85 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 86 | 87 | def lifecycle_version = "2.2.0" 88 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" 89 | 90 | def room_version = "2.4.0" 91 | implementation "androidx.room:room-runtime:$room_version" 92 | kapt "androidx.room:room-compiler:$room_version" 93 | 94 | implementation 'androidx.appcompat:appcompat:1.4.0' 95 | implementation 'com.google.android.material:material:1.4.0' 96 | implementation 'androidx.cardview:cardview:1.0.0' 97 | implementation 'androidx.recyclerview:recyclerview:1.2.1' 98 | def anko_version = '0.10.8' 99 | implementation "org.jetbrains.anko:anko-sdk21:$anko_version" 100 | implementation "org.jetbrains.anko:anko-sdk21-listeners:$anko_version" 101 | implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version" 102 | implementation "org.jetbrains.anko:anko-design:$anko_version" 103 | 104 | def okhttp_version = '4.9.0' 105 | implementation "com.squareup.okhttp3:okhttp:$okhttp_version" 106 | implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttp_version" 107 | 108 | def glide_version = '4.11.0' 109 | implementation "com.github.bumptech.glide:glide:$glide_version" 110 | kapt "com.github.bumptech.glide:compiler:$glide_version" 111 | 112 | implementation 'androidx.core:core-ktx:1.7.0' 113 | implementation 'androidx.paging:paging-runtime-ktx:3.1.0' 114 | implementation 'androidx.constraintlayout:constraintlayout:2.1.2' 115 | implementation 'androidx.preference:preference-ktx:1.1.1' 116 | implementation 'org.jsoup:jsoup:1.13.1' 117 | implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' 118 | implementation 'com.github.Tunous:SwipeActionView:1.3.1' 119 | implementation 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1' 120 | implementation 'com.github.jrvansuita:MaterialAbout:0.2.3' 121 | implementation 'q.rorbin:badgeview:1.1.3' 122 | implementation 'net.dankito.readability4j:readability4j:1.0.5' 123 | implementation 'pub.devrel:easypermissions:3.0.0' 124 | implementation 'com.rometools:rome-opml:1.15.0' 125 | implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1' 126 | implementation 'org.decsync:libdecsync:2.2.1' 127 | implementation 'com.nononsenseapps:filepicker:4.2.1' 128 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' 129 | implementation 'com.github.AppIntro:AppIntro:6.1.0' 130 | 131 | testImplementation 'junit:junit:4.13.2' 132 | } 133 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/fred/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | 11 | # for OOS, no need to remove all info 12 | -renamesourcefileattribute SourceFile 13 | -keepattributes SourceFile,LineNumberTable 14 | -keepnames class * 15 | -keepclasseswithmembernames class * { *; } 16 | 17 | # for the search 18 | -keep class android.support.v7.widget.SearchView { *; } 19 | 20 | # for anko 21 | -dontwarn org.jetbrains.anko.internals.AnkoInternals 22 | 23 | # for glide 24 | -keep public class * implements com.bumptech.glide.module.GlideModule 25 | -keep public class * extends com.bumptech.glide.AppGlideModule 26 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { 27 | **[] $VALUES; 28 | public *; 29 | } 30 | 31 | # OkHttp 32 | -keepattributes Signature 33 | -keepattributes *Annotation* 34 | -keep class okhttp3.** { *; } 35 | -keep interface okhttp3.** { *; } 36 | -dontwarn okhttp3.** 37 | -dontwarn okio.** 38 | 39 | # Rome lib 40 | -keep class com.rometools.** { *; } 41 | -dontwarn java.beans.** 42 | -dontwarn javax.** 43 | -dontwarn org.jaxen.** 44 | -dontwarn org.slf4j.** 45 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/39aldo39/Flym-DecSync/87194f32c675c5c395030feaa93aa12ef88f7b90/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/MyAppGlideModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym 19 | 20 | import android.content.Context 21 | import com.bumptech.glide.GlideBuilder 22 | import com.bumptech.glide.annotation.GlideModule 23 | import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory 24 | import com.bumptech.glide.module.AppGlideModule 25 | 26 | @GlideModule 27 | class MyAppGlideModule : AppGlideModule() { 28 | override fun applyOptions(context: Context, builder: GlideBuilder) { 29 | val diskCacheSizeBytes = 1024 * 1024 * 50 // 50 MB 30 | builder.setDiskCache(InternalCacheDiskCacheFactory(context, diskCacheSizeBytes.toLong())) 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/converters/Converters.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.converters 19 | 20 | import androidx.room.TypeConverter 21 | import java.util.Date 22 | 23 | class Converters { 24 | @TypeConverter 25 | fun fromTimestamp(value: Long?): Date? { 26 | return if (value == null) null else Date(value) 27 | } 28 | 29 | @TypeConverter 30 | fun dateToTimestamp(date: Date?): Long? { 31 | return date?.time 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/dao/FeedDao.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.dao 19 | 20 | import androidx.lifecycle.LiveData 21 | import androidx.room.Dao 22 | import androidx.room.Delete 23 | import androidx.room.Insert 24 | import androidx.room.OnConflictStrategy 25 | import androidx.room.Query 26 | import androidx.room.Update 27 | import org.decsync.flym.data.entities.DecsyncCategory 28 | import org.decsync.flym.data.entities.DecsyncFeed 29 | import org.decsync.flym.data.entities.Feed 30 | import org.decsync.flym.data.entities.FeedWithCount 31 | 32 | private const val DECSYNC_FEED_SELECT = "feedLink, feedTitle, groupId" 33 | private const val DECSYNC_FEED_WHERE = "isGroup = 0 AND feedLink != ''" 34 | private const val DECSYNC_CATEGORY_SELECT = "feedLink, feedTitle" 35 | private const val DECSYNC_CATEGORY_WHERE = "isGroup = 1 AND feedLink != '' AND feedTitle NOT NULL" 36 | private const val ENTRY_COUNT = "(SELECT COUNT(*) FROM entries WHERE feedId IS f.feedId AND read = 0)" 37 | 38 | @Dao 39 | abstract class FeedDao { 40 | 41 | @ExperimentalStdlibApi 42 | @get:Query("SELECT $DECSYNC_FEED_SELECT FROM feeds WHERE $DECSYNC_FEED_WHERE") 43 | abstract val observeAllDecsyncFeeds: LiveData> 44 | 45 | @ExperimentalStdlibApi 46 | @get:Query("SELECT $DECSYNC_CATEGORY_SELECT FROM feeds WHERE $DECSYNC_CATEGORY_WHERE") 47 | abstract val observeAllDecsyncCategories: LiveData> 48 | 49 | @get:Query("SELECT * FROM feeds WHERE isGroup = 0") 50 | abstract val allNonGroupFeeds: List 51 | 52 | @Query("SELECT * FROM feeds WHERE isGroup = 0 and groupId = :groupId") 53 | abstract fun allFeedsInGroup(groupId: Long): List 54 | 55 | @get:Query("SELECT * FROM feeds ORDER BY groupId DESC, displayPriority ASC, feedId ASC") 56 | abstract val all: List 57 | 58 | @get:Query("SELECT * FROM feeds ORDER BY groupId DESC, displayPriority ASC, feedId ASC") 59 | abstract val observeAll: LiveData> 60 | 61 | @get:Query("SELECT *, $ENTRY_COUNT AS entryCount FROM feeds AS f ORDER BY groupId DESC, displayPriority ASC, feedId ASC") 62 | abstract val observeAllWithCount: LiveData> 63 | 64 | @Query("SELECT * FROM feeds WHERE feedId IS :id LIMIT 1") 65 | abstract fun findById(id: Long): Feed? 66 | 67 | @Query("SELECT * FROM feeds WHERE feedLink IS :link") 68 | abstract fun findByLink(link: String): Feed? 69 | 70 | @Query("DELETE FROM feeds WHERE feedLink IS :link") 71 | abstract fun deleteByLink(link: String) 72 | 73 | @Query("UPDATE feeds SET retrieveFullText = 1 WHERE feedId = :feedId") 74 | abstract fun enableFullTextRetrieval(feedId: Long) 75 | 76 | @Query("UPDATE feeds SET retrieveFullText = 0 WHERE feedId = :feedId") 77 | abstract fun disableFullTextRetrieval(feedId: Long) 78 | 79 | @Query("UPDATE feeds SET fetchError = 1 WHERE feedId = :feedId") 80 | abstract fun setFetchError(feedId: Long) 81 | 82 | @Insert(onConflict = OnConflictStrategy.REPLACE) 83 | abstract fun insert(vararg feeds: Feed): List 84 | 85 | @Update 86 | abstract fun update(vararg feeds: Feed) 87 | 88 | @Delete 89 | abstract fun delete(vararg feeds: Feed) 90 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/dao/TaskDao.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.dao 19 | 20 | import androidx.lifecycle.LiveData 21 | import androidx.room.Dao 22 | import androidx.room.Delete 23 | import androidx.room.Insert 24 | import androidx.room.OnConflictStrategy 25 | import androidx.room.Query 26 | import androidx.room.Transaction 27 | import androidx.room.Update 28 | import org.decsync.flym.data.entities.Task 29 | 30 | 31 | @Dao 32 | abstract class TaskDao { 33 | @get:Query("SELECT * FROM tasks") 34 | abstract val all: List 35 | 36 | @get:Query("SELECT * FROM tasks") 37 | abstract val observeAll: LiveData> 38 | 39 | @get:Query("SELECT * FROM tasks WHERE imageLinkToDl = ''") 40 | abstract val mobilizeTasks: List 41 | 42 | @Query("SELECT COUNT(*) FROM tasks WHERE imageLinkToDl = '' AND entryId = :itemId") 43 | abstract fun observeItemMobilizationTasksCount(itemId: String): LiveData 44 | 45 | @get:Query("SELECT * FROM tasks WHERE imageLinkToDl != ''") 46 | abstract val downloadTasks: List 47 | 48 | @Insert(onConflict = OnConflictStrategy.REPLACE) 49 | protected abstract fun insertInternal(task: Task) 50 | 51 | @Transaction 52 | open fun insert(vararg tasks: Task) { 53 | for (task in tasks) { 54 | try { 55 | insertInternal(task) // Needed to avoid failing on all insert if a single one is failing 56 | } catch (t: Throwable) { 57 | } 58 | } 59 | } 60 | 61 | @Update 62 | abstract fun update(vararg tasks: Task) 63 | 64 | @Delete 65 | abstract fun delete(vararg tasks: Task) 66 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/DecsyncArticle.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.data.entities 2 | 3 | import org.decsync.library.items.Rss 4 | import java.util.* 5 | 6 | @ExperimentalStdlibApi 7 | data class DecsyncArticle( 8 | val uri: String, 9 | val read: Boolean, 10 | val favorite: Boolean, 11 | val publicationDate: Date 12 | ) { 13 | fun getRssArticle(): Rss.Article { 14 | val time = publicationDate.time 15 | val date = Calendar.getInstance(TimeZone.getTimeZone("UTC")) 16 | date.timeInMillis = time 17 | val year = date.get(Calendar.YEAR) 18 | val month = date.get(Calendar.MONTH) + 1 19 | val day = date.get(Calendar.DAY_OF_MONTH) 20 | return Rss.Article(uri, read, favorite, year, month, day) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/DecsyncFeed.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.data.entities 2 | 3 | import org.decsync.flym.App 4 | import org.decsync.library.items.Rss 5 | 6 | @ExperimentalStdlibApi 7 | data class DecsyncFeed( 8 | val feedLink: String, 9 | val feedTitle: String?, 10 | val groupId: Long? 11 | ) { 12 | fun getRssFeed(): Rss.Feed { 13 | return Rss.Feed(feedLink, feedTitle, groupId) { 14 | groupId?.let { App.db.feedDao().findById(it)?.link } 15 | } 16 | } 17 | } 18 | 19 | @ExperimentalStdlibApi 20 | data class DecsyncCategory( 21 | val feedLink: String, 22 | val feedTitle: String 23 | ) { 24 | fun getRssCategory() : Rss.Category { 25 | return Rss.Category(feedLink, feedTitle, null) { 26 | // We do not support nested categories 27 | // Only changes are detected, so always giving the default value of null is fine 28 | null 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/Entry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.content.Context 21 | import android.os.Parcelable 22 | import android.text.format.DateFormat 23 | import android.text.format.DateUtils 24 | import androidx.core.text.HtmlCompat 25 | import androidx.room.Entity 26 | import androidx.room.ForeignKey 27 | import androidx.room.Index 28 | import androidx.room.PrimaryKey 29 | import com.rometools.rome.feed.synd.SyndEntry 30 | import kotlinx.android.parcel.Parcelize 31 | import net.fred.feedex.R 32 | import org.decsync.flym.utils.sha1 33 | import java.util.* 34 | 35 | @Parcelize 36 | @Entity(tableName = "entries", 37 | indices = [(Index(value = ["feedId"])), (Index(value = ["link"], unique = true)), (Index(value = ["uri"], unique = true))], 38 | foreignKeys = [(ForeignKey(entity = Feed::class, 39 | parentColumns = ["feedId"], 40 | childColumns = ["feedId"], 41 | onDelete = ForeignKey.CASCADE))]) 42 | data class Entry(@PrimaryKey 43 | var id: String = "", 44 | var feedId: Long = 0L, 45 | var link: String? = null, 46 | var uri: String? = null, 47 | var fetchDate: Date = Date(), 48 | var publicationDate: Date = fetchDate, // important to know if the publication date has been set 49 | var title: String? = null, 50 | var description: String? = null, 51 | var mobilizedContent: String? = null, 52 | var imageLink: String? = null, 53 | var author: String? = null, 54 | var read: Boolean = false, 55 | var favorite: Boolean = false) : Parcelable { 56 | 57 | fun getReadablePublicationDate(context: Context): String = 58 | if (DateUtils.isToday(publicationDate.time)) { 59 | DateFormat.getTimeFormat(context).format(publicationDate) 60 | } else { 61 | DateFormat.getMediumDateFormat(context).format(publicationDate) + ' ' + 62 | DateFormat.getTimeFormat(context).format(publicationDate) 63 | } 64 | } 65 | 66 | fun SyndEntry.toDbFormat(context: Context, feedId: Long): Entry { 67 | val item = Entry() 68 | item.id = (feedId.toString() + "_" + (link ?: uri ?: title 69 | ?: UUID.randomUUID().toString())).sha1() 70 | item.feedId = feedId 71 | if (title != null) { 72 | item.title = HtmlCompat.fromHtml(title, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() 73 | } else { 74 | item.title = context.getString(R.string.entry_default_title) 75 | } 76 | item.description = contents.getOrNull(0)?.value ?: description?.value 77 | item.link = link 78 | item.uri = uri 79 | 80 | enclosures?.forEach { if (it.type.contains("image")) { item.imageLink = it.url } } 81 | if (item.imageLink == null) { 82 | foreignMarkup?.forEach { 83 | if (it.namespace?.prefix == "media" && it.name == "content") { 84 | it.attributes.forEach { mc -> 85 | if (mc.name == "url") item.imageLink = mc.value 86 | } 87 | } 88 | } 89 | } 90 | 91 | item.author = author 92 | 93 | val date = publishedDate ?: updatedDate 94 | item.publicationDate = if (date?.before(item.publicationDate) == true) date else item.publicationDate 95 | 96 | return item 97 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/EntryWithFeed.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.os.Parcelable 21 | import androidx.room.Embedded 22 | import kotlinx.android.parcel.Parcelize 23 | 24 | 25 | @Parcelize 26 | class EntryWithFeed( 27 | @Embedded 28 | var entry: Entry, 29 | var feedTitle: String? = null, 30 | var feedLink: String = "", 31 | var feedImageLink: String? = null, 32 | var groupId: String? = null) : Parcelable 33 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/Feed.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.os.Parcelable 21 | import androidx.room.ColumnInfo 22 | import androidx.room.Entity 23 | import androidx.room.ForeignKey 24 | import androidx.room.Index 25 | import androidx.room.PrimaryKey 26 | import com.amulyakhare.textdrawable.TextDrawable 27 | import com.amulyakhare.textdrawable.util.ColorGenerator 28 | import com.rometools.rome.feed.synd.SyndFeed 29 | import kotlinx.android.parcel.Parcelize 30 | 31 | 32 | val DELIMITERS = arrayOf(" ", "-", "&", ":", "|") 33 | 34 | @Parcelize 35 | @Entity(tableName = "feeds", 36 | indices = [(Index(value = ["groupId"])), (Index(value = ["feedId", "feedLink"], unique = true))], 37 | foreignKeys = [(ForeignKey(entity = Feed::class, 38 | parentColumns = ["feedId"], 39 | childColumns = ["groupId"], 40 | onDelete = ForeignKey.CASCADE))]) 41 | data class Feed( 42 | @PrimaryKey(autoGenerate = true) 43 | @ColumnInfo(name = "feedId") 44 | var id: Long = 0L, 45 | @ColumnInfo(name = "feedLink") 46 | var link: String = "", 47 | @ColumnInfo(name = "feedTitle") 48 | var title: String? = null, 49 | @ColumnInfo(name = "feedImageLink") 50 | var imageLink: String? = null, 51 | var fetchError: Boolean = false, 52 | var retrieveFullText: Boolean = false, 53 | var isGroup: Boolean = false, 54 | var groupId: Long? = null, 55 | var displayPriority: Int = 0, 56 | @Deprecated("Not used anymore") 57 | var lastManualActionUid: String = "") : Parcelable { 58 | 59 | companion object { 60 | 61 | const val ALL_ENTRIES_ID = -1L 62 | 63 | fun getLetterDrawable(feedId: Long, feedTitle: String?, rounded: Boolean = false): TextDrawable { 64 | val feedName = feedTitle.orEmpty() 65 | 66 | val color = ColorGenerator.MATERIAL.getColor(feedId) // The color is specific to the feedId (which shouldn't change) 67 | val lettersForName = getLettersForName(feedName) 68 | return if (rounded) { 69 | TextDrawable.builder().buildRound(lettersForName, color) 70 | } else { 71 | TextDrawable.builder().buildRect(lettersForName, color) 72 | } 73 | } 74 | 75 | internal fun getLettersForName(feedName: String): String { 76 | val split = feedName.split(*DELIMITERS).filter { it != "" } // filtering empty strings that occur when multiple delimiters are matched, e. g. colon-whitespace: ": " 77 | 78 | val letters = when { 79 | split.size >= 2 -> String(charArrayOf(split[0][0], split[1][0])) // first letter of first and second word 80 | split.isEmpty() -> "" 81 | else -> split[0][0].toString() 82 | } 83 | 84 | return letters.toUpperCase() 85 | } 86 | } 87 | 88 | fun update(feed: SyndFeed) { 89 | if (title == null) { 90 | title = feed.title 91 | } 92 | 93 | if (feed.image?.url != null) { 94 | imageLink = feed.image?.url 95 | } 96 | 97 | // no error anymore since we just got a feedWithCount 98 | fetchError = false 99 | } 100 | 101 | fun getLetterDrawable(rounded: Boolean = false): TextDrawable { 102 | return getLetterDrawable(id, title, rounded) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/FeedWithCount.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.os.Parcelable 21 | import androidx.room.Embedded 22 | import kotlinx.android.parcel.Parcelize 23 | 24 | @Parcelize 25 | data class FeedWithCount( 26 | @Embedded 27 | var feed: Feed, 28 | var entryCount: Int = 0) : Parcelable { 29 | 30 | fun getEntryCountString(): String { 31 | return if (entryCount > 0) entryCount.toString() else "" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/SearchFeedResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.os.Parcelable 21 | import kotlinx.android.parcel.Parcelize 22 | 23 | @Parcelize 24 | data class SearchFeedResult( 25 | var iconUrl: String? = "", 26 | var link: String = "", 27 | var name: String = "", 28 | var desc: String = "", 29 | var isAdded: Boolean = false) : Parcelable 30 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/entities/Task.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.entities 19 | 20 | import android.os.Parcelable 21 | import androidx.room.Entity 22 | import androidx.room.ForeignKey 23 | import androidx.room.Index 24 | import kotlinx.android.parcel.Parcelize 25 | 26 | @Parcelize 27 | @Entity(tableName = "tasks", 28 | primaryKeys = ["entryId", "imageLinkToDl"], 29 | indices = [(Index(value = ["entryId"]))], 30 | foreignKeys = [(ForeignKey(entity = Entry::class, 31 | parentColumns = ["id"], 32 | childColumns = ["entryId"], 33 | onDelete = ForeignKey.CASCADE))]) 34 | data class Task( 35 | var entryId: String = "", 36 | var imageLinkToDl: String = "", 37 | var numberAttempt: Int = 0) : Parcelable 38 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/data/utils/PrefConstants.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.data.utils 19 | 20 | 21 | object PrefConstants { 22 | 23 | const val FIRST_OPEN = "first_open" 24 | 25 | const val IS_REFRESHING = "is_refreshing" 26 | 27 | const val REFRESH_ENABLED = "refresh_enabled" 28 | const val REFRESH_NOTIFICATION_ENABLED = "enable_refresh_notification" 29 | const val REFRESH_INTERVAL = "refresh_interval" 30 | const val REFRESH_ON_STARTUP = "refresh_on_startup" 31 | const val REFRESH_WIFI_ONLY = "refresh_wifi_only" 32 | 33 | const val THEME = "theme" 34 | const val DISPLAY_THUMBNAILS = "display_thumbnails" 35 | const val DISPLAY_IMAGES = "display_images" 36 | 37 | const val PRELOAD_IMAGE_MODE = "preload_image_mode" 38 | const val PRELOAD_IMAGE_MODE__WIFI_ONLY = "WIFI_ONLY_PRELOAD" 39 | const val PRELOAD_IMAGE_MODE__ALWAYS = "ALWAYS_PRELOAD" 40 | 41 | const val REMOVE_DUPLICATES = "remove_duplicates" 42 | 43 | const val FILTER_KEYWORDS = "filter_keywords" 44 | 45 | const val KEEP_TIME = "keep_time" 46 | const val KEEP_TIME_UNREAD = "keep_time_unread" 47 | 48 | const val FONT_SIZE = "font_size" 49 | 50 | const val OPEN_BROWSER_DIRECTLY = "open_browser_directly" 51 | const val HIDE_BUTTON_MARK_ALL_AS_READ = "hide_button_mark_all_as_read" 52 | const val HIDE_NAVIGATION_ON_SCROLL = "hide_navigation_on_scroll" 53 | const val SORT_ORDER = "sort_order" 54 | 55 | const val ENABLE_SWIPE_ENTRY = "enable_swipe_entry" 56 | 57 | const val DECSYNC_ENABLED = "decsync.enabled" 58 | const val DECSYNC_USE_SAF = "decsync.use_saf" 59 | const val UPDATE_FORCES_SAF = "update_forces_saf" 60 | const val DECSYNC_FILE = "decsync.directory" 61 | const val DECSYNC_MANAGE_DATA = "decsync.manage_data" 62 | 63 | const val INTRO_DONE = "intro_done" 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/service/AutoRefreshJobService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.service 19 | 20 | import android.app.job.JobInfo 21 | import android.app.job.JobParameters 22 | import android.app.job.JobScheduler 23 | import android.app.job.JobService 24 | import android.content.ComponentName 25 | import android.content.Context 26 | import android.os.Build 27 | import kotlinx.coroutines.ObsoleteCoroutinesApi 28 | import org.decsync.flym.data.utils.PrefConstants 29 | import org.decsync.flym.utils.getPrefBoolean 30 | import org.decsync.flym.utils.getPrefString 31 | import org.jetbrains.anko.doAsync 32 | import kotlin.math.max 33 | 34 | @ExperimentalStdlibApi 35 | @ObsoleteCoroutinesApi 36 | class AutoRefreshJobService : JobService() { 37 | 38 | companion object { 39 | var ignoreNextJob = false 40 | 41 | private const val TWO_HOURS = "7200" 42 | private const val JOB_ID = 0 43 | 44 | fun initAutoRefresh(context: Context) { 45 | 46 | // DO NOT USE ANKO TO RETRIEVE THE SERVICE HERE (crash on API 21) 47 | val jobSchedulerService = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler 48 | 49 | val time = max(300, context.getPrefString(PrefConstants.REFRESH_INTERVAL, TWO_HOURS)!!.toInt()) 50 | 51 | if (context.getPrefBoolean(PrefConstants.REFRESH_ENABLED, true)) { 52 | val builder = JobInfo.Builder(JOB_ID, ComponentName(context, AutoRefreshJobService::class.java)) 53 | .setPeriodic(time * 1000L) 54 | .setPersisted(true) 55 | .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) 56 | 57 | if (Build.VERSION.SDK_INT >= 26) { 58 | builder.setRequiresBatteryNotLow(true) 59 | .setRequiresStorageNotLow(true) 60 | } 61 | 62 | ignoreNextJob = true // We can't add a initial delay with JobScheduler, so let's do this little hack instead 63 | jobSchedulerService.schedule(builder.build()) 64 | } else { 65 | jobSchedulerService.cancel(JOB_ID) 66 | } 67 | } 68 | } 69 | 70 | override fun onStartJob(params: JobParameters): Boolean { 71 | if (!ignoreNextJob && !getPrefBoolean(PrefConstants.IS_REFRESHING, false)) { 72 | doAsync { 73 | FetcherService.fetch(this@AutoRefreshJobService, true, FetcherService.ACTION_REFRESH_FEEDS) 74 | jobFinished(params, false) 75 | } 76 | return true 77 | } 78 | 79 | ignoreNextJob = false 80 | 81 | return false 82 | } 83 | 84 | override fun onStopJob(params: JobParameters): Boolean { 85 | return false 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/about/AboutActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.about 19 | 20 | import android.os.Bundle 21 | import android.view.MenuItem 22 | import androidx.appcompat.app.AppCompatActivity 23 | import com.vansuita.materialabout.builder.AboutBuilder 24 | import net.fred.feedex.R 25 | import org.decsync.flym.utils.setupTheme 26 | 27 | 28 | class AboutActivity : AppCompatActivity() { 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | setupTheme() 32 | 33 | super.onCreate(savedInstanceState) 34 | 35 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 36 | 37 | val view = AboutBuilder.with(this) 38 | .setPhoto(R.mipmap.profile_picture) 39 | .setCover(R.mipmap.profile_cover) 40 | .setName("Aldo Gunsing") 41 | .setSubTitle(R.string.about_screen_based_on_flym) 42 | .setBrief(R.string.about_screen_info) 43 | .setAppIcon(R.drawable.ic_launcher_foreground) 44 | .setAppName(R.string.app_name) 45 | .addGitHubLink("39aldo39/Flym-DecSync") 46 | .addShareAction(R.string.app_name) 47 | .setWrapScrollView(true) 48 | .setLinksAnimated(true) 49 | .setShowAsCard(true) 50 | .build() 51 | 52 | setContentView(view) 53 | } 54 | 55 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 56 | when (item.itemId) { 57 | android.R.id.home -> onBackPressed() 58 | } 59 | 60 | return true 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/discover/DiscoverFragment.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.ui.discover 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.* 9 | import androidx.fragment.app.Fragment 10 | import net.fred.feedex.R 11 | import org.decsync.flym.GlideApp 12 | import org.decsync.flym.data.entities.Feed 13 | import org.jetbrains.anko.layoutInflater 14 | 15 | 16 | class DiscoverFragment : Fragment(), AdapterView.OnItemClickListener { 17 | 18 | companion object { 19 | const val TAG = "DiscoverFragment" 20 | 21 | @JvmStatic 22 | fun newInstance() = DiscoverFragment() 23 | } 24 | 25 | private lateinit var manageFeeds: FeedManagementInterface 26 | 27 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 28 | val view = inflater.inflate(R.layout.fragment_discover, container, false) 29 | initGridView(view) 30 | return view 31 | } 32 | 33 | override fun onAttach(context: Context) { 34 | super.onAttach(context) 35 | manageFeeds = context as FeedManagementInterface 36 | } 37 | 38 | private fun initGridView(view: View) { 39 | val gvTopics: GridView = view.findViewById(R.id.gv_topics) 40 | val topics = view.context.resources.getStringArray(R.array.discover_topics) 41 | gvTopics.adapter = TopicAdapter(view.context, topics) 42 | gvTopics.onItemClickListener = this 43 | } 44 | 45 | override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { 46 | val topic = parent?.getItemAtPosition(position) as String 47 | manageFeeds.searchForFeed("#$topic") 48 | } 49 | 50 | class TopicAdapter(context: Context, topics: Array) : 51 | ArrayAdapter(context, R.layout.item_discover_topic, topics) { 52 | 53 | private class ItemViewHolder { 54 | var image: ImageView? = null 55 | var title: TextView? = null 56 | } 57 | 58 | private fun setTopicTitle(viewHolder: ItemViewHolder, topic: String) { 59 | viewHolder.title?.text = topic 60 | } 61 | 62 | private fun setTopicImage(viewHolder: ItemViewHolder, topic: String) { 63 | val letterDrawable = Feed.getLetterDrawable(topic.hashCode().toLong(), topic) 64 | viewHolder.image?.let { iv -> 65 | GlideApp.with(context).clear(iv) 66 | iv.setImageDrawable(letterDrawable) 67 | } 68 | } 69 | 70 | override fun getView(i: Int, view: View?, viewGroup: ViewGroup): View { 71 | val viewHolder: ItemViewHolder 72 | var inflatedView: View? = view 73 | if (inflatedView == null) { 74 | inflatedView = context.layoutInflater.inflate(R.layout.item_discover_topic, null) 75 | viewHolder = ItemViewHolder() 76 | inflatedView?.let { vw -> 77 | viewHolder.image = vw.findViewById(R.id.iv_topic_image) as ImageView 78 | viewHolder.title = vw.findViewById(R.id.tv_topic_title) as TextView 79 | } 80 | } else { 81 | viewHolder = inflatedView.tag as ItemViewHolder 82 | } 83 | val item = getItem(i) 84 | item?.let { it -> 85 | setTopicImage(viewHolder, it) 86 | setTopicTitle(viewHolder, it) 87 | } 88 | inflatedView?.tag = viewHolder 89 | return inflatedView!! 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/discover/FeedManagementInterface.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.ui.discover 2 | 3 | import android.view.View 4 | import org.decsync.flym.data.entities.SearchFeedResult 5 | 6 | interface FeedManagementInterface { 7 | 8 | fun searchForFeed(query: String) 9 | 10 | fun addFeed(view: View, title: String, link: String) 11 | 12 | fun deleteFeed(view: View, feed: SearchFeedResult) 13 | 14 | fun previewFeed(view: View, feed: SearchFeedResult) 15 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/discover/SquareGridItemLayout.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.ui.discover 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import androidx.constraintlayout.widget.ConstraintLayout 6 | 7 | class SquareGridItemLayout : ConstraintLayout { 8 | constructor(context: Context) : super(context) 9 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 10 | constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) 11 | 12 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 13 | super.onMeasure(widthMeasureSpec, widthMeasureSpec) 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/entrydetails/EntryDetailsActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.entrydetails 19 | 20 | import android.os.Bundle 21 | import android.util.TypedValue 22 | import android.view.MenuItem 23 | import androidx.appcompat.app.AppCompatActivity 24 | import kotlinx.coroutines.ObsoleteCoroutinesApi 25 | import net.fred.feedex.R 26 | import org.decsync.flym.utils.setupNoActionBarTheme 27 | import org.jetbrains.anko.backgroundColor 28 | 29 | @ExperimentalStdlibApi 30 | @ObsoleteCoroutinesApi 31 | class EntryDetailsActivity : AppCompatActivity() { 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | setupNoActionBarTheme() 35 | 36 | super.onCreate(savedInstanceState) 37 | 38 | val tv = TypedValue() 39 | if (theme.resolveAttribute(R.attr.colorPrimary, tv, true)) { 40 | window.decorView.backgroundColor = tv.data 41 | } 42 | 43 | if (savedInstanceState == null) { 44 | val fragment = EntryDetailsFragment().apply { 45 | arguments = intent.extras 46 | } 47 | 48 | supportFragmentManager 49 | .beginTransaction() 50 | .replace(android.R.id.content, fragment) 51 | .commitAllowingStateLoss() 52 | } 53 | } 54 | 55 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 56 | when (item.itemId) { 57 | android.R.id.home -> onBackPressed() 58 | } 59 | 60 | return false 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/feeds/DrawerFeedAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.feeds 19 | 20 | import android.os.Bundle 21 | import android.view.View 22 | import org.decsync.flym.data.entities.Feed 23 | import org.decsync.flym.data.entities.FeedWithCount 24 | import org.jetbrains.anko.sdk21.listeners.onClick 25 | 26 | 27 | private const val STATE_SELECTED_ID = "STATE_SELECTED_ID" 28 | 29 | open class FeedAdapter(groups: List) : BaseFeedAdapter(groups) { 30 | 31 | var selectedItemId = Feed.ALL_ENTRIES_ID 32 | set(newValue) { 33 | notifyParentDataSetChanged(true) 34 | field = newValue 35 | } 36 | 37 | override fun bindItem(itemView: View, feedWithCount: FeedWithCount) { 38 | itemView.isSelected = selectedItemId == feedWithCount.feed.id 39 | 40 | itemView.onClick { 41 | selectedItemId = feedWithCount.feed.id 42 | feedClickListener?.invoke(itemView, feedWithCount) 43 | } 44 | } 45 | 46 | override fun bindItem(itemView: View, group: FeedGroup) { 47 | itemView.isSelected = selectedItemId == group.feedWithCount.feed.id 48 | 49 | itemView.onClick { 50 | selectedItemId = group.feedWithCount.feed.id 51 | feedClickListener?.invoke(itemView, group.feedWithCount) 52 | } 53 | } 54 | 55 | override fun onSaveInstanceState(savedInstanceState: Bundle) { 56 | savedInstanceState.putLong(STATE_SELECTED_ID, selectedItemId) 57 | } 58 | 59 | override fun onRestoreInstanceState(savedInstanceState: Bundle?) { 60 | selectedItemId = savedInstanceState?.getLong(STATE_SELECTED_ID) ?: Feed.ALL_ENTRIES_ID 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/feeds/EditFeedAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.feeds 19 | 20 | import net.fred.feedex.R 21 | 22 | class EditFeedAdapter(groups: List) : BaseFeedAdapter(groups) { 23 | override val layoutId = R.layout.view_feed_edit 24 | } -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/feeds/FeedGroup.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.feeds 19 | 20 | import com.bignerdranch.expandablerecyclerview.model.Parent 21 | import org.decsync.flym.data.entities.FeedWithCount 22 | 23 | 24 | class FeedGroup(val feedWithCount: FeedWithCount, val subFeeds: List) : Parent { 25 | 26 | override fun getChildList(): List { 27 | return subFeeds 28 | } 29 | 30 | override fun isInitiallyExpanded(): Boolean { 31 | return false 32 | } 33 | 34 | // needed to preserve expansion state 35 | override fun equals(other: Any?): Boolean { 36 | if (this === other) return true 37 | if (javaClass != other?.javaClass) return false 38 | 39 | other as FeedGroup 40 | 41 | if (feedWithCount.feed.id != other.feedWithCount.feed.id) return false 42 | 43 | return true 44 | } 45 | 46 | override fun hashCode(): Int { 47 | return feedWithCount.feed.id.hashCode() 48 | } 49 | 50 | fun getEntryCountString(): String { 51 | val entryCount = if (subFeeds.isNotEmpty()) subFeeds.sumBy { it.entryCount } else feedWithCount.entryCount 52 | return if (entryCount > 0) entryCount.toString() else "" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/feeds/FeedListEditActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Frederic Julian 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see //www.gnu.org/licenses/>. 16 | */ 17 | 18 | package org.decsync.flym.ui.feeds 19 | 20 | import android.os.Bundle 21 | import android.view.MenuItem 22 | import androidx.appcompat.app.AppCompatActivity 23 | import net.fred.feedex.R 24 | import org.decsync.flym.utils.setupTheme 25 | 26 | class FeedListEditActivity : AppCompatActivity() { 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | setupTheme() 30 | 31 | super.onCreate(savedInstanceState) 32 | 33 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 34 | 35 | setContentView(R.layout.activity_feed_list_edit) 36 | } 37 | 38 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 39 | when (item.itemId) { 40 | android.R.id.home -> onBackPressed() 41 | } 42 | 43 | return false 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/decsync/flym/ui/intro/SafUpdateActivity.kt: -------------------------------------------------------------------------------- 1 | package org.decsync.flym.ui.intro 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.Button 9 | import android.widget.CheckBox 10 | import android.widget.Toast 11 | import androidx.fragment.app.Fragment 12 | import com.github.appintro.AppIntro2 13 | import com.github.appintro.SlidePolicy 14 | import kotlinx.android.synthetic.main.activity_saf_update.* 15 | import net.fred.feedex.R 16 | import org.decsync.flym.data.utils.PrefConstants 17 | import org.decsync.flym.ui.main.MainActivity 18 | import org.decsync.flym.utils.putPrefBoolean 19 | import org.decsync.library.DecsyncPrefUtils 20 | 21 | @ExperimentalStdlibApi 22 | class SafUpdateActivity : AppIntro2() { 23 | private val slideSafDirectory = SlideSafDirectory() 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | 28 | isSkipButtonEnabled = false 29 | isIndicatorEnabled = false 30 | showStatusBar(true) 31 | 32 | addSlide(slideSafDirectory) 33 | } 34 | 35 | override fun onIntroFinished() { 36 | super.onIntroFinished() 37 | 38 | putPrefBoolean(PrefConstants.UPDATE_FORCES_SAF, false) 39 | 40 | val decsyncEnabled = slideSafDirectory.decsyncEnabled 41 | putPrefBoolean(PrefConstants.DECSYNC_ENABLED, decsyncEnabled) 42 | 43 | val intent = Intent(this, MainActivity::class.java) 44 | startActivity(intent) 45 | finish() 46 | } 47 | } 48 | 49 | @ExperimentalStdlibApi 50 | class SlideSafDirectory : Fragment(), SlidePolicy { 51 | var decsyncEnabled = true 52 | 53 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 54 | val view = inflater.inflate(R.layout.activity_saf_update, container, false) 55 | 56 | val button = view.findViewById