├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libraries
│ └── stickyheaders
│ │ ├── .gitignore
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ ├── android
│ │ └── support
│ │ │ └── v7
│ │ │ └── widget
│ │ │ └── RecyclerViewHelper.java
│ │ └── com
│ │ └── eowise
│ │ └── recyclerview
│ │ └── stickyheaders
│ │ ├── DrawOrder.java
│ │ ├── HeaderStore.java
│ │ ├── OnHeaderClickListener.java
│ │ ├── StickyHeadersAdapter.java
│ │ ├── StickyHeadersBuilder.java
│ │ ├── StickyHeadersItemDecoration.java
│ │ └── StickyHeadersTouchListener.java
├── proguard-rules.pro
└── src
│ ├── droidconBerlin
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── de
│ │ │ └── droidcon
│ │ │ ├── CrashlyticsTimberTree.kt
│ │ │ ├── DroidconBerlinApp.kt
│ │ │ ├── dagger
│ │ │ └── DroidconBerlinNetworkModule.kt
│ │ │ └── model
│ │ │ └── backend
│ │ │ ├── DroidconBerlinBackend.java
│ │ │ ├── DroidconBerlinBackendScheduleAdapter.kt
│ │ │ ├── DroidconBerlinLink.java
│ │ │ ├── DroidconBerlinLocation.java
│ │ │ ├── DroidconBerlinSession.java
│ │ │ ├── DroidconBerlinSpeaker.java
│ │ │ └── InstantIsoTypeConverter.kt
│ └── res
│ │ ├── values-de
│ │ └── strings.xml
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── openconference
│ │ │ ├── Navigator.kt
│ │ │ ├── OpenConfApp.kt
│ │ │ ├── PhoneNavigator.kt
│ │ │ ├── dagger
│ │ │ ├── ApplicationComponent.kt
│ │ │ ├── ApplicationContext.kt
│ │ │ ├── ApplicationModule.kt
│ │ │ ├── DaoModule.kt
│ │ │ ├── ErrorMessageModule.kt
│ │ │ ├── LoadersModule.kt
│ │ │ ├── NetworkModule.kt
│ │ │ ├── PicassoModule.kt
│ │ │ ├── ScheduleModule.kt
│ │ │ ├── SchedulingModule.kt
│ │ │ └── SearchModule.kt
│ │ │ ├── main
│ │ │ ├── MainActivityComponent.kt
│ │ │ ├── MainActivityModule.kt
│ │ │ ├── MainActivityScope.java
│ │ │ ├── MainScreensPagerAdapter.kt
│ │ │ └── ViewPagerMainActivity.kt
│ │ │ ├── model
│ │ │ ├── Location.kt
│ │ │ ├── ScheduleDataAwareObservableFactory.kt
│ │ │ ├── Session.kt
│ │ │ ├── SessionsLoader.kt
│ │ │ ├── Speaker.kt
│ │ │ ├── SpeakerNotFoundException.kt
│ │ │ ├── SpeakersLoader.kt
│ │ │ ├── backend
│ │ │ │ └── schedule
│ │ │ │ │ ├── BackendScheduleAdapter.kt
│ │ │ │ │ ├── BackendScheduleResponse.kt
│ │ │ │ │ ├── ScheduleDataStateDeterminer.kt
│ │ │ │ │ ├── ScheduleSync.kt
│ │ │ │ │ └── TimebaseScheduleDataStateDeterminer.kt
│ │ │ ├── database
│ │ │ │ ├── EndTimeInstantCursorAdapter.kt
│ │ │ │ ├── InstantParcelableTypeAdapter.kt
│ │ │ │ ├── LocationAutoValue.kt
│ │ │ │ ├── SessionAutoValue.kt
│ │ │ │ ├── SessionDateTimeComparator.kt
│ │ │ │ ├── SpeakerAutoValue.kt
│ │ │ │ ├── StartTimeInstantCursorAdapter.kt
│ │ │ │ └── dao
│ │ │ │ │ ├── LocationDao.kt
│ │ │ │ │ ├── LocationDaoSqlite.kt
│ │ │ │ │ ├── SessionDao.kt
│ │ │ │ │ ├── SessionDaoSqlite.kt
│ │ │ │ │ ├── SessionJoinResult.kt
│ │ │ │ │ ├── SpeakerDao.kt
│ │ │ │ │ └── SpeakerDaoSqlite.kt
│ │ │ ├── errormessage
│ │ │ │ ├── DefaultErrorMessageDeterminer.kt
│ │ │ │ └── ErrorMessageDeterminer.kt
│ │ │ ├── notification
│ │ │ │ ├── DefaultNotificationScheduler.kt
│ │ │ │ ├── NotificationBroadcastReceiver.kt
│ │ │ │ ├── NotificationBuilderIntentService.kt
│ │ │ │ ├── NotificationScheduler.kt
│ │ │ │ └── NotificationSchedulerCommand.kt
│ │ │ ├── screen
│ │ │ │ ├── MyScheduleScreen.kt
│ │ │ │ ├── Screen.kt
│ │ │ │ ├── Screens.kt
│ │ │ │ ├── SessionsScreen.kt
│ │ │ │ ├── SpeakersScreen.kt
│ │ │ │ └── TwitterScreen.kt
│ │ │ └── search
│ │ │ │ ├── DefaultSearchEngine.kt
│ │ │ │ ├── SearchEngine.kt
│ │ │ │ ├── SearchSource.kt
│ │ │ │ ├── SearchableItem.kt
│ │ │ │ ├── SessionSearchableItem.kt
│ │ │ │ ├── SpeakerSearchableItem.kt
│ │ │ │ └── source
│ │ │ │ ├── LocalStorageSessionsSearchSource.kt
│ │ │ │ └── LocalStorageSpeakersSearchSource.kt
│ │ │ ├── myschedule
│ │ │ ├── MyScheduleComponent.kt
│ │ │ ├── MyScheduleFragment.kt
│ │ │ ├── MyScheduleModule.kt
│ │ │ ├── MySchedulePresenter.kt
│ │ │ ├── MyScheduleScope.kt
│ │ │ ├── MyScheduleView.kt
│ │ │ └── presentationmodel
│ │ │ │ ├── MySchedulePresentationModel.kt
│ │ │ │ └── MySchedulePresentationModelTransformer.kt
│ │ │ ├── search
│ │ │ ├── SearchActivity.kt
│ │ │ ├── SearchComponent.kt
│ │ │ ├── SearchPresenter.kt
│ │ │ ├── SearchScope.kt
│ │ │ ├── SearchView.kt
│ │ │ ├── SearchViewModule.kt
│ │ │ ├── SearchViewState.kt
│ │ │ ├── SessionItemAdapterDelegate.kt
│ │ │ └── SpeakerAdapterDelegate.kt
│ │ │ ├── sessiondetails
│ │ │ ├── DetailsDateAdapterDelegate.kt
│ │ │ ├── DetailsDescriptionAdapterDelegate.kt
│ │ │ ├── DetailsLocationAdapterDelegate.kt
│ │ │ ├── DetailsSeparatorAdapterDelegate.kt
│ │ │ ├── DetailsSpeakerAdapterDelegate.kt
│ │ │ ├── SessionDetailsActivity.kt
│ │ │ ├── SessionDetailsComponent.kt
│ │ │ ├── SessionDetailsFragment.kt
│ │ │ ├── SessionDetailsModule.kt
│ │ │ ├── SessionDetailsPresenter.kt
│ │ │ ├── SessionDetailsScope.kt
│ │ │ ├── SessionDetailsView.kt
│ │ │ └── presentationmodel
│ │ │ │ ├── SessionDetail.kt
│ │ │ │ ├── SessionDetailItem.kt
│ │ │ │ └── SessionDetailsPresentationModelTransformer.kt
│ │ │ ├── sessions
│ │ │ ├── SessionDateStickyHeaderAdapter.kt
│ │ │ ├── SessionItemAdapterDelegate.kt
│ │ │ ├── SessionsComponent.kt
│ │ │ ├── SessionsFragment.kt
│ │ │ ├── SessionsModule.kt
│ │ │ ├── SessionsPresenter.kt
│ │ │ ├── SessionsScope.java
│ │ │ ├── SessionsView.kt
│ │ │ └── presentationmodel
│ │ │ │ ├── GroupableSession.kt
│ │ │ │ ├── PhoneSessionPresentationModelTransformer.kt
│ │ │ │ ├── SessionPresentationModel.kt
│ │ │ │ └── SessionPresentationModelTransformer.kt
│ │ │ ├── speakerdetails
│ │ │ ├── SpeakerDetailsActivity.kt
│ │ │ ├── SpeakerDetailsBioAdapterDelegate.kt
│ │ │ ├── SpeakerDetailsComponent.kt
│ │ │ ├── SpeakerDetailsFragment.kt
│ │ │ ├── SpeakerDetailsJobInfoAdapterDelegate.kt
│ │ │ ├── SpeakerDetailsLinkAdapterDelegate.kt
│ │ │ ├── SpeakerDetailsModule.kt
│ │ │ ├── SpeakerDetailsPresenter.kt
│ │ │ ├── SpeakerDetailsScope.kt
│ │ │ ├── SpeakerDetailsView.kt
│ │ │ ├── SpeakerDetailsViewHolder.kt
│ │ │ └── presentationmodel
│ │ │ │ ├── SpeakerDetail.kt
│ │ │ │ ├── SpeakerDetailsItem.kt
│ │ │ │ ├── SpeakerDetailsPresentationModelTransformer.kt
│ │ │ │ └── SpeakerDetailsSessionDelegate.kt
│ │ │ ├── speakers
│ │ │ ├── SpeakerAdapterDelegate.kt
│ │ │ ├── SpeakersComponent.kt
│ │ │ ├── SpeakersFragment.kt
│ │ │ ├── SpeakersModule.kt
│ │ │ ├── SpeakersPresenter.kt
│ │ │ ├── SpeakersScope.java
│ │ │ └── SpeakersView.kt
│ │ │ ├── splash
│ │ │ ├── SplashActivity.kt
│ │ │ ├── SplashComponent.kt
│ │ │ ├── SplashPresenter.kt
│ │ │ ├── SplashScope.kt
│ │ │ └── SplashView.kt
│ │ │ ├── twitter
│ │ │ ├── TwitterTimelineFragment.kt
│ │ │ ├── TwitterTimelinePresenter.kt
│ │ │ └── TwitterTimelineView.kt
│ │ │ └── util
│ │ │ ├── ActivityExtensions.kt
│ │ │ ├── ContentValuesExtensions.kt
│ │ │ ├── FragmentExtensions.kt
│ │ │ ├── FragmentScope.kt
│ │ │ ├── RxPresenter.kt
│ │ │ ├── SchedulerTransformer.kt
│ │ │ ├── StableIdListAdapter.kt
│ │ │ ├── ViewExtensions.kt
│ │ │ ├── lce
│ │ │ ├── LceAnimatable.kt
│ │ │ ├── LceView.kt
│ │ │ └── LceViewState.kt
│ │ │ ├── picasso
│ │ │ ├── CircleImageTransformation.java
│ │ │ └── PicassoScrollListener.kt
│ │ │ └── ui
│ │ │ └── SquaredImageView.kt
│ └── res
│ │ ├── anim
│ │ ├── fade_in.xml
│ │ └── fade_out.xml
│ │ ├── animator
│ │ ├── add_to_schedule_line_1_move.xml
│ │ ├── add_to_schedule_line_1_trim.xml
│ │ ├── add_to_schedule_line_2_move.xml
│ │ ├── add_to_schedule_line_2_untrim.xml
│ │ ├── add_to_schedule_rotate.xml
│ │ ├── remove_from_schedule_line_1_move.xml
│ │ ├── remove_from_schedule_line_1_untrim.xml
│ │ ├── remove_from_schedule_line_2_move.xml
│ │ ├── remove_from_schedule_line_2_trim.xml
│ │ └── remove_from_schedule_rotate.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification_small.png
│ │ ├── drawable-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification_small.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification_small.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification_small.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_notification_small.png
│ │ ├── drawable
│ │ ├── avd_add_to_schedule.xml
│ │ ├── avd_remove_from_schedule.xml
│ │ ├── ic_add_to_schedule_anim.xml
│ │ ├── ic_arrow_back.xml
│ │ ├── ic_arrow_back_white.xml
│ │ ├── ic_bio.xml
│ │ ├── ic_done.xml
│ │ ├── ic_empty.xml
│ │ ├── ic_error.xml
│ │ ├── ic_link.xml
│ │ ├── ic_location.xml
│ │ ├── ic_my_schedule.xml
│ │ ├── ic_person.xml
│ │ ├── ic_remove_from_schedule_anim.xml
│ │ ├── ic_search.xml
│ │ ├── ic_search_big.xml
│ │ ├── ic_sessions.xml
│ │ ├── ic_sessions_details.xml
│ │ ├── ic_speakers.xml
│ │ ├── ic_time.xml
│ │ ├── ic_twitter.xml
│ │ ├── ic_work.xml
│ │ ├── rounded_profile_pic_placeholder.xml
│ │ ├── separator_line.xml
│ │ ├── splash_logo.xml
│ │ └── viewpager_separator.xml
│ │ ├── layout-land
│ │ └── fragment_speaker_details.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_search.xml
│ │ ├── activity_session_details.xml
│ │ ├── activity_splash.xml
│ │ ├── fragment_my_schedule.xml
│ │ ├── fragment_session_details.xml
│ │ ├── fragment_sessions.xml
│ │ ├── fragment_speaker_details.xml
│ │ ├── fragment_twitter_timeline.xml
│ │ ├── item_details_icon_link_text.xml
│ │ ├── item_details_icon_text.xml
│ │ ├── item_search_session.xml
│ │ ├── item_search_speaker.xml
│ │ ├── item_session.xml
│ │ ├── item_session_date_sticky_header.xml
│ │ ├── item_session_details_date.xml
│ │ ├── item_session_details_description.xml
│ │ ├── item_session_details_location.xml
│ │ ├── item_session_details_separator.xml
│ │ ├── item_session_details_speaker.xml
│ │ ├── item_speaker.xml
│ │ ├── item_speaker_details_jobinfo.xml
│ │ ├── view_error.xml
│ │ └── view_loading.xml
│ │ ├── menu
│ │ └── main_menu.xml
│ │ ├── raw
│ │ └── notices.xml
│ │ ├── transition
│ │ └── auto.xml
│ │ ├── values-de
│ │ └── strings.xml
│ │ ├── values-land
│ │ └── integers.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── fractions.xml
│ │ ├── integers.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── playground
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── openconfernce
│ │ ├── MockNetworkModule.kt
│ │ ├── PlaygroundApp.kt
│ │ └── mock
│ │ └── MockSchedulerAdapterStub.kt
│ └── test
│ └── java
│ └── com
│ └── openconference
│ ├── TestApplication.kt
│ └── model
│ ├── ScheduleDataAwareObservableFactoryTest.kt
│ ├── backend
│ └── schedule
│ │ ├── ScheduleSyncTest.kt
│ │ └── TimebaseScheduleDataStateDeterminerTest.kt
│ ├── database
│ ├── InstantParcelableTypeAdapterTest.kt
│ └── dao
│ │ ├── LocationDaoSqliteTest.kt
│ │ ├── SessionDaoSqliteTest.kt
│ │ ├── SortByStartDateTimeTest.kt
│ │ └── SpeakerDaoSqliteTest.kt
│ └── notification
│ └── NotificationSchedulerCommandTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | bin/
5 | gen/
6 | classes/
7 | gen-external-apklibs/
8 |
9 | # Eclipse project files
10 | .classpath
11 | .project
12 | .metadata
13 | .settings
14 |
15 | # IntelliJ files
16 | .idea
17 | *.iml
18 | *.iml
19 | *.ipr
20 | *.iws
21 | **/.idea/workspace.xml
22 | **/.idea/tasks.xml
23 | **/.idea/datasources.xml
24 | **/.idea/dataSources.ids
25 | **/.idea/gradle.xml
26 | **/.idea/misc.xml
27 | **/.idea/modules.xml
28 | **/.idea/libraries
29 | **/.idea/dictionaries
30 |
31 | # OSX files
32 | .DS_Store
33 |
34 | # Windows files
35 | Thumbs.db
36 |
37 | # vi swap files
38 | *.swp
39 |
40 | # backup files
41 | *.bak
42 |
43 |
44 | # Files for the Dalvik VM
45 | *.dex
46 |
47 | # Java class files
48 | *.class
49 |
50 | # Generated files
51 | bin/
52 | gen/
53 |
54 | # Gradle files
55 | .gradle/
56 | build/
57 | .gradle
58 |
59 | #maven files
60 | target/
61 | /null
62 |
63 | # Local configuration file (sdk path, etc)
64 |
65 | local.properties
66 |
67 | # Proguard folder generated by Eclipse
68 | proguard/
69 |
70 | #Log Files
71 | *.log
72 |
73 |
74 | #crashlytics
75 | **/com_crashlytics_export_strings.xml
76 |
77 | #infer
78 | infer-out/
79 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | android:
4 | components:
5 | - platform-tools
6 | - tools
7 | - android-23
8 | - build-tools-23.0.3
9 | - extra-android-support
10 | - extra-android-m2repository
11 |
12 | licenses:
13 | - 'android-sdk-license-.+'
14 |
15 | jdk:
16 | - oraclejdk8
17 |
18 | install: true
19 |
20 | script: ./gradlew clean build --info --stacktrace
21 |
22 | branches:
23 | except:
24 | - gh-pages
25 |
26 | notifications:
27 | email: false
28 |
29 | sudo: false
30 |
31 | cache:
32 | directories:
33 | - $HOME/.gradle
34 | - $HOME/.m2
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenConference
2 |
3 | This repository offers an android app that can be used by any conference to display information like sessions, speaker etc. about the conference in a native android app
4 |
5 | Originally this app has been build for droidcon Berlin, but the app can be styled and configured freely so that it can be used by other conferences as well.
6 |
7 | [](https://travis-ci.org/OpenConference/OpenConference-android)
8 |
9 | # For your conference
10 |
11 | The documentation is not available yet, but basically there are two ways to create your own android app for your conference (based on this source code):
12 |
13 | 1. Create a product flavor for your conference: Android's gradle plugin allows us to have multiple product flavors. If you use product flavors, you can benefit from some features like CI and testing. If you need help, please create an issue here on github.
14 |
15 | 2. Fork the whole repository and do your own thing.
16 |
17 |
18 | # Connect to your backend
19 | This app is has been built with changeable, modular and components in mind. We use dagger 2 for dependency injection and so you can override almost all components to match your needs. The most important one is: [BackendScheduleAdapter](https://github.com/OpenConference/OpenConference-android/blob/master/app/src/main/java/com/openconference/model/backend/schedule/BackendScheduleAdapter.kt) where you define how to load data from your backend (i.e. by using Retrofit).
20 |
21 | Custom styling can be applied by overriding default xml styles and layouts files.
22 |
23 |
24 | # License
25 | ```
26 | Copyright 2016 Open Conference
27 |
28 | Licensed under the Apache License, Version 2.0 (the "License");
29 | you may not use this file except in compliance with the License.
30 | You may obtain a copy of the License at
31 |
32 | http://www.apache.org/licenses/LICENSE-2.0
33 |
34 | Unless required by applicable law or agreed to in writing, software
35 | distributed under the License is distributed on an "AS IS" BASIS,
36 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37 | See the License for the specific language governing permissions and
38 | limitations under the License.
39 | ```
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | bin/
5 | gen/
6 | classes/
7 | gen-external-apklibs/
8 |
9 | # Eclipse project files
10 | .classpath
11 | .project
12 | .metadata
13 | .settings
14 |
15 | # IntelliJ files
16 | .idea
17 | *.iml
18 | *.iml
19 | *.ipr
20 | *.iws
21 | **/.idea/workspace.xml
22 | **/.idea/tasks.xml
23 | **/.idea/datasources.xml
24 | **/.idea/dataSources.ids
25 | **/.idea/gradle.xml
26 | **/.idea/misc.xml
27 | **/.idea/modules.xml
28 | **/.idea/libraries
29 | **/.idea/dictionaries
30 |
31 | # OSX files
32 | .DS_Store
33 |
34 | # Windows files
35 | Thumbs.db
36 |
37 | # vi swap files
38 | *.swp
39 |
40 | # backup files
41 | *.bak
42 |
43 |
44 | # Files for the Dalvik VM
45 | *.dex
46 |
47 | # Java class files
48 | *.class
49 |
50 | # Generated files
51 | bin/
52 | gen/
53 |
54 | # Gradle files
55 | .gradle/
56 | build/
57 | .gradle
58 |
59 | #maven files
60 | target/
61 | /null
62 |
63 | # Local configuration file (sdk path, etc)
64 |
65 | local.properties
66 |
67 | # Proguard folder generated by Eclipse
68 | proguard/
69 |
70 | #Log Files
71 | *.log
72 |
73 | #infer
74 | infer-out/
75 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | bin/
5 | gen/
6 | classes/
7 | gen-external-apklibs/
8 |
9 | # Eclipse project files
10 | .classpath
11 | .project
12 | .metadata
13 | .settings
14 |
15 | # IntelliJ files
16 | .idea
17 | *.iml
18 | *.iml
19 | *.ipr
20 | *.iws
21 | **/.idea/workspace.xml
22 | **/.idea/tasks.xml
23 | **/.idea/datasources.xml
24 | **/.idea/dataSources.ids
25 | **/.idea/gradle.xml
26 | **/.idea/misc.xml
27 | **/.idea/modules.xml
28 | **/.idea/libraries
29 | **/.idea/dictionaries
30 |
31 | # OSX files
32 | .DS_Store
33 |
34 | # Windows files
35 | Thumbs.db
36 |
37 | # vi swap files
38 | *.swp
39 |
40 | # backup files
41 | *.bak
42 |
43 |
44 | # Files for the Dalvik VM
45 | *.dex
46 |
47 | # Java class files
48 | *.class
49 |
50 | # Generated files
51 | bin/
52 | gen/
53 |
54 | # Gradle files
55 | .gradle/
56 | build/
57 | .gradle
58 |
59 | #maven files
60 | target/
61 | /null
62 |
63 | # Local configuration file (sdk path, etc)
64 |
65 | local.properties
66 |
67 | # Proguard folder generated by Eclipse
68 | proguard/
69 |
70 | #Log Files
71 | *.log
72 |
73 | #infer
74 | infer-out/
75 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | dependencies {
4 | compile libs.recyclerView
5 | }
6 |
7 | android {
8 |
9 | compileOptions.incremental = false
10 |
11 | compileSdkVersion compileSdk
12 | buildToolsVersion buildTools
13 |
14 | defaultConfig {
15 | minSdkVersion minSdk
16 | targetSdkVersion targetSdk
17 | }
18 | }
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=Sticky headers library
2 | POM_ARTIFACT_ID=recyclerview-stickyheaders
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/src/main/java/android/support/v7/widget/RecyclerViewHelper.java:
--------------------------------------------------------------------------------
1 | package android.support.v7.widget;
2 |
3 | /**
4 | * Created by aurel on 19/10/14.
5 | */
6 | public class RecyclerViewHelper {
7 |
8 | public static int convertPreLayoutPositionToPostLayout(RecyclerView recyclerView, int position) {
9 | return recyclerView.mRecycler.convertPreLayoutPositionToPostLayout(position);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/src/main/java/com/eowise/recyclerview/stickyheaders/DrawOrder.java:
--------------------------------------------------------------------------------
1 | package com.eowise.recyclerview.stickyheaders;
2 |
3 | /**
4 | * Created by aurel on 10/11/14.
5 | */
6 | public enum DrawOrder {
7 | OverItems,
8 | UnderItems
9 | }
10 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/src/main/java/com/eowise/recyclerview/stickyheaders/OnHeaderClickListener.java:
--------------------------------------------------------------------------------
1 | package com.eowise.recyclerview.stickyheaders;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by aurel on 08/11/14.
7 | */
8 | public interface OnHeaderClickListener {
9 | void onHeaderClick(View header, long headerId);
10 | }
11 |
--------------------------------------------------------------------------------
/app/libraries/stickyheaders/src/main/java/com/eowise/recyclerview/stickyheaders/StickyHeadersAdapter.java:
--------------------------------------------------------------------------------
1 | package com.eowise.recyclerview.stickyheaders;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.ViewGroup;
5 |
6 | public interface StickyHeadersAdapter {
7 |
8 | /**
9 | * Create a header {@link android.support.v7.widget.RecyclerView.ViewHolder ViewHolder} witch encapsulate the header view
10 | * You can either create a View manually or inflate it from an XML layout file.
11 | *
12 | * @param parent the parent {@link android.view.ViewGroup ViewGroup}
13 | * @return the newly created {@link android.support.v7.widget.RecyclerView.ViewHolder ViewHolder}
14 | */
15 | HeaderViewHolder onCreateViewHolder(ViewGroup parent);
16 |
17 | /**
18 | * Binds a header view according to the current item data.
19 | *
20 | * @param headerViewHolder the ViewHolder containing the view to bind
21 | * @param position the current item position
22 | */
23 | void onBindViewHolder(HeaderViewHolder headerViewHolder, int position);
24 |
25 | /**
26 | * Get the header id associated with the specified item position.
27 | *
28 | * @param position the current item position
29 | * @return the header id for the current item
30 | */
31 | long getHeaderId(int position);
32 | }
33 |
--------------------------------------------------------------------------------
/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 /Users/hannes/android-sdks/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 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | -dontwarn com.squareup.okhttp.**
--------------------------------------------------------------------------------
/app/src/droidconBerlin/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/CrashlyticsTimberTree.kt:
--------------------------------------------------------------------------------
1 | package de.droidcon
2 |
3 | import com.crashlytics.android.Crashlytics
4 | import timber.log.Timber
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | class CrashlyticsTimberTree : Timber.Tree() {
12 | override fun log(priority: Int, tag: String?, message: String?, t: Throwable?) {
13 |
14 | if (message != null) {
15 | Crashlytics.log(message)
16 | }
17 |
18 | if (t != null) {
19 | Crashlytics.logException(t)
20 | }
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/DroidconBerlinApp.kt:
--------------------------------------------------------------------------------
1 | package de.droidcon
2 |
3 | import com.crashlytics.android.Crashlytics
4 | import com.openconference.OpenConfApp
5 | import com.openconference.dagger.DaggerApplicationComponent
6 | import com.twitter.sdk.android.Twitter
7 | import com.twitter.sdk.android.core.TwitterAuthConfig
8 | import de.droidcon.dagger.DroidconBerlinNetworkModule
9 | import io.fabric.sdk.android.Fabric
10 | import timber.log.Timber
11 |
12 | /**
13 | *
14 | *
15 | * @author Hannes Dorfmann
16 | */
17 | class DroidconBerlinApp : OpenConfApp() {
18 |
19 |
20 | override fun onCreate() {
21 |
22 | val config = TwitterAuthConfig("API-KEY",
23 | "API-SECRET")
24 | Fabric.with(this, Crashlytics(), Twitter(config));
25 |
26 |
27 | super.onCreate()
28 | }
29 |
30 | override fun buildApplicationComponent(): DaggerApplicationComponent.Builder {
31 | return super.buildApplicationComponent().networkModule(DroidconBerlinNetworkModule(this))
32 | }
33 |
34 | override fun plantProductionTimberTree() {
35 | super.plantProductionTimberTree()
36 | Timber.plant(CrashlyticsTimberTree())
37 |
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/dagger/DroidconBerlinNetworkModule.kt:
--------------------------------------------------------------------------------
1 | package de.droidcon.dagger
2 |
3 | import android.content.Context
4 | import com.github.aurae.retrofit2.LoganSquareConverterFactory
5 | import com.openconference.dagger.NetworkModule
6 | import com.openconference.model.backend.schedule.BackendScheduleAdapter
7 | import de.droidcon.model.backend.DroidconBerlinBackend
8 | import de.droidcon.model.backend.DroidconBerlinBackendScheduleAdapter
9 | import okhttp3.Cache
10 | import okhttp3.OkHttpClient
11 | import retrofit2.Retrofit
12 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
13 |
14 | class DroidconBerlinNetworkModule(context: Context) : NetworkModule(context) {
15 |
16 | private val retrofit: Retrofit
17 | private val okHttp: OkHttpClient
18 | private val backendAdapter: BackendScheduleAdapter
19 | private val backend: DroidconBerlinBackend
20 |
21 | init {
22 | okHttp = OkHttpClient.Builder().cache(Cache(context.cacheDir, 48 * 1024 * 1024))
23 | .build()
24 |
25 | retrofit = Retrofit.Builder()
26 | .client(okHttp)
27 | .baseUrl("http://droidcon.de/rest/")
28 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
29 | .addConverterFactory(LoganSquareConverterFactory.create())
30 | .build()
31 |
32 |
33 | backend = retrofit.create(DroidconBerlinBackend::class.java)
34 |
35 | backendAdapter = DroidconBerlinBackendScheduleAdapter(backend)
36 | }
37 |
38 | override fun provideOkHttp(): OkHttpClient = okHttp
39 |
40 | override fun provideBackendAdapter(): BackendScheduleAdapter = backendAdapter
41 | }
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/model/backend/DroidconBerlinBackend.java:
--------------------------------------------------------------------------------
1 | package de.droidcon.model.backend;
2 |
3 | import java.util.List;
4 | import retrofit2.http.GET;
5 | import rx.Observable;
6 |
7 | /**
8 | * @author Hannes Dorfmann
9 | */
10 | public interface DroidconBerlinBackend {
11 |
12 | @GET("sessions.json") Observable> getSessions();
13 |
14 | @GET("speakers.json") Observable> getSpeakers();
15 |
16 | @GET("rooms.json") Observable> getLocations();
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/model/backend/DroidconBerlinBackendScheduleAdapter.kt:
--------------------------------------------------------------------------------
1 | package de.droidcon.model.backend
2 |
3 | import com.openconference.model.Location
4 | import com.openconference.model.Session
5 | import com.openconference.model.Speaker
6 | import com.openconference.model.backend.schedule.BackendScheduleAdapter
7 | import com.openconference.model.backend.schedule.BackendScheduleResponse
8 | import rx.Observable
9 |
10 | /**
11 | * [BackendScheduleAdapter] for droidcon Berlin backend
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class DroidconBerlinBackendScheduleAdapter(private val backend: DroidconBerlinBackend) : BackendScheduleAdapter {
16 |
17 | override fun getSpeakers(): Observable> =
18 | backend.getSpeakers().map {
19 | BackendScheduleResponse.dataChanged(it as List)
20 | }
21 |
22 | override fun getLocations(): Observable>
23 | = backend.getLocations().map {
24 | BackendScheduleResponse.dataChanged(it as List)
25 | }
26 |
27 | override fun getSessions(): Observable> =
28 | backend.getSessions().map {
29 | BackendScheduleResponse.dataChanged(it as List)
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/model/backend/DroidconBerlinLink.java:
--------------------------------------------------------------------------------
1 | package de.droidcon.model.backend;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import com.bluelinelabs.logansquare.annotation.JsonField;
6 | import com.bluelinelabs.logansquare.annotation.JsonObject;
7 |
8 | /**
9 | * @author Hannes Dorfmann
10 | */
11 | @JsonObject
12 | public class DroidconBerlinLink implements Parcelable{
13 | @JsonField String url;
14 |
15 | @Override public int describeContents() {
16 | return 0;
17 | }
18 |
19 | @Override public void writeToParcel(Parcel dest, int flags) {
20 | dest.writeString(this.url);
21 | }
22 |
23 | public DroidconBerlinLink() {
24 | }
25 |
26 | protected DroidconBerlinLink(Parcel in) {
27 | this.url = in.readString();
28 | }
29 |
30 | public static final Creator CREATOR = new Creator() {
31 | @Override public DroidconBerlinLink createFromParcel(Parcel source) {
32 | return new DroidconBerlinLink(source);
33 | }
34 |
35 | @Override public DroidconBerlinLink[] newArray(int size) {
36 | return new DroidconBerlinLink[size];
37 | }
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/model/backend/DroidconBerlinLocation.java:
--------------------------------------------------------------------------------
1 | package de.droidcon.model.backend;
2 |
3 | import android.os.Parcel;
4 | import com.bluelinelabs.logansquare.annotation.JsonField;
5 | import com.bluelinelabs.logansquare.annotation.JsonObject;
6 | import com.openconference.model.Location;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author Hannes Dorfmann
11 | */
12 | @JsonObject public class DroidconBerlinLocation implements Location {
13 |
14 | @JsonField(name = "title") String name;
15 | @JsonField(name = "nid") String id;
16 |
17 | @NotNull @Override public String name() {
18 | return name;
19 | }
20 |
21 | @NotNull @Override public String id() {
22 | return id;
23 | }
24 |
25 | @Override public int describeContents() {
26 | return 0;
27 | }
28 |
29 | @Override public void writeToParcel(Parcel dest, int flags) {
30 | dest.writeString(this.name);
31 | dest.writeString(this.id);
32 | }
33 |
34 | public DroidconBerlinLocation() {
35 | }
36 |
37 | protected DroidconBerlinLocation(Parcel in) {
38 | this.name = in.readString();
39 | this.id = in.readString();
40 | }
41 |
42 | public static final Creator CREATOR =
43 | new Creator() {
44 | @Override public DroidconBerlinLocation createFromParcel(Parcel source) {
45 | return new DroidconBerlinLocation(source);
46 | }
47 |
48 | @Override public DroidconBerlinLocation[] newArray(int size) {
49 | return new DroidconBerlinLocation[size];
50 | }
51 | };
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/droidconBerlin/java/de/droidcon/model/backend/InstantIsoTypeConverter.kt:
--------------------------------------------------------------------------------
1 | package de.droidcon.model.backend
2 |
3 | import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter
4 | import org.threeten.bp.Instant
5 | import org.threeten.bp.format.DateTimeFormatter
6 |
7 | /**
8 | * Logan Square json parser type converter for Dates ins ISO format
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class InstantIsoTypeConverter : StringBasedTypeConverter() {
13 |
14 | override fun convertToString(o: Instant?): String? = if (o == null) {
15 | null
16 | } else {
17 | val timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
18 | timeFormatter.format(o)
19 |
20 | }
21 |
22 | override fun getFromString(str: String?): Instant? = if (str == null) {
23 | null
24 | } else {
25 | val timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
26 | val accessor = timeFormatter.parse(str);
27 | Instant.from(accessor)
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/droidconBerlin/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | droidcon Berlin
4 |
--------------------------------------------------------------------------------
/app/src/droidconBerlin/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | droidcon Berlin
4 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/Navigator.kt:
--------------------------------------------------------------------------------
1 | package com.openconference
2 |
3 | import com.openconference.model.Session
4 | import com.openconference.model.Speaker
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface Navigator {
12 |
13 | fun showSessions()
14 |
15 | fun showSpeakers()
16 |
17 | fun showSessionDetails(session: Session)
18 |
19 | fun showMySchedule()
20 |
21 | fun showSpeakerDetails(speaker: Speaker)
22 |
23 | fun showSearch()
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/OpenConfApp.kt:
--------------------------------------------------------------------------------
1 | package com.openconference
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import com.jakewharton.threetenabp.AndroidThreeTen
6 | import com.openconference.dagger.*
7 | import timber.log.Timber
8 |
9 | /**
10 | * Custom application mainly to integrate dagger
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | open class OpenConfApp : Application() {
15 |
16 | private lateinit var applicationComponent: ApplicationComponent
17 |
18 | override fun onCreate() {
19 | super.onCreate()
20 | AndroidThreeTen.init(this)
21 | if (BuildConfig.DEBUG) {
22 | plantDebugTimberTree()
23 | } else {
24 | plantProductionTimberTree()
25 | }
26 | applicationComponent = buildApplicationComponent().build()
27 | }
28 |
29 | companion object {
30 | fun getApplicationComponent(context: Context): ApplicationComponent {
31 | val app = context.applicationContext as OpenConfApp
32 | return app.applicationComponent
33 | }
34 | }
35 |
36 | open fun plantDebugTimberTree(){
37 | Timber.plant(Timber.DebugTree())
38 | }
39 |
40 | open fun buildApplicationComponent(): DaggerApplicationComponent.Builder {
41 |
42 | return DaggerApplicationComponent.builder()
43 | .daoModule(DaoModule(this))
44 | .loadersModule(LoadersModule())
45 | .schedulingModule(SchedulingModule())
46 | .networkModule(NetworkModule(this))
47 | .applicationModule(ApplicationModule(this))
48 | .scheduleModule(ScheduleModule(this))
49 | .picassoModule(PicassoModule(this))
50 | }
51 |
52 | /**
53 | * Override this method to use a Timber Tree for production with crashreporting software like crashlytics
54 | */
55 | open fun plantProductionTimberTree() {
56 |
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/PhoneNavigator.kt:
--------------------------------------------------------------------------------
1 | package com.openconference
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import com.openconference.main.ViewPagerMainActivity
6 | import com.openconference.model.Session
7 | import com.openconference.model.Speaker
8 | import com.openconference.model.screen.SessionsScreen
9 | import com.openconference.search.SearchActivity
10 | import com.openconference.sessiondetails.SessionDetailsActivity
11 | import com.openconference.sessiondetails.SpeakerDetailsActivity
12 |
13 | /**
14 | * A Navigator that is responsible to navigate between the different screens
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | // TODO Tablet Navigator
19 | class PhoneNavigator(private val activity: Activity) : Navigator {
20 |
21 | override fun showSessionDetails(session: Session) {
22 | val i = SessionDetailsActivity.buildIntent(activity, session)
23 | activity.startActivity(i)
24 | }
25 |
26 | override fun showMySchedule() {
27 | throw UnsupportedOperationException()
28 | }
29 |
30 | override fun showSpeakerDetails(speaker: Speaker) {
31 | val i = Intent(activity, SpeakerDetailsActivity::class.java)
32 | i.putExtra(SpeakerDetailsActivity.KEY_SPEAKER, speaker)
33 | activity.startActivity(i)
34 | }
35 |
36 | override fun showSessions() = if (activity is ViewPagerMainActivity) {
37 | activity.jumpToScreen({ it is SessionsScreen })
38 | } else throw UnsupportedOperationException("Oops, something in Navigation is not setup properly")
39 |
40 | override fun showSpeakers() {
41 | throw UnsupportedOperationException()
42 | }
43 |
44 | override fun showSearch() {
45 | val i = Intent(activity, SearchActivity::class.java)
46 | activity.startActivity(i)
47 | activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/ApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.openconference.model.ScheduleDataAwareObservableFactory
5 | import com.openconference.model.SessionsLoader
6 | import com.openconference.model.SpeakersLoader
7 | import com.openconference.model.database.dao.SessionDao
8 | import com.openconference.model.errormessage.ErrorMessageDeterminer
9 | import com.openconference.model.notification.NotificationScheduler
10 | import com.openconference.model.search.SearchEngine
11 | import com.openconference.util.SchedulerTransformer
12 | import com.squareup.picasso.Picasso
13 | import dagger.Component
14 | import javax.inject.Singleton
15 |
16 | /**
17 | * A Dagger component providing application wide dependencies
18 | * @author Hannes Dorfmann
19 | */
20 | @Component(modules = arrayOf(ApplicationModule::class))
21 | interface ApplicationComponent {
22 |
23 | fun schedulerTransformer(): SchedulerTransformer
24 |
25 | fun scheduleDataAwareObservableFactory(): ScheduleDataAwareObservableFactory
26 |
27 | fun sessionLoader(): SessionsLoader
28 |
29 | fun speakersLoader(): SpeakersLoader
30 |
31 | fun sessionDao(): SessionDao
32 |
33 | fun errorMessageDeterminer(): ErrorMessageDeterminer
34 |
35 | fun picasso(): Picasso
36 |
37 | fun notificationScheduler(): NotificationScheduler
38 |
39 | fun searchEngine(): SearchEngine
40 |
41 | @ApplicationContext
42 | fun applicationContext(): Context
43 |
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/ApplicationContext.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import javax.inject.Named
4 |
5 | /**
6 | * This indicates that the annotated Context is an ApplicationContext
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Named
11 | annotation class ApplicationContext
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/ApplicationModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.openconference.model.backend.schedule.BackendScheduleAdapter
5 | import com.openconference.model.backend.schedule.ScheduleSync
6 | import com.openconference.model.database.dao.LocationDao
7 | import com.openconference.model.database.dao.SessionDao
8 | import com.openconference.model.database.dao.SpeakerDao
9 | import com.openconference.model.notification.NotificationScheduler
10 | import dagger.Module
11 | import dagger.Provides
12 | import javax.inject.Singleton
13 |
14 | /**
15 | *
16 | *
17 | * @author Hannes Dorfmann
18 | */
19 | @Module(includes = arrayOf(
20 | DaoModule::class,
21 | LoadersModule::class,
22 | SchedulingModule::class,
23 | NetworkModule::class,
24 | ScheduleModule::class,
25 | ErrorMessageModule::class,
26 | PicassoModule::class,
27 | SearchModule::class)
28 | )
29 | class ApplicationModule(c: Context) {
30 |
31 | private val applicationContext = c.applicationContext
32 |
33 | @Provides
34 | @Singleton
35 | fun provideScheduleSync(backend: BackendScheduleAdapter,
36 | notificationScheduler: NotificationScheduler,
37 | sessionDao: SessionDao,
38 | speakerDao: SpeakerDao,
39 | locationDao: LocationDao) = ScheduleSync(backend, notificationScheduler, sessionDao,
40 | speakerDao, locationDao)
41 |
42 | @Provides
43 | @Singleton
44 | @ApplicationContext
45 | fun provideApplicationContext() = applicationContext
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/DaoModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.hannesdorfmann.sqlbrite.dao.DaoManager
5 | import com.openconference.model.database.dao.*
6 | import dagger.Module
7 | import dagger.Provides
8 | import javax.inject.Singleton
9 |
10 | /**
11 | * Module providing DAO's
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | @Module
16 | @Singleton
17 | class DaoModule(context: Context) {
18 |
19 |
20 | private val sessionDao: SessionDao
21 | private val speakerDao: SpeakerDao
22 | private val locationDao: LocationDao
23 |
24 | init {
25 |
26 | // DAO's
27 | sessionDao = SessionDaoSqlite()
28 | speakerDao = SpeakerDaoSqlite()
29 | locationDao = LocationDaoSqlite()
30 | DaoManager.with(context.applicationContext)
31 | .add(sessionDao)
32 | .add(speakerDao)
33 | .add(locationDao)
34 | .version(1)
35 | .databaseName("schedule.db")
36 | .build()
37 | }
38 |
39 | @Provides
40 | @Singleton
41 | fun provideSessionDao() = sessionDao
42 |
43 | @Provides
44 | @Singleton
45 | fun provideSpeakerDao() = speakerDao
46 |
47 | @Provides
48 | @Singleton
49 | fun provideLocationDao() = locationDao
50 |
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/ErrorMessageModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import com.openconference.model.errormessage.DefaultErrorMessageDeterminer
4 | import com.openconference.model.errormessage.ErrorMessageDeterminer
5 | import dagger.Module
6 | import dagger.Provides
7 | import javax.inject.Singleton
8 |
9 | /**
10 | * Dagger module for Error Message
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | @Module
15 | class ErrorMessageModule {
16 |
17 | @Provides
18 | @Singleton
19 | fun provideErrorMessageDeterminer() : ErrorMessageDeterminer = DefaultErrorMessageDeterminer()
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/LoadersModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import com.openconference.model.*
4 | import com.openconference.model.backend.schedule.ScheduleDataStateDeterminer
5 | import com.openconference.model.backend.schedule.ScheduleSync
6 | import com.openconference.model.database.dao.SessionDao
7 | import com.openconference.model.database.dao.SpeakerDao
8 | import com.openconference.model.notification.NotificationScheduler
9 | import dagger.Module
10 | import dagger.Provides
11 | import rx.schedulers.Schedulers
12 | import javax.inject.Singleton
13 |
14 | /**
15 | *
16 | *
17 | * @author Hannes Dorfmann
18 | */
19 | @Module
20 | class LoadersModule {
21 |
22 | @Provides
23 | @Singleton
24 | fun providesScheduleDataAwareObservableFactory(scheduleSync: ScheduleSync,
25 | scheduleDataStateDeterminer: ScheduleDataStateDeterminer) =
26 | ScheduleDataAwareObservableFactory(scheduleSync, scheduleDataStateDeterminer, Schedulers.io())
27 |
28 | @Provides
29 | @Singleton
30 | fun providesSessionLoader(factory: ScheduleDataAwareObservableFactory,
31 | sessionDao: SessionDao,
32 | notificationScheduler: NotificationScheduler): SessionsLoader = LocalStorageSessionsLoader(
33 | factory, sessionDao, notificationScheduler)
34 |
35 | @Provides
36 | @Singleton
37 | fun provideSpeakersLoader(factory: ScheduleDataAwareObservableFactory,
38 | speakerDao: SpeakerDao): SpeakersLoader = LocalStorageSpeakersLoader(factory, speakerDao)
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/NetworkModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.openconference.model.backend.schedule.BackendScheduleAdapter
5 | import dagger.Module
6 | import dagger.Provides
7 | import okhttp3.Cache
8 | import okhttp3.OkHttpClient
9 | import javax.inject.Singleton
10 |
11 | /**
12 | * @author Hannes Dorfmann
13 | */
14 | @Module
15 | open class NetworkModule(c: Context) {
16 |
17 | protected val context: Context
18 | protected val okHttpClient: OkHttpClient
19 |
20 | init {
21 | context = c.applicationContext
22 | okHttpClient = OkHttpClient.Builder()
23 | .cache(Cache(context.cacheDir, 48 * 1024 * 1024))
24 | .build()
25 | }
26 |
27 | @Provides
28 | @Singleton
29 | open fun provideOkHttp() = okHttpClient
30 |
31 | @Provides
32 | @Singleton
33 | open fun provideBackendAdapter(): BackendScheduleAdapter =
34 | throw UnsupportedOperationException(
35 | "Every Build Flavor / conference app has to provide his own BackendAdpater")
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/PicassoModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.jakewharton.picasso.OkHttp3Downloader
5 | import com.squareup.picasso.Picasso
6 | import dagger.Module
7 | import dagger.Provides
8 | import okhttp3.OkHttpClient
9 | import javax.inject.Singleton
10 |
11 | /**
12 | *
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | @Module
17 | class PicassoModule(c: Context) {
18 |
19 | private val context = c.applicationContext
20 |
21 | @Singleton
22 | @Provides
23 | fun providePicasso(okhttp: OkHttpClient) =
24 | Picasso.Builder(context).downloader(OkHttp3Downloader(okhttp)).build()
25 |
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/ScheduleModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.openconference.model.backend.schedule.ScheduleDataStateDeterminer
5 | import com.openconference.model.backend.schedule.TimebaseScheduleDataStateDeterminer
6 | import com.openconference.model.notification.DefaultNotificationScheduler
7 | import com.openconference.model.notification.NotificationScheduler
8 | import dagger.Module
9 | import dagger.Provides
10 | import javax.inject.Singleton
11 |
12 | /**
13 | *
14 | * Provides some things related to the conferences schedule
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | @Module
19 | open class ScheduleModule(c: Context) {
20 |
21 | protected val context: Context = c.applicationContext
22 |
23 | @Provides
24 | @Singleton
25 | fun provideScheduleDataStateDeterminer(): ScheduleDataStateDeterminer {
26 | val sharedPrefs = context.getSharedPreferences("TimebaseScheduleDeterminer",
27 | Context.MODE_PRIVATE)
28 | return TimebaseScheduleDataStateDeterminer(sharedPrefs)
29 | }
30 |
31 | @Provides
32 | @Singleton
33 | fun provideNotificationScheduler(): NotificationScheduler = DefaultNotificationScheduler(context)
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/SchedulingModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import com.openconference.util.DefaultSchedulerTransformer
4 | import com.openconference.util.SchedulerTransformer
5 | import dagger.Module
6 | import dagger.Provides
7 | import javax.inject.Singleton
8 |
9 | /**
10 | * Dagger Module providing Threading and Scheduling related stuff
11 | * @author Hannes Dorfmann
12 | */
13 | @Module
14 | class SchedulingModule() {
15 |
16 | @Provides
17 | @Singleton
18 | fun provideSchedulerTransformer() :SchedulerTransformer = DefaultSchedulerTransformer()
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/dagger/SearchModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.dagger
2 |
3 | import android.content.Context
4 | import com.openconference.R
5 | import com.openconference.model.ScheduleDataAwareObservableFactory
6 | import com.openconference.model.database.dao.SessionDao
7 | import com.openconference.model.database.dao.SpeakerDao
8 | import com.openconference.model.search.DefaultSearchEngine
9 | import com.openconference.model.search.SearchEngine
10 | import com.openconference.model.search.SearchSource
11 | import com.openconference.model.search.source.LocalStorageSessionsSearchSource
12 | import com.openconference.model.search.source.LocalStorageSpeakersSearchSource
13 | import com.openconference.sessions.presentationmodel.PhoneSessionPresentationModelTransformer
14 | import dagger.Module
15 | import dagger.Provides
16 | import javax.inject.Singleton
17 |
18 | /**
19 | *
20 | *
21 | * @author Hannes Dorfmann
22 | */
23 | @Module
24 | class SearchModule {
25 |
26 |
27 | data class SearchSources(val sources: List)
28 |
29 | @Provides
30 | @Singleton
31 | fun provideSearchSources(
32 | @ApplicationContext context: Context,
33 | awareObservableFactory: ScheduleDataAwareObservableFactory,
34 | sessionDao: SessionDao, speakerDao: SpeakerDao) = SearchSources(
35 | listOf(
36 | LocalStorageSessionsSearchSource(awareObservableFactory, sessionDao,
37 | PhoneSessionPresentationModelTransformer(context.getString(
38 | R.string.sessions_sticky_date_format))),
39 | LocalStorageSpeakersSearchSource(awareObservableFactory, speakerDao)))
40 |
41 | @Provides
42 | @Singleton
43 | fun provideSearchEngine(searchSources: SearchSources): SearchEngine = DefaultSearchEngine(
44 | searchSources.sources)
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/main/MainActivityComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.main
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import dagger.Component
5 |
6 | /**
7 | * Dagger Component for
8 | * @author Hannes Dorfmann
9 | */
10 | @Component (
11 | modules = arrayOf(MainActivityModule::class), dependencies = arrayOf(ApplicationComponent::class))
12 | @MainActivityScope
13 | interface MainActivityComponent {
14 | fun inject(activity: ViewPagerMainActivity)
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/main/MainActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.main
2 |
3 | import android.app.Activity
4 | import com.openconference.Navigator
5 | import com.openconference.PhoneNavigator
6 | import com.openconference.model.screen.*
7 | import dagger.Module
8 | import dagger.Provides
9 |
10 | /**
11 | *
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | @Module
16 | class MainActivityModule(private val activity: Activity) {
17 |
18 | @Provides
19 | @MainActivityScope
20 | fun provideScreens(): Screens = Screens(listOf(SessionsScreen(), MyScheduleScreen(),
21 | SpeakersScreen(), TwitterScreen()))
22 |
23 | @Provides
24 | @MainActivityScope
25 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/main/MainActivityScope.java:
--------------------------------------------------------------------------------
1 | package com.openconference.main;
2 |
3 | import javax.inject.Scope;
4 |
5 | /**
6 | * @author Hannes Dorfmann
7 | */
8 | @Scope public @interface MainActivityScope {
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/main/MainScreensPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.main
2 |
3 | import android.graphics.Rect
4 | import android.support.v4.app.Fragment
5 | import android.support.v4.app.FragmentStatePagerAdapter
6 | import android.support.v4.content.ContextCompat
7 | import android.support.v7.app.AppCompatActivity
8 | import android.text.Spannable
9 | import android.text.SpannableString
10 | import android.text.style.ImageSpan
11 | import com.openconference.model.screen.*
12 | import com.openconference.sessions.MyScheduleFragmentBuilder
13 | import com.openconference.sessions.SessionsFragmentBuilder
14 | import com.openconference.sessions.SpeakersFragmentBuilder
15 | import com.openconference.twitter.TwitterTimelineFragmentBuilder
16 |
17 | /**
18 | * ViewPagerAdapter for MainScreens
19 | * @author Hannes Dorfmann
20 | */
21 | open class MainScreensPagerAdapter(private val activity: AppCompatActivity, private val screens: List) : FragmentStatePagerAdapter(
22 | activity.supportFragmentManager) {
23 |
24 |
25 | override fun getItem(position: Int): Fragment = when (screens[position]) {
26 | is SessionsScreen -> SessionsFragmentBuilder().build()
27 | is MyScheduleScreen -> MyScheduleFragmentBuilder().build()
28 | is SpeakersScreen -> SpeakersFragmentBuilder().build()
29 | is TwitterScreen -> TwitterTimelineFragmentBuilder().build()
30 | else -> throw IllegalArgumentException("Unknown type for screen at position $position")
31 | }
32 |
33 | override fun getCount(): Int = screens.size
34 |
35 | override fun getPageTitle(position: Int): CharSequence? {
36 |
37 | val image = ContextCompat.getDrawable(activity, screens[position].iconRes())
38 | image.bounds = Rect(0, 0, image.intrinsicWidth, image.intrinsicHeight)
39 | val sb = SpannableString(" ") // TODO tablet layout
40 | val imageSpan = ImageSpan(image, ImageSpan.ALIGN_BOTTOM)
41 | sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
42 | return sb
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/Location.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model
2 |
3 | import android.os.Parcelable
4 | import com.openconference.model.database.dao.LocationDaoSqlite
5 | import com.gabrielittner.auto.value.cursor.ColumnName
6 |
7 | /**
8 | * Represents a location where a session takes place
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | interface Location : Parcelable {
13 |
14 | /**
15 | * The id of the location
16 | */
17 | fun id(): String
18 |
19 | /**
20 | * The name of the location
21 | */
22 | fun name(): String
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/Session.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model
2 |
3 | import android.os.Parcelable
4 | import android.support.annotation.NonNull
5 | import android.support.annotation.Nullable
6 | import org.threeten.bp.Instant
7 |
8 | /**
9 | *
10 | * Contains the description of a Session
11 | * @author Hannes Dorfmann
12 | */
13 | interface Session : Parcelable {
14 |
15 | /**
16 | * The session id
17 | */
18 | @NonNull
19 | fun id(): String
20 |
21 | /**
22 | * The title of the sessions
23 | */
24 | @Nullable
25 | fun title(): String?
26 |
27 | /**
28 | * The description of the speaker
29 | */
30 | @Nullable
31 | fun description(): String?
32 |
33 | /**
34 | * Optional tags for this session
35 | */
36 | @Nullable
37 | fun tags(): String?
38 |
39 | /**
40 | * The location id
41 | */
42 | @Nullable fun locationId(): String?
43 |
44 | /**
45 | * The location name
46 | */
47 | @Nullable fun locationName(): String?
48 |
49 | /**
50 | * Start date / time
51 | */
52 | @Nullable
53 | fun startTime(): Instant?
54 |
55 | /**
56 | * End date / time
57 | */
58 | @Nullable
59 | fun endTime(): Instant?
60 |
61 | @Nullable
62 | fun speakers(): List
63 |
64 | /**
65 | * Specifies whether or not this seesion has been marked by the user of the app as his favorite
66 | * which means it will be display in the users personal schedule.
67 | */
68 | @NonNull
69 | fun favorite(): Boolean
70 |
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/Speaker.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model
2 |
3 | import android.os.Parcelable
4 | import android.support.annotation.NonNull
5 | import android.support.annotation.Nullable
6 |
7 | /**
8 | * Represents an Speaker
9 | * @author Hannes Dorfmann
10 | */
11 | interface Speaker : Parcelable {
12 |
13 | @NonNull
14 | fun id(): String
15 |
16 | /**
17 | * The full name of the speaker
18 | */
19 | @NonNull
20 | fun name(): String
21 |
22 | /**
23 | * The bio / info about the speaker
24 | */
25 | @Nullable
26 | fun info(): String ?
27 |
28 | /**
29 | * The company's name the speaker is working for
30 | */
31 | @Nullable
32 | fun company(): String?
33 |
34 | /**
35 | * The job title / role in the company
36 | */
37 | @Nullable
38 | fun jobTitle(): String?
39 |
40 | /**
41 | * The first link i.e. link to twitter profile of the speaker
42 | */
43 | @Nullable
44 | fun link1(): String?
45 |
46 | /**
47 | * The second link i.e. link to Google+ profile
48 | */
49 | @Nullable
50 | fun link2(): String ?
51 |
52 | /**
53 | * The third link i.e. to personal website / blog
54 | */
55 | @Nullable
56 | fun link3(): String?
57 |
58 | /**
59 | * The url to the profile picture of this speaker
60 | */
61 | @Nullable
62 | fun profilePic(): String?
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/SpeakerNotFoundException.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model
2 |
3 | /**
4 | * Indicates that a certain speaker has not been found.
5 | *
6 | * @author Hannes Dorfmann
7 | */
8 | class SpeakerNotFoundException(msg: String) : Exception(msg)
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/SpeakersLoader.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model
2 |
3 | import com.openconference.model.database.dao.SpeakerDao
4 | import rx.Observable
5 |
6 | /**
7 | * Responsible to load Speakers
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SpeakersLoader {
12 |
13 | /**
14 | * Get a list of all speakers
15 | */
16 | fun allSpeakers(): Observable>
17 |
18 | fun getSpeaker(id: String): Observable
19 | }
20 |
21 | /**
22 | * A [SpeakersLoader] that uses the speakers from local database
23 | */
24 | class LocalStorageSpeakersLoader(private val scheduleDataAwareObservableFactory: ScheduleDataAwareObservableFactory, private val speakerDao: SpeakerDao) : SpeakersLoader {
25 |
26 | override fun allSpeakers(): Observable> = scheduleDataAwareObservableFactory.create(
27 | speakerDao.getSpeakers())
28 |
29 | override fun getSpeaker(id: String): Observable =
30 | scheduleDataAwareObservableFactory.create(
31 | speakerDao.getSpeaker(id)).map {
32 | if (it == null) throw SpeakerNotFoundException(
33 | "Speaker with the id = $id has not been found in database")
34 | else it
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/backend/schedule/BackendScheduleAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.backend.schedule
2 |
3 | import com.openconference.model.Location
4 | import com.openconference.model.Session
5 | import com.openconference.model.Speaker
6 | import rx.Observable
7 |
8 | /**
9 | * API to communicate with the backend. This is where you have to communicate with
10 | * your conferences backend
11 | * @author Hannes Dorfmann
12 | */
13 | interface BackendScheduleAdapter {
14 |
15 | /**
16 | * Get a list of all Speakers
17 | */
18 | fun getSpeakers(): Observable>
19 |
20 | /**
21 | * Get a list of all locations where sessions will be heldt
22 | */
23 | fun getLocations(): Observable>
24 |
25 | /**
26 | * Get list of all sessions
27 | */
28 | fun getSessions(): Observable>
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/backend/schedule/BackendScheduleResponse.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.backend.schedule
2 |
3 | /**
4 | * This data structure will be retuned from
5 | *
6 | * @author Hannes Dorfmann
7 | */
8 | data class BackendScheduleResponse private constructor(val isNewerDataAvailable: Boolean, val data: List) {
9 |
10 | companion object {
11 | fun nothingChanged() = BackendScheduleResponse(false, emptyList())
12 |
13 | fun dataChanged(data: List) = BackendScheduleResponse(true, data)
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/backend/schedule/ScheduleDataStateDeterminer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.backend.schedule
2 |
3 | import rx.Observable
4 |
5 | /**
6 | * Determine the state of the schedule.
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface ScheduleDataStateDeterminer {
11 |
12 | /**
13 | * Enum representing whether or not [ScheduleSync] should running or not
14 | */
15 | enum class ScheduleDataState {
16 |
17 | /**
18 | * Syncing has to be executed right now, before continue with the rest of your data flow
19 | */
20 | NO_DATA,
21 | /**
22 | * Schedule data is available. That data might not be up-to-date (stale data) but can be used
23 | * in the mean time i.e. to display the schedule in the UI, while starting a refresh in the
24 | * background
25 | */
26 | RUN_BACKGROUND_SYNC,
27 |
28 | /**
29 | * Schedule data is up to date. Running sync is not needed.
30 | */
31 | UP_TO_DATE
32 | }
33 |
34 |
35 | /**
36 | * Determine the current state of the schedule sync data
37 | */
38 | fun getScheduleSyncDataState(): Observable
39 |
40 | /**
41 | * Marks that the schedule has been run successfully
42 | */
43 | fun markScheduleSyncedSuccessful(): Observable
44 |
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/backend/schedule/TimebaseScheduleDataStateDeterminer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.backend.schedule
2 |
3 | import android.content.SharedPreferences
4 | import org.threeten.bp.Instant
5 | import rx.Observable
6 |
7 | /**
8 | * This [TimebaseScheduleDataStateDeterminer] basically says that every two hours a sync will run in background
9 | * @author Hannes Dorfmann
10 | */
11 | class TimebaseScheduleDataStateDeterminer(private val sharedPrefs: SharedPreferences, private val runAfter: Long = 2 * 3600 * 1000) : ScheduleDataStateDeterminer {
12 |
13 | companion object {
14 | val KEY_LAST_SYNC = "lastSync"
15 | val KEY_RUN_AT_LEAST_ONCE = "atLeastOnce"
16 | }
17 |
18 | override fun getScheduleSyncDataState(): Observable =
19 | Observable.fromCallable {
20 | val atLeastOnce = sharedPrefs.getBoolean(KEY_RUN_AT_LEAST_ONCE, false)
21 |
22 | if (!atLeastOnce) {
23 | ScheduleDataStateDeterminer.ScheduleDataState.NO_DATA
24 | } else {
25 | val lastSyncMS = sharedPrefs.getLong(KEY_LAST_SYNC, 0)
26 | val lastSync = Instant.ofEpochMilli(lastSyncMS)
27 | val currentTime = currentTime()
28 | val expiresAt = lastSync.plusMillis(runAfter)
29 | if (expiresAt.isAfter(currentTime)) {
30 | ScheduleDataStateDeterminer.ScheduleDataState.UP_TO_DATE
31 | } else {
32 | ScheduleDataStateDeterminer.ScheduleDataState.RUN_BACKGROUND_SYNC
33 | }
34 | }
35 |
36 | }
37 |
38 | override fun markScheduleSyncedSuccessful(): Observable =
39 | Observable.fromCallable {
40 | sharedPrefs.edit()
41 | .putBoolean(KEY_RUN_AT_LEAST_ONCE, true)
42 | .putLong(KEY_LAST_SYNC, currentTime().toEpochMilli())
43 | .commit()
44 | }
45 |
46 | fun currentTime() = Instant.now()
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/EndTimeInstantCursorAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import android.database.Cursor
4 | import com.openconference.model.database.dao.SessionDaoSqlite
5 | import org.threeten.bp.Instant
6 |
7 | /**
8 | * A auto-value-cursor CursorAdapter
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class EndTimeInstantCursorAdapter {
13 |
14 | companion object {
15 | @JvmStatic
16 | fun createFromCursor(c: Cursor): Instant? {
17 | val index = c.getColumnIndex(SessionDaoSqlite.COL_END_TIME)
18 | return if (index >= 0) {
19 | if (c.isNull(index)) {
20 | null
21 | } else {
22 | Instant.ofEpochMilli(c.getLong(index))
23 | }
24 | } else null
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/InstantParcelableTypeAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import android.os.Parcel
4 | import com.ryanharter.auto.value.parcel.TypeAdapter
5 | import org.threeten.bp.Instant
6 |
7 | /**
8 | * A TypeAdapter for Auto-Value parcelable plugin
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class InstantParcelableTypeAdapter : TypeAdapter {
13 |
14 | private val NULL_VALUE = -1L;
15 |
16 | override fun toParcel(value: Instant?, dest: Parcel) {
17 | if (value == null)
18 | dest.writeLong(NULL_VALUE)
19 | else
20 | dest.writeLong(value.toEpochMilli())
21 | }
22 |
23 | override fun fromParcel(parcel: Parcel): Instant? {
24 | val ms = parcel.readLong()
25 | return if (ms == NULL_VALUE)
26 | null
27 | else
28 | Instant.ofEpochMilli(ms)
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/LocationAutoValue.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import android.content.ContentValues
4 | import android.database.Cursor
5 | import com.openconference.model.Location
6 | import com.openconference.model.database.dao.LocationDaoSqlite
7 | import com.gabrielittner.auto.value.cursor.ColumnName
8 | import com.google.auto.value.AutoValue
9 | import rx.functions.Func1
10 |
11 | /**
12 | * A [Location] implementation with AutoValue
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | @AutoValue
17 | abstract class LocationAutoValue : Location {
18 |
19 | @ColumnName(LocationDaoSqlite.COL_ID)
20 | override abstract fun id(): String
21 |
22 | @ColumnName(LocationDaoSqlite.COL_NAME)
23 | override abstract fun name(): String
24 |
25 | abstract fun toContentValues(): ContentValues
26 |
27 | companion object {
28 | @JvmStatic
29 | fun mapper(): Func1 =
30 | AutoValue_LocationAutoValue.MAPPER
31 |
32 | fun create(id: String, name: String): LocationAutoValue = AutoValue_LocationAutoValue(id, name)
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/SessionDateTimeComparator.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import com.openconference.model.Session
4 | import java.util.*
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | class SessionDateTimeComparator : Comparator {
12 |
13 | override fun compare(lhs: Session, rhs: Session): Int {
14 |
15 | if (lhs.startTime() == null && rhs.startTime() == null) {
16 | return 0
17 | }
18 |
19 | if (lhs.startTime() == null && rhs.startTime() != null){
20 | return 1
21 | }
22 |
23 | if (lhs.startTime() != null && rhs.startTime() == null){
24 | return -1
25 | }
26 |
27 |
28 | val dateComparisonResult = lhs.startTime()!!.compareTo(rhs.startTime())
29 | if (dateComparisonResult != 0){
30 | return dateComparisonResult
31 | }
32 |
33 | val lhsLocationName = lhs.locationName()
34 | val rhsLocationName = rhs.locationName()
35 |
36 | if (lhsLocationName == null && rhsLocationName == null){
37 | return 0
38 | }
39 |
40 |
41 | if (lhsLocationName == null && rhsLocationName != null){
42 | return 1
43 | }
44 |
45 | if (lhsLocationName != null && rhsLocationName == null){
46 | return -1
47 | }
48 |
49 | return lhsLocationName!!.compareTo(rhsLocationName!!)
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/StartTimeInstantCursorAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import android.database.Cursor
4 | import com.openconference.model.database.dao.SessionDaoSqlite
5 | import org.threeten.bp.Instant
6 |
7 | /**
8 | * A auto-value-cursor CursorAdapter
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class StartTimeInstantCursorAdapter {
13 |
14 | companion object {
15 | @JvmStatic
16 | fun createFromCursor(c: Cursor): Instant? {
17 | val index = c.getColumnIndex(SessionDaoSqlite.COL_START_TIME)
18 | return if (index >= 0) {
19 | if (c.isNull(index)) {
20 | null
21 | } else {
22 | Instant.ofEpochMilli(c.getLong(index))
23 | }
24 | } else null
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/dao/LocationDao.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database.dao
2 |
3 | import com.openconference.model.Location
4 | import rx.Observable
5 |
6 | /**
7 | * Data-Access-Object for [com.droidcon.model.Location]
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface LocationDao {
12 |
13 | /**
14 | * Get all locations
15 | */
16 | fun getLocations(): Observable>
17 |
18 | /**
19 | * Get a location by id
20 | */
21 | fun getById(id: String): Observable
22 |
23 | /**
24 | * Insert or update a location
25 | */
26 | fun insertOrUpdate(id: String, name: String): Observable
27 |
28 | /**
29 | * Removes a location
30 | */
31 | fun remove(id: String): Observable
32 |
33 | /**
34 | * Removes all locations
35 | */
36 | fun removeAll(): Observable
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/dao/LocationDaoSqlite.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database.dao
2 |
3 | import android.database.sqlite.SQLiteDatabase
4 | import com.openconference.model.Location
5 | import com.openconference.model.database.LocationAutoValue
6 | import com.hannesdorfmann.sqlbrite.dao.Dao
7 | import rx.Observable
8 |
9 | /**
10 | * DAO implementation that uses SqlBrite
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | open class LocationDaoSqlite : LocationDao, Dao() {
15 |
16 | companion object {
17 | const val TABLE = "Location"
18 | const val COL_ID = "id"
19 | const val COL_NAME = "name"
20 | }
21 |
22 |
23 | override fun createTable(database: SQLiteDatabase) {
24 | CREATE_TABLE(TABLE,
25 | "$COL_ID VARCHAR(20) PRIMARY KEY",
26 | "$COL_NAME TEXT NOT NULL")
27 | .execute(database)
28 |
29 | }
30 |
31 | override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
32 |
33 | }
34 |
35 | override fun getLocations(): Observable> =
36 | query(
37 | SELECT(COL_ID, COL_NAME).FROM(TABLE)
38 | ).run()
39 | .mapToList(LocationAutoValue.mapper())
40 | .map { it as List }
41 |
42 | override fun getById(id: String): Observable {
43 | throw UnsupportedOperationException()
44 | }
45 |
46 | override fun insertOrUpdate(id: String, name: String): Observable
47 | = insert(TABLE, LocationAutoValue.create(id, name).toContentValues(),
48 | SQLiteDatabase.CONFLICT_REPLACE)
49 |
50 | override fun remove(id: String): Observable = delete(TABLE, "$COL_ID = ?", id)
51 |
52 | override fun removeAll(): Observable = delete(TABLE)
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/dao/SessionDao.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database.dao
2 |
3 | import com.openconference.model.Session
4 | import com.squareup.sqlbrite.BriteDatabase
5 | import rx.Observable
6 |
7 | /**
8 | * Data-Access-Object for [com.droidcon.model.Session]
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | interface SessionDao {
13 |
14 | /**
15 | * Get the list with all sessions
16 | */
17 | fun getSessions(): Observable>
18 |
19 | /**
20 | * Get a single session by his id
21 | */
22 | fun getById(id: String): Observable
23 |
24 | /**
25 | * Insert or update a Session
26 | */
27 | fun insertOrUpdate(session: Session, favorite: Boolean): Observable
28 |
29 | /**
30 | * Removes a session
31 | * @return Observable with the number of deleted Items (should be 1 or 0)
32 | */
33 | fun remove(id: String): Observable
34 |
35 | /**
36 | * Removes all sessions
37 | * @return Observable with the number of deleted sessions
38 | */
39 | fun removeAll(): Observable
40 |
41 | /**
42 | * See [Session.favorite]
43 | */
44 | fun setFavorite(sessionId: String, favorite: Boolean): Observable
45 |
46 | /**
47 | * Get all sessions given by a speaker
48 | */
49 | fun getSessionsOfSpeaker(speakerId: String): Observable>
50 |
51 | /**
52 | * Get a list with all sessions marked as favorite
53 | */
54 | fun getFavoriteSessions(): Observable>
55 |
56 | /**
57 | * Find sessions containing the specified query
58 | */
59 | fun findSessionsWith(query: String): Observable>
60 |
61 | // TODO refactor that
62 | fun getBriteDatabase(): BriteDatabase
63 |
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/database/dao/SpeakerDao.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database.dao
2 |
3 | import com.openconference.model.Speaker
4 | import rx.Observable
5 |
6 | /**
7 | * Data-Access-Object for [com.droidcon.model.Speaker]
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SpeakerDao {
12 |
13 | /**
14 | * Insert or update a given Speaker
15 | */
16 | fun insertOrUpdate(id: String, name: String,
17 | info: String?, profilePicUrl: String?, company: String?,
18 | jobTitle: String?, link1: String?, link2: String?, link3: String?): Observable
19 |
20 | /**
21 | * Remove a speaker
22 | * @return Observable containing the number of deleted speakers (should be 1 or 0)
23 | */
24 | fun remove(id: String): Observable
25 |
26 | /**
27 | * Removes all speakers
28 | * @return Observable containing the number of deleted speakers
29 | */
30 | fun removeAll(): Observable
31 |
32 | /**
33 | * Get a given Speaker by his id
34 | */
35 | fun getSpeaker(id: String): Observable
36 |
37 | /**
38 | * Get all speakers
39 | */
40 | fun getSpeakers(): Observable>
41 |
42 | /**
43 | * Find speakers that match the following criteria
44 | */
45 | fun findSessionsWith(query: String): Observable>
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/errormessage/DefaultErrorMessageDeterminer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.errormessage
2 |
3 | import com.openconference.R
4 |
5 | /**
6 | * The default error message determiner
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class DefaultErrorMessageDeterminer : ErrorMessageDeterminer {
11 |
12 | override fun getErrorMessageRes(t: Throwable): Int = R.string.error_unknown
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/errormessage/ErrorMessageDeterminer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.errormessage
2 |
3 | import android.support.annotation.StringRes
4 |
5 | /**
6 | * Responsible to determine the error message for a given error
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface ErrorMessageDeterminer {
11 |
12 | @StringRes
13 | fun getErrorMessageRes(t : Throwable) : Int
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/notification/NotificationBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.notification
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.support.v4.content.WakefulBroadcastReceiver
6 | import timber.log.Timber
7 |
8 | /**
9 | *
10 | *
11 | * @author Hannes Dorfmann
12 | */
13 | class NotificationBroadcastReceiver : WakefulBroadcastReceiver() {
14 |
15 | companion object {
16 | val SESSION_ID = "NotificationBroadcastReceiver.SESSION_ID"
17 | }
18 |
19 | override fun onReceive(context: Context, intent: Intent) {
20 |
21 | val sessionId = intent.getStringExtra(SESSION_ID)
22 | Timber.d("onReceive() $sessionId")
23 |
24 | val serviceIntent = Intent(context, NotificationBuilderIntentService::class.java)
25 | serviceIntent.putExtra(NotificationBuilderIntentService.KEY_SESSION_ID, sessionId)
26 |
27 | startWakefulService(context, serviceIntent);
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/notification/NotificationScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.notification
2 |
3 | import com.openconference.model.Session
4 |
5 | /**
6 | * Responsible to interact with the android systems AlarmManager to schedule Notifications
7 | * to be shown before the session starts.
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface NotificationScheduler {
12 |
13 | /**
14 | * Remove any scheduled notification for a given session.
15 | * Does nothing if the no notification for this session has been scheduled before
16 | */
17 | fun removeNotification(session: Session)
18 |
19 | /**
20 | * Schedule a notification for the given session or reschedule an existing scheduled
21 | * notification for the same session
22 | */
23 | fun addOrRescheduleNotification(session: Session)
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/notification/NotificationSchedulerCommand.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.notification
2 |
3 | import com.openconference.model.notification.NotificationScheduler
4 | import com.openconference.model.Session
5 |
6 | /**
7 | * Implementation of the command pattern
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface NotificationSchedulerCommand {
12 |
13 | /**
14 | * Executes the command
15 | */
16 | fun execute()
17 | }
18 |
19 | /**
20 | * Removes a Scheduled Notification for the given session
21 | */
22 | class RemoveScheduledNotificationCommand(private val session: Session, private val notificationScheduler: NotificationScheduler) : NotificationSchedulerCommand {
23 |
24 | override fun execute() {
25 | notificationScheduler.removeNotification(session)
26 | }
27 | }
28 |
29 | /**
30 | * Adds or reschedule a Notification for the given Session
31 | */
32 | class AddOrRescheduleNotificationCommand(private val session: Session, private val notificationScheduler: NotificationScheduler) : NotificationSchedulerCommand {
33 |
34 | override fun execute() {
35 | notificationScheduler.addOrRescheduleNotification(session)
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/MyScheduleScreen.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | import com.openconference.R
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class MyScheduleScreen : Screen {
11 |
12 | override fun titleRes(): Int = R.string.screen_title_my_schedule
13 |
14 | override fun iconRes(): Int = R.drawable.ic_my_schedule
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/Screen.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | import android.support.annotation.DrawableRes
4 | import android.support.annotation.StringRes
5 |
6 | /**
7 | * A Screen represents a visual component (like a Fragment)
8 | * @author Hannes Dorfmann
9 | */
10 | interface Screen {
11 |
12 | @StringRes
13 | fun titleRes(): Int
14 |
15 | @DrawableRes
16 | fun iconRes(): Int
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/Screens.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | /**
4 | * Screens container
5 | *
6 | * @author Hannes Dorfmann
7 | */
8 | data class Screens(val screens: List)
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/SessionsScreen.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | import com.openconference.R
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class SessionsScreen : Screen {
11 |
12 | override fun titleRes(): Int = R.string.screen_title_sessions
13 |
14 | override fun iconRes(): Int = R.drawable.ic_sessions
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/SpeakersScreen.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | import com.openconference.R
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class SpeakersScreen : Screen {
11 |
12 | override fun titleRes(): Int = R.string.screen_title_speakers
13 |
14 | override fun iconRes(): Int = R.drawable.ic_speakers
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/screen/TwitterScreen.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.screen
2 |
3 | import com.openconference.R
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class TwitterScreen : Screen {
11 |
12 | override fun titleRes(): Int = R.string.screen_title_twitter
13 |
14 | override fun iconRes(): Int = R.drawable.ic_twitter
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/DefaultSearchEngine.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | import rx.Observable
4 | import timber.log.Timber
5 | import java.util.*
6 |
7 | /**
8 | *
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class DefaultSearchEngine(private val searchSources: List) : SearchEngine {
13 |
14 | override fun search(query: String): Observable> {
15 |
16 | var errorsCount = 0
17 | val errorCatchingSources = searchSources.map { source ->
18 | source.search(query).onErrorReturn {
19 | errorsCount++
20 | Timber.e(it, "Error in SearchSource $source")
21 | if (errorsCount < searchSources.size) {
22 | emptyList()
23 | } else {
24 | throw it
25 | }
26 | }
27 | }
28 |
29 | return Observable.combineLatest(errorCatchingSources, {
30 | val result = ArrayList()
31 | it.forEach {
32 | result.addAll(it as List)
33 | }
34 | result
35 | })
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/SearchEngine.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | import com.openconference.model.search.SearchableItem
4 | import rx.Observable
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SearchEngine {
12 |
13 | fun search(query: String): Observable>
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/SearchSource.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | import com.openconference.model.search.SearchableItem
4 | import rx.Observable
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SearchSource {
12 |
13 | fun search(query: String): Observable>
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/SearchableItem.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | /**
4 | *
5 | *
6 | * @author Hannes Dorfmann
7 | */
8 | interface SearchableItem {
9 |
10 | // TODO implement relevance factor for each item
11 | //fun relevance() :Int
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/SessionSearchableItem.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | import com.openconference.model.Session
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | data class SessionSearchableItem (val session : Session) : SearchableItem
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/SpeakerSearchableItem.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search
2 |
3 | import com.openconference.model.Speaker
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | data class SpeakerSearchableItem(val speaker: Speaker) : SearchableItem
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/source/LocalStorageSessionsSearchSource.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search.source
2 |
3 | import com.openconference.model.ScheduleDataAwareObservableFactory
4 | import com.openconference.model.database.dao.SessionDao
5 | import com.openconference.model.search.SearchSource
6 | import com.openconference.model.search.SearchableItem
7 | import com.openconference.sessions.presentationmodel.SessionPresentationModelTransformer
8 | import rx.Observable
9 |
10 | /**
11 | *
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class LocalStorageSessionsSearchSource(private val awareObservableFactory: ScheduleDataAwareObservableFactory, private val sessionDao: SessionDao, private val modelTransformer: SessionPresentationModelTransformer) : SearchSource {
16 |
17 | override fun search(
18 | query: String): Observable> = awareObservableFactory.create>(
19 | sessionDao.findSessionsWith(query)
20 | .map { modelTransformer.transform(it) }
21 | )
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/model/search/source/LocalStorageSpeakersSearchSource.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.search.source
2 |
3 | import com.openconference.model.ScheduleDataAwareObservableFactory
4 | import com.openconference.model.database.dao.SpeakerDao
5 | import com.openconference.model.search.SearchSource
6 | import com.openconference.model.search.SearchableItem
7 | import com.openconference.model.search.SpeakerSearchableItem
8 | import rx.Observable
9 | import java.util.*
10 |
11 | /**
12 | *
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | class LocalStorageSpeakersSearchSource(private val awareObservableFactory: ScheduleDataAwareObservableFactory, private val speakerDao: SpeakerDao) : SearchSource {
17 |
18 | override fun search(
19 | query: String): Observable> =
20 | awareObservableFactory.create>(
21 | speakerDao.findSessionsWith(query)
22 | .map {
23 | val searchItems = ArrayList(it.size)
24 | it.forEach {
25 | searchItems.add(SpeakerSearchableItem(it))
26 | }
27 | searchItems
28 | }
29 | )
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/MyScheduleComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import com.openconference.myschedule.MyScheduleScope
5 | import dagger.Component
6 |
7 | /**
8 | *
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | @Component (
13 | modules = arrayOf(MyScheduleModule::class), dependencies = arrayOf(ApplicationComponent::class))
14 | @MyScheduleScope
15 | interface MyScheduleComponent {
16 |
17 | fun mySchedulePresenter(): MySchedulePresenter
18 | fun inject(fragment: MyScheduleFragment)
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/MyScheduleModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import com.openconference.Navigator
6 | import com.openconference.PhoneNavigator
7 | import com.openconference.R
8 | import com.openconference.dagger.ApplicationContext
9 | import com.openconference.myschedule.MyScheduleScope
10 | import com.openconference.myschedule.presentationmodel.MySchedulePresentationModelTransformer
11 | import com.openconference.sessions.presentationmodel.PhoneSessionPresentationModelTransformer
12 | import com.openconference.sessions.presentationmodel.SessionPresentationModelTransformer
13 | import dagger.Module
14 | import dagger.Provides
15 |
16 | /**
17 | * @author Hannes Dorfmann
18 | */
19 | @Module
20 | class MyScheduleModule(private val activity: Activity) {
21 |
22 | @Provides
23 | @MyScheduleScope
24 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
25 |
26 | @Provides
27 | @MyScheduleScope
28 | fun providesMySchedulePresentationTransformer() = MySchedulePresentationModelTransformer()
29 |
30 | @Provides
31 | @MyScheduleScope
32 | fun provideSessionPresentationModelTransformer(
33 | @ApplicationContext context: Context): SessionPresentationModelTransformer =
34 | PhoneSessionPresentationModelTransformer(context.getString(
35 | R.string.sessions_sticky_date_format)) // TODO make that changeable at runtime as any other config change
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/MySchedulePresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.model.SessionsLoader
4 | import com.openconference.model.errormessage.ErrorMessageDeterminer
5 | import com.openconference.myschedule.presentationmodel.MySchedulePresentationModelTransformer
6 | import com.openconference.sessions.presentationmodel.SessionPresentationModelTransformer
7 | import com.openconference.util.RxPresenter
8 | import com.openconference.util.SchedulerTransformer
9 | import javax.inject.Inject
10 |
11 | /**
12 | * Presenter responsible to show display sessions in [SessionsView]
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | class MySchedulePresenter @Inject constructor(scheduler: SchedulerTransformer,
17 | private val sessionsLoader: SessionsLoader,
18 | private val sessionGroupTransformer: SessionPresentationModelTransformer,
19 | private val presentationModelTransformer: MySchedulePresentationModelTransformer,
20 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
21 | scheduler, errorMessageDeterminer) {
22 |
23 | fun loadSessions() {
24 | view?.showLoading()
25 | subscribe(sessionsLoader.favoriteSessions()
26 | .map { sessionGroupTransformer.transform(it) }
27 | .map { presentationModelTransformer.transform(it) },
28 | {
29 | view?.showContent(it)
30 | },
31 | {
32 | view?.showError(errorMessageDeterminer.getErrorMessageRes(it))
33 | }
34 | )
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/MyScheduleScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.myschedule
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | * Defines the scope of the MySchedule components
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class MyScheduleScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/MyScheduleView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.myschedule.presentationmodel.MySchedulePresentationModel
4 | import com.openconference.util.lce.LceView
5 |
6 | /**
7 | * Displays a list of users favorite sessions
8 | * @author Hannes Dorfmann
9 | */
10 | interface MyScheduleView : LceView
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/presentationmodel/MySchedulePresentationModel.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.myschedule.presentationmodel
2 |
3 | import com.openconference.sessions.presentationmodel.SessionPresentationModel
4 |
5 | /**
6 | * Presentation model for easier use in [com.openconference.sessions.MyScheduleView]
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | data class MySchedulePresentationModel(val items: List, var scrollToPosition: Int?)
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/myschedule/presentationmodel/MySchedulePresentationModelTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.myschedule.presentationmodel
2 |
3 | import com.openconference.sessions.presentationmodel.SessionPresentationModel
4 |
5 | /**
6 | * Transforms a list of [SessionPresentationModel] to [MySchedulePresentationModel]
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class MySchedulePresentationModelTransformer {
11 |
12 | fun transform(sessions: List): MySchedulePresentationModel {
13 |
14 | // TODO implement
15 | return MySchedulePresentationModel(sessions, null)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.search
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import dagger.Component
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | @Component (
12 | modules = arrayOf(SearchViewModule::class), dependencies = arrayOf(ApplicationComponent::class))
13 | @SearchScope
14 | interface SearchComponent {
15 |
16 | fun searchPresenter(): SearchPresenter
17 |
18 | fun inject(a: SearchActivity)
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.search
2 |
3 | import com.openconference.model.errormessage.ErrorMessageDeterminer
4 | import com.openconference.model.search.SearchEngine
5 | import com.openconference.util.RxPresenter
6 | import com.openconference.util.SchedulerTransformer
7 | import javax.inject.Inject
8 |
9 | /**
10 | * Presenter for [SearchView]
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | class SearchPresenter @Inject constructor(scheduler: SchedulerTransformer,
15 | private val searchEngine: SearchEngine,
16 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
17 | scheduler, errorMessageDeterminer) {
18 |
19 | fun search(query: String) {
20 |
21 | val trimmedQuery = query.trim()
22 |
23 | unsubscribe() // Unsubscribe previous search
24 |
25 | if (trimmedQuery.isBlank()) {
26 | view?.showSearchNotStarted()
27 | return
28 | }
29 |
30 | view?.showLoading()
31 |
32 | subscribe(searchEngine.search(trimmedQuery),
33 | { view?.showResults(it) },
34 | { view?.showError(errorMessageDeterminer.getErrorMessageRes(it)) }
35 | )
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.search
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class SearchScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.search
2 |
3 | import android.support.annotation.StringRes
4 | import com.hannesdorfmann.mosby.mvp.MvpView
5 | import com.openconference.model.search.SearchableItem
6 |
7 | /**
8 | *
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | interface SearchView : MvpView {
13 | fun showLoading();
14 | fun showSearchNotStarted();
15 | fun showError(@StringRes errorMesgId: Int)
16 | fun showResults(result: List)
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchViewModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.search
2 |
3 | import com.openconference.Navigator
4 | import com.openconference.PhoneNavigator
5 | import dagger.Module
6 | import dagger.Provides
7 |
8 | /**
9 | *
10 | *
11 | * @author Hannes Dorfmann
12 | */
13 | @Module
14 | class SearchViewModule(private val activity: SearchActivity){
15 |
16 | @Provides
17 | @SearchScope
18 | fun provideNavigator() : Navigator = PhoneNavigator(activity)
19 |
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/search/SearchViewState.kt:
--------------------------------------------------------------------------------
1 | package com.primetime.search
2 |
3 | import android.support.annotation.StringRes
4 | import com.hannesdorfmann.mosby.mvp.viewstate.ViewState
5 | import com.openconference.model.search.SearchableItem
6 | import com.openconference.search.SearchView
7 |
8 | /**
9 | *
10 | *
11 | * @author Hannes Dorfmann
12 | */
13 | class SearchViewState : ViewState {
14 |
15 | private enum class State {
16 | NOT_STARTED, SHOW_LOADING, SHOW_ERROR, SHOW_RESULTS
17 | }
18 |
19 | private var state = State.NOT_STARTED
20 | private var error: Int = -1
21 | private var results: List? = null
22 |
23 | override fun apply(view: SearchView, retained: Boolean) = when (state) {
24 | State.NOT_STARTED -> view.showSearchNotStarted()
25 | State.SHOW_ERROR -> view.showError(error)
26 | State.SHOW_LOADING -> view.showLoading()
27 | State.SHOW_RESULTS -> view.showResults(results!!)
28 | }
29 |
30 | fun setShowError(@StringRes errorMesgId: Int) {
31 | error = errorMesgId
32 | results = null
33 | state = State.SHOW_ERROR
34 |
35 | }
36 |
37 | fun setSearchNotStarted() {
38 | state = State.NOT_STARTED
39 |
40 | this.error = -1
41 | this.results = null
42 | }
43 |
44 | fun setShowLoading() {
45 | state = State.SHOW_LOADING
46 | this.error = -1
47 | this.results = null
48 | }
49 |
50 | fun setShowResults(results: List) {
51 | state = State.SHOW_RESULTS
52 | this.results = results
53 | this.error = -1
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/DetailsDateAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
9 | import com.openconference.R
10 | import com.openconference.sessiondetails.presentationmodel.SessionDateTimeItem
11 | import com.openconference.sessiondetails.presentationmodel.SessionDetailItem
12 | import com.openconference.util.findView
13 |
14 | /**
15 | * Displays the Date and time of a session
16 | *
17 | * @author Hannes Dorfmann
18 | */
19 | open class DetailsDateAdapterDelegate(protected val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
20 |
21 |
22 | override fun isForViewType(item: SessionDetailItem, items: MutableList?,
23 | position: Int): Boolean = item is SessionDateTimeItem
24 |
25 | override fun onCreateViewHolder(parent: ViewGroup): DetailsViewHolder =
26 | DetailsViewHolder(
27 | inflater.inflate(R.layout.item_session_details_date, parent, false))
28 |
29 | override fun onBindViewHolder(item: SessionDateTimeItem, viewHolder: DetailsViewHolder) {
30 | viewHolder.text.text = item.dateTime
31 | }
32 |
33 | }
34 |
35 | class DetailsViewHolder(v: View) : RecyclerView.ViewHolder(v) {
36 | val text: TextView = v.findView(R.id.text)
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/DetailsDescriptionAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
9 | import com.openconference.R
10 | import com.openconference.sessiondetails.presentationmodel.SessionDescriptionItem
11 | import com.openconference.sessiondetails.presentationmodel.SessionDetailItem
12 | import com.openconference.util.findView
13 |
14 | /**
15 | * Displays the description of a session
16 | *
17 | * @author Hannes Dorfmann
18 | */
19 | open class DetailsDescriptionAdapterDelegate(protected val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
20 |
21 |
22 | override fun isForViewType(item: SessionDetailItem, items: MutableList?,
23 | position: Int): Boolean = item is SessionDescriptionItem
24 |
25 | override fun onCreateViewHolder(parent: ViewGroup): DescriptionViewHolder =
26 | DescriptionViewHolder(
27 | inflater.inflate(R.layout.item_session_details_description, parent, false))
28 |
29 | override fun onBindViewHolder(item: SessionDescriptionItem, viewHolder: DescriptionViewHolder) {
30 | viewHolder.description.text = item.description
31 | }
32 |
33 | class DescriptionViewHolder(v: View) : RecyclerView.ViewHolder(v) {
34 | val description: TextView = v.findView(R.id.description)
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/DetailsLocationAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
6 | import com.openconference.R
7 | import com.openconference.sessiondetails.presentationmodel.SessionDetailItem
8 | import com.openconference.sessiondetails.presentationmodel.SessionLocationItem
9 |
10 | /**
11 | * Displays the location of a session
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | open class DetailsLocationAdapterDelegate(protected val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
16 |
17 |
18 | override fun isForViewType(item: SessionDetailItem, items: MutableList?,
19 | position: Int): Boolean = item is SessionLocationItem
20 |
21 | override fun onCreateViewHolder(parent: ViewGroup): DetailsViewHolder =
22 | DetailsViewHolder(
23 | inflater.inflate(R.layout.item_session_details_location, parent, false))
24 |
25 | override fun onBindViewHolder(item: SessionLocationItem, viewHolder: DetailsViewHolder) {
26 | viewHolder.text.text = item.locationName
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/DetailsSeparatorAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
8 | import com.openconference.R
9 | import com.openconference.sessiondetails.presentationmodel.SessionDetailItem
10 | import com.openconference.sessiondetails.presentationmodel.SessionSeparatorItem
11 |
12 | /**
13 | * Displays the description of a session
14 | *
15 | * @author Hannes Dorfmann
16 | */
17 | open class DetailsSeparatorAdapterDelegate(protected val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
18 |
19 |
20 | override fun isForViewType(item: SessionDetailItem, items: MutableList?,
21 | position: Int): Boolean = item is SessionSeparatorItem
22 |
23 | override fun onCreateViewHolder(parent: ViewGroup): SeparatorViewHolder =
24 | SeparatorViewHolder(
25 | inflater.inflate(R.layout.item_session_details_separator, parent, false))
26 |
27 | override fun onBindViewHolder(item: SessionSeparatorItem, viewHolder: SeparatorViewHolder) {
28 |
29 | }
30 |
31 | class SeparatorViewHolder(v: View) : RecyclerView.ViewHolder(v)
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.support.v7.app.AppCompatActivity
7 | import com.openconference.R
8 | import com.openconference.model.Session
9 |
10 | /***
11 | * Simple Activity that hosts a "SessionDetailsFragment"
12 | */
13 | class SessionDetailsActivity : AppCompatActivity() {
14 |
15 | companion object {
16 | val KEY_SESSION = "SessionDetailsActivity.SESSION"
17 |
18 | fun buildIntent(c: Context, s: Session): Intent {
19 | val intent = Intent(c, SessionDetailsActivity::class.java)
20 | intent.putExtra(SessionDetailsActivity.KEY_SESSION, s)
21 | return intent
22 | }
23 | }
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | setContentView(R.layout.activity_session_details)
28 |
29 | if (savedInstanceState == null) {
30 | val session: Session = intent.getParcelableExtra(KEY_SESSION)
31 |
32 | supportFragmentManager.beginTransaction()
33 | .replace(R.id.fragmentContainer, SessionDetailsFragmentBuilder(session).build())
34 | .commit()
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import dagger.Component
5 |
6 | /**
7 | * SessionDetails component
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | @Component(modules = arrayOf(SessionDetailsModule::class),
12 | dependencies = arrayOf(ApplicationComponent::class))
13 | @SessionDetailsScope
14 | interface SessionDetailsComponent {
15 |
16 | fun sessionDetailsPresenter(): SessionDetailsPresenter
17 | fun inject(f: SessionDetailsFragment)
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.app.Activity
4 | import com.openconference.Navigator
5 | import com.openconference.PhoneNavigator
6 | import com.openconference.sessiondetails.presentationmodel.PhoneSessionDetailsPresentationModelTransformer
7 | import com.openconference.sessiondetails.presentationmodel.SessionDetailsPresentationModelTransformer
8 | import dagger.Module
9 | import dagger.Provides
10 |
11 | /**
12 | * Dagger Module for SessionDetails
13 | * @author Hannes Dorfmann
14 | */
15 | @Module
16 | class SessionDetailsModule(private val activity: Activity) {
17 |
18 | @Provides
19 | @SessionDetailsScope
20 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
21 |
22 | @Provides
23 | @SessionDetailsScope
24 | fun providePresentationModelTransformer(): SessionDetailsPresentationModelTransformer =
25 | PhoneSessionDetailsPresentationModelTransformer()
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import com.openconference.model.Session
4 | import com.openconference.model.SessionsLoader
5 | import com.openconference.model.errormessage.ErrorMessageDeterminer
6 | import com.openconference.sessiondetails.presentationmodel.SessionDetailsPresentationModelTransformer
7 | import com.openconference.util.RxPresenter
8 | import com.openconference.util.SchedulerTransformer
9 | import javax.inject.Inject
10 |
11 | /**
12 | *
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | class SessionDetailsPresenter @Inject constructor(scheduler: SchedulerTransformer,
17 | private val sessionsLoader: SessionsLoader,
18 | private val presentationModelTransformer: SessionDetailsPresentationModelTransformer,
19 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
20 | scheduler, errorMessageDeterminer) {
21 |
22 |
23 | fun loadSession(sessionId: String) {
24 | view?.showLoading()
25 | subscribe(
26 | sessionsLoader.getSession(sessionId).map { presentationModelTransformer.transform(it) },
27 | {
28 | view?.showContent(it)
29 | },
30 | {
31 | view?.showError(errorMessageDeterminer.getErrorMessageRes(it))
32 | })
33 | }
34 |
35 | fun addSessionToSchedule(session : Session) {
36 |
37 | schedulerTransformer.schedule(sessionsLoader.addSessionToSchedule(session)).subscribe ({
38 | view?.showSessionAddedToSchedule()
39 | }, {
40 | view?.showErrorWhileAddingSessionToSchedule()
41 | }
42 | )
43 |
44 |
45 | }
46 |
47 | fun removeSessionFromSchedule(session: Session) {
48 | schedulerTransformer.schedule(sessionsLoader.removeSessionFromSchedule(session)).subscribe ({
49 | view?.showSessionRemovedFromSchedule()
50 | }, {
51 | view?.showErrorWhileRemovingSessionFromSchedule()
52 | }
53 | )
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | * Scope for SessionDetails
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class SessionDetailsScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/SessionDetailsView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import com.openconference.sessiondetails.presentationmodel.SessionDetail
4 | import com.openconference.util.lce.LceView
5 |
6 | /**
7 | * Displays details about a certain Session
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SessionDetailsView : LceView {
12 | fun showSessionAddedToSchedule()
13 | fun showErrorWhileAddingSessionToSchedule()
14 |
15 | fun showSessionRemovedFromSchedule()
16 | fun showErrorWhileRemovingSessionFromSchedule()
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/presentationmodel/SessionDetail.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails.presentationmodel
2 |
3 | import com.openconference.model.Session
4 |
5 | /**
6 | *
7 | * Presentation Model for [com.openconference.sessiondetails.SessionDetailsView]
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | data class SessionDetail(val sessionId: String, val sessionName: String?, val session: Session, val detailsItems: List, val inMySchedule: Boolean)
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessiondetails/presentationmodel/SessionDetailItem.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails.presentationmodel
2 |
3 | import com.openconference.model.Speaker
4 | import com.openconference.model.search.SearchableItem
5 |
6 | /**
7 | * Represents the base class of elements that can be represented in this app
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SessionDetailItem
12 |
13 | /**
14 | * Holds the data for displaying session details
15 | * @author Hannes Dorfmann
16 | */
17 | data class SessionDescriptionItem(val description: String) : SessionDetailItem
18 |
19 | /**
20 | * Tags with which this item has been tagged
21 | * @author Hannes Dorfmann
22 | */
23 | data class SessionTagsItem(val tags: String) : SessionDetailItem
24 |
25 | /**
26 | * Contains the location id
27 | * @author Hannes Dorfmann
28 | */
29 | data class SessionLocationItem(val locationName: String) : SessionDetailItem
30 |
31 | /**
32 | * Contains the start - end date of a sessoin
33 | */
34 | data class SessionDateTimeItem(val dateTime: String) : SessionDetailItem
35 |
36 | /**
37 | * Speaker of a session
38 | */
39 | data class SessionSpeakerItem(val speaker: Speaker) : SessionDetailItem
40 |
41 | /**
42 | * Represents a separator line
43 | */
44 | class SessionSeparatorItem() : SessionDetailItem, SearchableItem
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionDateStickyHeaderAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import butterknife.bindView
9 | import com.eowise.recyclerview.stickyheaders.StickyHeadersAdapter
10 | import com.openconference.R
11 | import com.openconference.sessions.presentationmodel.SessionPresentationModel
12 |
13 | /**
14 | *
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | class SessionDateStickyHeaderAdapter(private val inflater: LayoutInflater) : StickyHeadersAdapter {
19 |
20 | var sessions: List = emptyList()
21 |
22 | override fun onCreateViewHolder(parent: ViewGroup?) =
23 | DateViewHolder(inflater.inflate(R.layout.item_session_date_sticky_header, parent, false))
24 |
25 | override fun onBindViewHolder(vh: DateViewHolder, position: Int) {
26 | val session = sessions[position]
27 | if (session.dateShort() != null) {
28 | vh.date.text = session.dateShort()
29 | vh.date.visibility = View.VISIBLE
30 | } else {
31 | vh.date.visibility = View.GONE
32 | }
33 |
34 | if (session.dayInWeek() != null){
35 | vh.dayInWeek.text = session.dayInWeek()
36 | vh.dayInWeek.visibility = View.VISIBLE
37 | } else {
38 | vh.dayInWeek.visibility = View.GONE
39 | }
40 | }
41 |
42 | override fun getHeaderId(position: Int): Long = sessions[position].getSectionId()
43 |
44 | class DateViewHolder(v: View) : RecyclerView.ViewHolder(v) {
45 | val dayInWeek: TextView by bindView(R.id.dayInWeek)
46 | val date: TextView by bindView(R.id.date)
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionsComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import dagger.Component
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | @Component (
12 | modules = arrayOf(SessionsModule::class), dependencies = arrayOf(ApplicationComponent::class))
13 | @SessionsScope
14 | interface SessionsComponent {
15 |
16 | fun sessionPresenter(): SessionsPresenter
17 |
18 | fun inject(f: SessionsFragment)
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionsModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import com.openconference.Navigator
6 | import com.openconference.PhoneNavigator
7 | import com.openconference.R
8 | import com.openconference.dagger.ApplicationContext
9 | import com.openconference.sessions.presentationmodel.PhoneSessionPresentationModelTransformer
10 | import com.openconference.sessions.presentationmodel.SessionPresentationModelTransformer
11 | import dagger.Module
12 | import dagger.Provides
13 |
14 | /**
15 | * @author Hannes Dorfmann
16 | */
17 | @Module
18 | class SessionsModule(private val activity: Activity) {
19 |
20 |
21 | @Provides
22 | @SessionsScope
23 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
24 |
25 | @Provides
26 | @SessionsScope
27 | fun provideSessionPresentationModelTransformer(
28 | @ApplicationContext context: Context): SessionPresentationModelTransformer =
29 | PhoneSessionPresentationModelTransformer(context.getString(
30 | R.string.sessions_sticky_date_format)) // TODO make that changeable at runtime as any other config change
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionsPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.model.SessionsLoader
4 | import com.openconference.model.errormessage.ErrorMessageDeterminer
5 | import com.openconference.sessions.presentationmodel.SessionPresentationModelTransformer
6 | import com.openconference.util.RxPresenter
7 | import com.openconference.util.SchedulerTransformer
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Presenter responsible to show display sessions in [SessionsView]
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class SessionsPresenter @Inject constructor(scheduler: SchedulerTransformer,
16 | private val sessionsLoader: SessionsLoader,
17 | private val presentationModelTransformer: SessionPresentationModelTransformer,
18 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
19 | scheduler, errorMessageDeterminer) {
20 |
21 | fun loadSessions() {
22 | view?.showLoading()
23 | subscribe(sessionsLoader.allSessions().map { presentationModelTransformer.transform(it) },
24 | {
25 | view?.showContent(it)
26 | },
27 | {
28 | view?.showError(errorMessageDeterminer.getErrorMessageRes(it))
29 | }
30 | )
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionsScope.java:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions;
2 |
3 | import javax.inject.Scope;
4 |
5 | /**
6 | * @author Hannes Dorfmann
7 | */
8 | @Scope public @interface SessionsScope {
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/SessionsView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.sessions.presentationmodel.GroupableSession
4 | import com.openconference.sessions.presentationmodel.SessionPresentationModel
5 | import com.openconference.util.lce.LceView
6 |
7 | /**
8 | * Displays a list of sessions
9 | * @author Hannes Dorfmann
10 | */
11 | interface SessionsView : LceView>
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/presentationmodel/GroupableSession.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions.presentationmodel
2 |
3 | import android.os.Parcelable
4 |
5 | /**
6 | * Common interface to group session together
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface GroupableSession : Parcelable {
11 |
12 |
13 | /**
14 | * Specify to which section this Session belongs. Typically sections are grouped by days
15 | */
16 | fun getSectionId(): Long
17 |
18 | /**
19 | * Specifies the id of the session
20 | */
21 | fun getSessionId(): String
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/presentationmodel/SessionPresentationModel.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions.presentationmodel
2 |
3 | import com.google.auto.value.AutoValue
4 | import com.openconference.model.Session
5 | import com.openconference.model.search.SearchableItem
6 |
7 | /**
8 | * Presentation Model of [com.openconference.model.Session] used by [com.openconference.sessions.SessionsView]
9 | * @author Hannes Dorfmann
10 | */
11 | @AutoValue
12 | abstract class SessionPresentationModel : GroupableSession, SearchableItem {
13 |
14 |
15 | abstract fun dayInWeek(): String?
16 |
17 | abstract fun dateShort(): String?
18 |
19 | abstract fun time(): String?
20 |
21 | abstract fun speakers(): String?
22 |
23 | abstract fun session(): Session
24 |
25 | companion object {
26 | fun create(id: Long, dayInWeek: String?, dateShort: String?, speakers: String?, time: String?,
27 | session: Session): SessionPresentationModel =
28 | AutoValue_SessionPresentationModel(id, session.id().toString(), dayInWeek, dateShort, time,
29 | speakers, session)
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/sessions/presentationmodel/SessionPresentationModelTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions.presentationmodel
2 |
3 | import com.openconference.model.Session
4 |
5 | /**
6 | *Transforms a [com.openconference.model.Session] to [SessionPresentationModel]
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface SessionPresentationModelTransformer {
11 |
12 | fun transform(s: List): List
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import com.openconference.R
6 | import com.openconference.model.Speaker
7 |
8 | /***
9 | * Simple Activity that hosts a "SessionDetailsFragment"
10 | */
11 | class SpeakerDetailsActivity : AppCompatActivity() {
12 |
13 | companion object {
14 | val KEY_SPEAKER = "SpeakerDetailsActivity.SPEAKER"
15 | }
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_session_details)
20 |
21 | if (savedInstanceState == null) {
22 | val speaker: Speaker = intent.getParcelableExtra(KEY_SPEAKER)
23 |
24 | supportFragmentManager.beginTransaction()
25 | .replace(R.id.fragmentContainer, SpeakerDetailsFragmentBuilder(speaker).build())
26 | .commit()
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsBioAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
6 | import com.openconference.R
7 | import com.openconference.speakerdetails.presentationmodel.SpeakerBioItem
8 | import com.openconference.speakerdetails.presentationmodel.SpeakerDetailsItem
9 |
10 | /**
11 | *
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class SpeakerDetailsBioAdapterDelegate(val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
16 |
17 |
18 | override fun isForViewType(item: SpeakerDetailsItem, items: MutableList?,
19 | position: Int) = item is SpeakerBioItem
20 |
21 | override fun onBindViewHolder(item: SpeakerBioItem, viewHolder: SpeakerDetailsViewHolder) =
22 | viewHolder.bind(null, item.bio)
23 |
24 | override fun onCreateViewHolder(parent: ViewGroup): SpeakerDetailsViewHolder {
25 | val view = inflater.inflate(R.layout.item_details_icon_text, parent, false)
26 | view.isClickable = false
27 | return SpeakerDetailsViewHolder(view)
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import com.openconference.speakerdetails.SpeakerDetailsPresenter
5 | import dagger.Component
6 |
7 | /**
8 | * SessionDetails component
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | @Component(modules = arrayOf(SpeakerDetailsModule::class),
13 | dependencies = arrayOf(ApplicationComponent::class))
14 | @SpeakerDetailsScope
15 | interface SpeakerDetailsComponent {
16 |
17 | fun sessionDetailsPresenter(): SpeakerDetailsPresenter
18 | fun inject(f: SpeakerDetailsFragment)
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsJobInfoAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import butterknife.bindView
9 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
10 | import com.openconference.R
11 | import com.openconference.speakerdetails.presentationmodel.SpeakerDetailsItem
12 | import com.openconference.speakerdetails.presentationmodel.SpeakerJobInfoItem
13 |
14 | /**
15 | *
16 | *
17 | * @author Hannes Dorfmann
18 | */
19 | class SpeakerDetailsJobInfoAdapterDelegate(val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
20 |
21 |
22 | override fun isForViewType(item: SpeakerDetailsItem, items: MutableList?,
23 | position: Int) = item is SpeakerJobInfoItem
24 |
25 | override fun onBindViewHolder(item: SpeakerJobInfoItem, viewHolder: JobInfoViewHolder) =
26 | viewHolder.bind(item)
27 |
28 | override fun onCreateViewHolder(parent: ViewGroup) = JobInfoViewHolder(
29 | inflater.inflate(R.layout.item_speaker_details_jobinfo, parent, false))
30 |
31 | class JobInfoViewHolder(v: View) : RecyclerView.ViewHolder(v) {
32 | val jobTitle by bindView(R.id.jobTitle)
33 | val companyName by bindView(R.id.company)
34 |
35 | inline fun bind(info: SpeakerJobInfoItem) {
36 | val title = info.jobTitle
37 | if (title != null) {
38 | jobTitle.text = title
39 | jobTitle.visibility = View.VISIBLE
40 | } else {
41 | jobTitle.visibility = View.GONE
42 | }
43 |
44 | val company = info.company
45 | if (company != null) {
46 | companyName.text = company
47 | companyName.visibility = View.VISIBLE
48 | } else {
49 | companyName.visibility = View.GONE
50 | }
51 | }
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsLinkAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
6 | import com.openconference.R
7 | import com.openconference.speakerdetails.presentationmodel.SpeakerDetailsItem
8 | import com.openconference.speakerdetails.presentationmodel.SpeakerLinkItem
9 |
10 | /**
11 | *
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class SpeakerDetailsLinkAdapterDelegate(val inflater: LayoutInflater) : AbsListItemAdapterDelegate() {
16 |
17 |
18 | override fun isForViewType(item: SpeakerDetailsItem, items: MutableList?,
19 | position: Int) = item is SpeakerLinkItem
20 |
21 | override fun onBindViewHolder(item: SpeakerLinkItem, viewHolder: SpeakerDetailsViewHolder) {
22 | viewHolder.bind(if (item.showIcon) {
23 | R.drawable.ic_link
24 | } else null, item.url)
25 | }
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup) = SpeakerDetailsViewHolder(
28 | inflater.inflate(R.layout.item_details_icon_link_text, parent, false))
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import android.app.Activity
4 | import com.openconference.Navigator
5 | import com.openconference.PhoneNavigator
6 | import com.openconference.sessiondetails.presentationmodel.PhoneSpeakerDetailsPresentationModelTransformer
7 | import com.openconference.sessiondetails.presentationmodel.SpeakerDetailsPresentationModelTransformer
8 | import dagger.Module
9 | import dagger.Provides
10 |
11 | /**
12 | * Dagger Module for SessionDetails
13 | * @author Hannes Dorfmann
14 | */
15 | @Module
16 | class SpeakerDetailsModule(private val activity: Activity) {
17 |
18 | @Provides
19 | @SpeakerDetailsScope
20 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
21 |
22 | @Provides
23 | @SpeakerDetailsScope
24 | fun providePresentationModelTransformer(): SpeakerDetailsPresentationModelTransformer =
25 | PhoneSpeakerDetailsPresentationModelTransformer()
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import com.openconference.model.SessionsLoader
4 | import com.openconference.model.SpeakersLoader
5 | import com.openconference.model.errormessage.ErrorMessageDeterminer
6 | import com.openconference.sessiondetails.presentationmodel.SpeakerDetailsPresentationModelTransformer
7 | import com.openconference.util.RxPresenter
8 | import com.openconference.util.SchedulerTransformer
9 | import rx.Observable
10 | import javax.inject.Inject
11 |
12 | /**
13 | *
14 | *
15 | * @author Hannes Dorfmann
16 | */
17 | class SpeakerDetailsPresenter @Inject constructor(scheduler: SchedulerTransformer,
18 | private val sessionsLoader: SessionsLoader,
19 | private val speakersLoader: SpeakersLoader,
20 | private val presentationModelTransformer: SpeakerDetailsPresentationModelTransformer,
21 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
22 | scheduler, errorMessageDeterminer) {
23 |
24 |
25 | fun loadSpeakerDetails(speakerId: String) {
26 | view?.showLoading()
27 | subscribe(
28 | // TODO move this in a own class
29 | Observable.combineLatest(
30 | sessionsLoader.getSessionsOfSpeaker(speakerId),
31 | speakersLoader.getSpeaker(speakerId),
32 | { sessions, speaker -> presentationModelTransformer.transform(speaker, sessions) }),
33 | {
34 | view?.showContent(it)
35 | },
36 | {
37 | view?.showError(errorMessageDeterminer.getErrorMessageRes(it))
38 | })
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessiondetails
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | * Scope for SessionDetails
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class SpeakerDetailsScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import com.openconference.speakerdetails.presentationmodel.SpeakerDetail
4 | import com.openconference.util.lce.LceView
5 |
6 | /**
7 | * A view that dispalys information about a speaker
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SpeakerDetailsView : LceView
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/SpeakerDetailsViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails
2 |
3 | import android.support.annotation.DrawableRes
4 | import android.support.v7.widget.RecyclerView
5 | import android.view.View
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import butterknife.bindView
9 | import com.openconference.R
10 |
11 | /**
12 | * ViewHolder for icon text combination
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | open class SpeakerDetailsViewHolder(v: View) : RecyclerView.ViewHolder(v) {
17 |
18 | val icon by bindView(R.id.icon)
19 | val text by bindView(R.id.text)
20 |
21 | inline fun bind(@DrawableRes iconRes: Int?, t: String) {
22 | if (iconRes == null) {
23 | icon.visibility = View.INVISIBLE
24 | } else {
25 | icon.setImageDrawable(itemView.resources.getDrawable(iconRes))
26 | }
27 |
28 | text.text = t
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/presentationmodel/SpeakerDetail.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails.presentationmodel
2 |
3 | /**
4 | * Presentation Model containig all the data required to dispaly details about a Speaker
5 | *
6 | * @author Hannes Dorfmann
7 | */
8 | data class SpeakerDetail(val speakerName: String, val profilePic: String?,
9 | val detailsItems: List)
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakerdetails/presentationmodel/SpeakerDetailsItem.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakerdetails.presentationmodel
2 |
3 | import com.openconference.model.Session
4 |
5 | /**
6 | * Common super interface for items that can be dispalyed in the speakers details
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface SpeakerDetailsItem
11 |
12 | /**
13 | * Information about the job of the speaker
14 | */
15 | data class SpeakerJobInfoItem(val company: String?, val jobTitle: String?) : SpeakerDetailsItem
16 |
17 | /**
18 | * A link like personal blog, twitter account etc. of the speaker
19 | */
20 | data class SpeakerLinkItem(val url: String, val showIcon: Boolean) : SpeakerDetailsItem
21 |
22 | /**
23 | * Containing the bio of the speaker
24 | */
25 | data class SpeakerBioItem(val bio: String) : SpeakerDetailsItem
26 |
27 | /**
28 | * Represents a session that will be given by the speaker
29 | */
30 | data class SpeakerSessionItem(val session: Session, val showIcon: Boolean) : SpeakerDetailsItem
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakerAdapterDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakers
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.ImageView
8 | import android.widget.TextView
9 | import butterknife.bindView
10 | import com.hannesdorfmann.adapterdelegates2.AbsListItemAdapterDelegate
11 | import com.openconference.R
12 | import com.openconference.model.Speaker
13 | import com.openconference.util.picasso.PicassoScrollListener
14 | import com.squareup.picasso.Picasso
15 |
16 | /**
17 | * Displays an profile pic image and name of a given Speaker
18 | *
19 | * @author Hannes Dorfmann
20 | */
21 | class SpeakerAdapterDelegate(
22 | private val inflater: LayoutInflater,
23 | private val picasso: Picasso,
24 | private val clickListener: (Speaker) -> Unit) : AbsListItemAdapterDelegate() {
25 |
26 | override fun isForViewType(item: Speaker, items: MutableList?, position: Int): Boolean =
27 | item is Speaker
28 |
29 | override fun onBindViewHolder(item: Speaker, viewHolder: SpeakerViewHolder) =
30 | viewHolder.bind(item)
31 |
32 | override fun onCreateViewHolder(parent: ViewGroup): SpeakerViewHolder =
33 | SpeakerViewHolder(inflater.inflate(R.layout.item_speaker, parent, false), picasso,
34 | clickListener)
35 |
36 | class SpeakerViewHolder(v: View, val picasso: Picasso, clickListener: (Speaker) -> Unit) : RecyclerView.ViewHolder(
37 | v) {
38 |
39 | init {
40 | v.setOnClickListener { clickListener(speaker) }
41 | }
42 |
43 | val image: ImageView by bindView(R.id.image)
44 | val name: TextView by bindView(R.id.name)
45 | lateinit var speaker: Speaker
46 |
47 | inline fun bind(s: Speaker) {
48 | speaker = s
49 | name.text = s.name()
50 | picasso.load(speaker.profilePic())
51 | .tag(PicassoScrollListener.TAG)
52 | .centerCrop()
53 | .fit()
54 | .placeholder(R.color.speakerslist_placeholder)
55 | .into(image)
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakersComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakers
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import com.openconference.sessions.SpeakersFragment
5 | import com.openconference.sessions.SpeakersModule
6 | import com.openconference.sessions.SpeakersPresenter
7 | import dagger.Component
8 |
9 | /**
10 | *
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | @Component(modules = arrayOf(SpeakersModule::class),
15 | dependencies = arrayOf(ApplicationComponent::class))
16 | @SpeakersScope
17 | interface SpeakersComponent {
18 |
19 | fun inject(f: SpeakersFragment)
20 |
21 | fun speakersPresenter(): SpeakersPresenter
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakersModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import android.app.Activity
4 | import com.openconference.Navigator
5 | import com.openconference.PhoneNavigator
6 | import com.openconference.speakers.SpeakersScope
7 | import dagger.Module
8 | import dagger.Provides
9 |
10 | /**
11 | * @author Hannes Dorfmann
12 | */
13 | @Module
14 | class SpeakersModule(private val activity: Activity) {
15 |
16 | @Provides
17 | @SpeakersScope
18 | fun provideNavigator(): Navigator = PhoneNavigator(activity)
19 |
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakersPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.sessions
2 |
3 | import com.openconference.model.SpeakersLoader
4 | import com.openconference.model.errormessage.ErrorMessageDeterminer
5 | import com.openconference.speakers.SpeakersView
6 | import com.openconference.util.RxPresenter
7 | import com.openconference.util.SchedulerTransformer
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Presenter responsible to show display sessions in [SessionsView]
12 | *
13 | * @author Hannes Dorfmann
14 | */
15 | class SpeakersPresenter @Inject constructor(scheduler: SchedulerTransformer,
16 | private val speakersLoader: SpeakersLoader,
17 | errorMessageDeterminer: ErrorMessageDeterminer) : RxPresenter(
18 | scheduler, errorMessageDeterminer) {
19 |
20 | fun loadSpeakers() {
21 | view?.showLoading()
22 | subscribe(speakersLoader.allSpeakers(),
23 | {
24 | view?.showContent(it)
25 | },
26 | {
27 | view?.showError(errorMessageDeterminer.getErrorMessageRes(it))
28 | }
29 | )
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakersScope.java:
--------------------------------------------------------------------------------
1 | package com.openconference.speakers;
2 |
3 | import javax.inject.Scope;
4 |
5 | /**
6 | * @author Hannes Dorfmann
7 | */
8 | @Scope public @interface SpeakersScope {
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/speakers/SpeakersView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.speakers
2 |
3 | import com.openconference.model.Speaker
4 | import com.openconference.util.lce.LceView
5 |
6 | /**
7 | * View that displays a list of all speakers
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface SpeakersView : LceView>
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/splash/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.splash
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import com.hannesdorfmann.mosby.mvp.viewstate.MvpViewStateActivity
6 | import com.hannesdorfmann.mosby.mvp.viewstate.ViewState
7 | import com.openconference.R
8 | import com.openconference.main.ViewPagerMainActivity
9 | import com.openconference.util.applicationComponent
10 |
11 | /**
12 | *
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | class SplashActivity : SplashView, MvpViewStateActivity() {
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | setContentView(R.layout.activity_splash)
21 | retainInstance = true
22 |
23 | }
24 |
25 | override fun finishSplash() {
26 | finish()
27 | startActivity(Intent(this, ViewPagerMainActivity::class.java))
28 | overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
29 | }
30 |
31 | override fun createPresenter(): SplashPresenter =
32 | DaggerSplashComponent.builder().applicationComponent(
33 | applicationComponent()).build().splashPresenter()
34 |
35 | override fun createViewState(): ViewState = ViewState { view, retained -> } // dummy, does nothing, not needed
36 |
37 | override fun onNewViewStateInstance() = presenter.start()
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/splash/SplashComponent.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.splash
2 |
3 | import com.openconference.dagger.ApplicationComponent
4 | import dagger.Component
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | @Component(
12 | dependencies = arrayOf(ApplicationComponent::class))
13 | @SplashScope
14 | interface SplashComponent {
15 |
16 | fun splashPresenter(): SplashPresenter
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/splash/SplashPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.splash
2 |
3 | import com.openconference.model.ScheduleDataAwareObservableFactory
4 | import com.openconference.model.errormessage.ErrorMessageDeterminer
5 | import com.openconference.util.RxPresenter
6 | import com.openconference.util.SchedulerTransformer
7 | import rx.Observable
8 | import java.util.concurrent.TimeUnit
9 | import javax.inject.Inject
10 |
11 | /**
12 | *
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | class SplashPresenter @Inject constructor(schedulerTransformer: SchedulerTransformer,
17 | errorMessageDeterminer: ErrorMessageDeterminer, private val observableFactory: ScheduleDataAwareObservableFactory) : RxPresenter(
18 | schedulerTransformer,
19 | errorMessageDeterminer) {
20 |
21 |
22 | fun start() {
23 |
24 | // Preload data in background
25 | subscribe(observableFactory.create(Observable.just(1)),
26 | {},
27 | {},
28 | {}
29 | ) // no callbacks needed
30 |
31 | // wait for two seconds
32 | val timer = Observable.timer(1500, TimeUnit.MILLISECONDS)
33 | subscribe(
34 | timer,
35 | { // onNext
36 | },
37 | {
38 | // onError
39 | view?.finishSplash()
40 | },
41 | {
42 | // onCompleted (timer just fire onCompleted)
43 | view?.finishSplash()
44 | }
45 | )
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/splash/SplashScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.splash
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class SplashScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/splash/SplashView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.splash
2 |
3 | import com.hannesdorfmann.mosby.mvp.MvpView
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | interface SplashView : MvpView {
11 | fun finishSplash()
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/twitter/TwitterTimelinePresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.twitter
2 |
3 | import com.hannesdorfmann.mosby.mvp.MvpBasePresenter
4 | import com.openconference.R
5 | import com.twitter.sdk.android.core.Callback
6 | import com.twitter.sdk.android.core.Result
7 | import com.twitter.sdk.android.core.TwitterException
8 | import com.twitter.sdk.android.core.models.Tweet
9 | import com.twitter.sdk.android.tweetui.SearchTimeline
10 | import com.twitter.sdk.android.tweetui.Timeline
11 | import com.twitter.sdk.android.tweetui.TimelineResult
12 | import timber.log.Timber
13 |
14 | class TwitterTimelinePresenter : MvpBasePresenter() {
15 |
16 | private val timeline: Timeline = SearchTimeline.Builder().query("#droidconDE").build()
17 |
18 | override fun attachView(view: TwitterTimelineView) {
19 | super.attachView(view)
20 | view.setTimeline(timeline)
21 | }
22 |
23 | fun loadNextTweets() {
24 | view?.showLoading()
25 | timeline.next(0, object : Callback>() {
26 |
27 | override fun success(result: Result>?) {
28 | view?.showContent(1) // Data will be bound automatically via view.setTimeline
29 | }
30 |
31 | override fun failure(exception: TwitterException?) {
32 | view?.showError(R.string.error_unknown)
33 | Timber.e(exception, "Error while loading Twitter")
34 | }
35 | })
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/twitter/TwitterTimelineView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.twitter
2 |
3 | import com.openconference.util.lce.LceView
4 | import com.twitter.sdk.android.core.models.Tweet
5 | import com.twitter.sdk.android.tweetui.Timeline
6 |
7 | /**
8 | * Displays a list of item in the timeline
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | interface TwitterTimelineView : LceView {
13 | fun setTimeline(timeline: Timeline)
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/ActivityExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import android.app.Activity
4 | import android.support.annotation.IdRes
5 | import android.util.DisplayMetrics
6 | import android.view.View
7 | import com.openconference.OpenConfApp
8 |
9 |
10 | fun Activity.applicationComponent() = OpenConfApp.getApplicationComponent(application)
11 |
12 | fun Activity.dpToPx(dp: Int): Float {
13 | val metrics = resources.displayMetrics;
14 | val px: Float = dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT);
15 | return px;
16 | }
17 |
18 | fun Activity.findView(@IdRes id: Int) = this.findViewById(id) as T
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/ContentValuesExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import android.content.ContentValues
4 | import org.threeten.bp.Instant
5 |
6 |
7 | /**
8 | * Checks if the value is null and either inserts null into content value or the real value
9 | */
10 | fun ContentValues.putOrNull(key: String, value: String?) =
11 | if (value == null) putNull(key) else put(key, value)
12 |
13 |
14 | fun ContentValues.putOrNull(key: String, value: Instant?) =
15 | if (value == null) putNull(key) else put(key, value.toEpochMilli())
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/FragmentExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import android.app.Activity
4 | import android.support.annotation.IntegerRes
5 | import android.support.v4.app.Fragment
6 | import android.util.DisplayMetrics
7 | import com.openconference.OpenConfApp
8 |
9 | fun Fragment.applicationComponent() = OpenConfApp.getApplicationComponent(activity)
10 |
11 | fun Fragment.layoutInflater() = activity.layoutInflater
12 |
13 | fun Fragment.getInt(@IntegerRes intRes: Int) = resources.getInteger(intRes)
14 |
15 | fun Fragment.dpToPx(dp: Int): Float {
16 | val metrics = resources.displayMetrics;
17 | val px: Float = dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT);
18 | return px;
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/FragmentScope.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import javax.inject.Scope
4 |
5 | /**
6 | *
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | @Scope
11 | annotation class FragmentScope
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/RxPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import com.hannesdorfmann.mosby.mvp.MvpBasePresenter
4 | import com.hannesdorfmann.mosby.mvp.MvpView
5 | import com.openconference.model.errormessage.ErrorMessageDeterminer
6 | import rx.Observable
7 | import rx.subscriptions.CompositeSubscription
8 | import timber.log.Timber
9 |
10 | /**
11 | * A Presenter that automatically unsubscribes from Observable
12 | * once the view has been permanently detached
13 | * @author Hannes Dorfmann
14 | */
15 | open class RxPresenter(protected val schedulerTransformer: SchedulerTransformer,
16 | protected val errorMessageDeterminer: ErrorMessageDeterminer) : MvpBasePresenter() {
17 |
18 | protected var subscriptions = CompositeSubscription()
19 |
20 | /**
21 | * subscribes the given observable with the given lambdas.
22 | * Per default the presenters default [SchedulerTransformer] will be applied
23 | */
24 | protected fun subscribe(observable: Observable,
25 | onNext: (M) -> Unit,
26 | onError: (Throwable) -> Unit,
27 | onCompleted: (() -> Unit)? = null,
28 | scheduler: SchedulerTransformer = schedulerTransformer) {
29 |
30 |
31 | val o = scheduler.schedule(observable)
32 | .doOnError {
33 | Timber.e(it, "Error caught")
34 | }
35 |
36 | if (onCompleted != null) {
37 | subscriptions.add(o.subscribe(onNext, onError, onCompleted))
38 | } else {
39 | subscriptions.add(o.subscribe(onNext, onError))
40 | }
41 | }
42 |
43 | private fun unsubscribe(recreateComposite: Boolean) {
44 | if (!subscriptions.isUnsubscribed) {
45 | subscriptions.unsubscribe()
46 | if (recreateComposite) subscriptions = CompositeSubscription()
47 | }
48 | }
49 |
50 | protected fun unsubscribe() {
51 | unsubscribe(true)
52 | }
53 |
54 | override fun detachView(retainInstance: Boolean) {
55 | super.detachView(retainInstance)
56 | if (!retainInstance) {
57 | unsubscribe(false)
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/SchedulerTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import rx.Observable
4 | import rx.android.schedulers.AndroidSchedulers
5 | import rx.schedulers.Schedulers
6 |
7 | /**
8 | *
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | interface SchedulerTransformer {
13 |
14 | fun schedule(observable: Observable): Observable
15 | }
16 |
17 | class DefaultSchedulerTransformer : SchedulerTransformer {
18 |
19 | override fun schedule(observable: Observable): Observable =
20 | observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
21 |
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/StableIdListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import com.hannesdorfmann.adapterdelegates2.AdapterDelegatesManager
4 | import com.hannesdorfmann.adapterdelegates2.ListDelegationAdapter
5 |
6 | /**
7 | *
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | class StableIdListAdapter>(delegatesManager: AdapterDelegatesManager, private val idDeterminer: (T, Int) -> Long) : ListDelegationAdapter(
12 | delegatesManager) {
13 |
14 | init {
15 | setHasStableIds(true)
16 | }
17 |
18 | override fun getItemId(position: Int): Long {
19 | return idDeterminer(items, position)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/ViewExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util
2 |
3 | import android.content.Context
4 | import android.support.annotation.IdRes
5 | import android.view.View
6 | import android.view.inputmethod.InputMethodManager
7 |
8 |
9 | fun View.findView(@IdRes id: Int) = this.findViewById(id) as T
10 |
11 | fun View.hideKeyboard() {
12 | (context.getSystemService(
13 | Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(
14 | windowToken, 0)
15 | }
16 |
17 | fun View.showKeyboard() {
18 | (context.getSystemService(
19 | Context.INPUT_METHOD_SERVICE) as InputMethodManager).toggleSoftInput(
20 | InputMethodManager.SHOW_FORCED, 0)
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/lce/LceView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util.lce
2 |
3 | import android.support.annotation.StringRes
4 | import com.hannesdorfmann.mosby.mvp.MvpView
5 |
6 | /**
7 | * LCE (Loading-Content-Error) MVP View
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | interface LceView : MvpView {
12 |
13 | /**
14 | * show the loading indicator
15 | */
16 | fun showLoading()
17 |
18 | /**
19 | * Show the error indicator
20 | */
21 | fun showError(@StringRes errorMsgRes: Int)
22 |
23 | /**
24 | * Show the content with the given data
25 | */
26 | fun showContent(data: M)
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/lce/LceViewState.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util.lce
2 |
3 | import android.support.annotation.StringRes
4 | import com.hannesdorfmann.mosby.mvp.viewstate.ViewState
5 |
6 | /**
7 | * ViewState implementation for [LceView]
8 | *
9 | * @author Hannes Dorfmann
10 | */
11 | // TODO test
12 | class LceViewState : ViewState> {
13 |
14 | private enum class State {
15 | SHOW_LOADING, SHOW_ERROR, SHOW_CONTENT
16 | }
17 |
18 | private var data: M? = null
19 | private var errorMsg: Int = -1
20 | private var state = State.SHOW_LOADING
21 |
22 | fun showContent(data: M) {
23 | this.data = data
24 | this.state = State.SHOW_CONTENT
25 | this.errorMsg = -1
26 | }
27 |
28 | fun showError(@StringRes errorMsgRes: Int) {
29 | this.errorMsg = errorMsgRes
30 | this.state = State.SHOW_ERROR
31 | this.data = null
32 | }
33 |
34 | fun showLoading() {
35 | this.errorMsg = -1
36 | this.data = null
37 | this.state = State.SHOW_LOADING
38 | }
39 |
40 | override fun apply(view: LceView, retained: Boolean) =
41 | when (state) {
42 | State.SHOW_CONTENT -> view.showContent(data!!)
43 | State.SHOW_LOADING -> view.showLoading()
44 | State.SHOW_ERROR -> view.showError(errorMsg)
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/picasso/CircleImageTransformation.java:
--------------------------------------------------------------------------------
1 | package com.openconference.util.picasso;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapShader;
5 | import android.graphics.Canvas;
6 | import android.graphics.Matrix;
7 | import android.graphics.Paint;
8 | import android.graphics.RectF;
9 | import android.graphics.Shader;
10 | import com.squareup.picasso.Transformation;
11 |
12 | /**
13 | * Created by codezjx on 2016/5/4.
14 | */
15 | public class CircleImageTransformation implements Transformation {
16 |
17 | /**
18 | * A unique key for the transformation, used for caching purposes.
19 | */
20 | private static final String KEY = "circleImageTransformation";
21 |
22 | @Override
23 | public Bitmap transform(Bitmap source) {
24 |
25 | int minEdge = Math.min(source.getWidth(), source.getHeight());
26 | int dx = (source.getWidth() - minEdge) / 2;
27 | int dy = (source.getHeight() - minEdge) / 2;
28 |
29 | // Init shader
30 | Shader shader = new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
31 | Matrix matrix = new Matrix();
32 | matrix.setTranslate(-dx, -dy); // Move the target area to center of the source bitmap
33 | shader.setLocalMatrix(matrix);
34 |
35 | // Init paint
36 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
37 | paint.setShader(shader);
38 |
39 | // Create and draw circle bitmap
40 | Bitmap output = Bitmap.createBitmap(minEdge, minEdge, source.getConfig());
41 | Canvas canvas = new Canvas(output);
42 | canvas.drawOval(new RectF(0, 0, minEdge, minEdge), paint);
43 |
44 | // Recycle the source bitmap, because we already generate a new one
45 | source.recycle();
46 |
47 | return output;
48 | }
49 |
50 | @Override
51 | public String key() {
52 | return KEY;
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/picasso/PicassoScrollListener.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util.picasso
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import com.squareup.picasso.Picasso
5 |
6 | /**
7 | * This is a scroll listener that listens for scroll events on recyclerviews
8 | * to avoid picasso loading images while scrolling (avoid laggy scroll behavior)
9 | */
10 | class PicassoScrollListener(private val picasso: Picasso) : RecyclerView.OnScrollListener() {
11 |
12 |
13 | companion object {
14 | val TAG = "PicassoScrollTag"
15 | }
16 |
17 | private var previousScrollState = RecyclerView.SCROLL_STATE_IDLE
18 | private var scrollingFirstTime = true
19 |
20 | init {
21 | picasso.resumeTag(TAG)
22 | }
23 |
24 | override fun onScrollStateChanged(view: RecyclerView?, scrollState: Int) {
25 | if (scrollingFirstTime) {
26 | resume()
27 | scrollingFirstTime = false
28 | }
29 |
30 | // TO the picasso staff
31 | if (!isScrolling(scrollState) && isScrolling(previousScrollState)) {
32 | resume()
33 | }
34 |
35 | if (isScrolling(scrollState) && !isScrolling(previousScrollState)) {
36 | pause()
37 | }
38 |
39 | previousScrollState = scrollState
40 |
41 | }
42 |
43 | private inline fun isScrolling(scrollState: Int): Boolean {
44 | return scrollState == RecyclerView.SCROLL_STATE_DRAGGING || scrollState == RecyclerView.SCROLL_STATE_SETTLING
45 | }
46 |
47 | private inline fun resume() {
48 | picasso.resumeTag(TAG)
49 | }
50 |
51 | private inline fun pause() {
52 | picasso.pauseTag(TAG)
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openconference/util/ui/SquaredImageView.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.util.ui
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.ImageView
6 |
7 | /**
8 | * An image view with square aspect ratio (respecting width).
9 | * @author Hannes Dorfmann
10 | */
11 | class SquaredImageView : ImageView {
12 | constructor(context: Context) : super(context) {
13 | }
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
16 | }
17 |
18 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
19 | super.onMeasure(widthMeasureSpec, heightMeasureSpec)
20 | setMeasuredDimension(measuredWidth, measuredWidth)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/add_to_schedule_line_1_move.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/add_to_schedule_line_1_trim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/add_to_schedule_line_2_move.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/add_to_schedule_line_2_untrim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/add_to_schedule_rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/remove_from_schedule_line_1_move.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/remove_from_schedule_line_1_untrim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/remove_from_schedule_line_2_move.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/remove_from_schedule_line_2_trim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/remove_from_schedule_rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_notification_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-hdpi/ic_notification_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_notification_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-mdpi/ic_notification_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_notification_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xhdpi/ic_notification_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_notification_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xxhdpi/ic_notification_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_notification_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/app/src/main/res/drawable-xxxhdpi/ic_notification_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avd_add_to_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avd_remove_from_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_to_schedule_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bio.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_link.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_location.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_my_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_remove_from_schedule_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_big.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sessions.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sessions_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_speakers.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_time.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_twitter.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_work.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_profile_pic_placeholder.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/separator_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | -
7 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/viewpager_separator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 | -
13 |
15 |
20 |
21 |
22 |
23 |
24 | -
27 |
29 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
25 |
26 |
34 |
35 |
36 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_session_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_sessions.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
14 |
15 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_twitter_timeline.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
17 |
18 |
19 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_details_icon_link_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
21 |
22 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_details_icon_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_search_speaker.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
21 |
22 |
31 |
32 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_date_sticky_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
18 |
19 |
20 |
28 |
29 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_details_date.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
21 |
22 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_details_description.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_details_location.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
20 |
21 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_details_separator.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_session_details_speaker.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
21 |
22 |
31 |
32 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_speaker.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_speaker_details_jobinfo.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
32 |
33 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/transition/auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OpenConference
4 |
5 | Sessions
6 | Mein Kalender
7 | Referenten
8 | #droidconDE
9 |
10 | Ein unerwarteter Fehler ist aufgetreten.
11 | Ungültige Suchanfrage
12 |
13 | dd.MM
14 | Leider sind noch keine Sessions verfügbar
15 | Keine Sessions in deinem Kalender.\nHier klicken um Sessions hinzuzufügen.
16 | Noch keine Daten für diese Session verfügbar
17 |
18 | Session hinzugefügt. Du bekommst eine Erinnerung 10 Minuten bevor die Session startet.
19 | Ein Fehler ist aufgetreten. Bitte wiederholen.
20 | Ein Fehler ist aufgetreten. Bitte wiederholen.
21 | Leider sind noch keine Daten vorhanden.
22 |
23 | Eine Session startet bald
24 | %1$s startet um %2$s
25 |
26 |
27 | Lizenzen
28 | Suche
29 |
30 |
31 | Suchbegriff ...
32 | Keine Ergebnisse gefunden
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #222222
4 | #000000
5 | #8ED300
6 | #78B300
7 |
8 | #6a6a6a
9 | #919191
10 |
11 |
12 | #F5F5F5
13 | #B9323232
14 |
15 |
16 | #A8A8A8
17 | #C2C2C2
18 |
19 |
20 | #E0E0E0
21 | #D6D6D6
22 |
23 |
24 | #1E222222
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
7 | 6dp
8 |
9 | 4dp
10 | 10dp
11 |
12 | 72dp
13 | 40dp
14 | 56dp
15 |
16 | 16dp
17 | 128dp
18 | 128dp
19 |
20 | 4dp
21 |
22 |
23 | 32dp
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/fractions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - 1.0
4 | - 0.96666664
5 | - 0.033333335
6 | - 0.768
7 | - 0.205
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2
5 | @android:integer/config_mediumAnimTime
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OpenConference
3 |
4 | Sessions
5 | My Schedule
6 | Speakers
7 | #droidconDE
8 |
9 |
10 | An unexpected error has occurred.
11 | The inserted query string is not valid
12 |
13 | MM/dd
14 |
15 | No sessions available yet. Stay tuned.
16 | No session in your schedule yet.\nClick here to browse all available sessions.
17 | No data for this session available yet
18 | Session has been added. You will receive a Notification 10 minutes before Session starts.
19 | An error has occurred. Please retry.
20 | An error has occurred. Please retry.
21 | No data for this speaker available yet
22 |
23 |
24 | A session starts soon
25 | %1$s starts at %2$s
26 |
27 |
28 | License
29 | Search
30 |
31 | Search ...
32 | No results found
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/playground/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/playground/java/com/openconfernce/MockNetworkModule.kt:
--------------------------------------------------------------------------------
1 | package com.openconfernce
2 |
3 | import android.content.Context
4 | import com.openconference.dagger.NetworkModule
5 | import com.openconference.model.backend.schedule.BackendScheduleAdapter
6 | import com.openconfernce.mock.MockSchedulerAdapterStub
7 |
8 | /**
9 | * This just mocks some data
10 | *
11 | * @author Hannes Dorfmann
12 | */
13 | class MockNetworkModule(c: Context) : NetworkModule(c) {
14 |
15 | override fun provideBackendAdapter(): BackendScheduleAdapter = MockSchedulerAdapterStub()
16 | }
--------------------------------------------------------------------------------
/app/src/playground/java/com/openconfernce/PlaygroundApp.kt:
--------------------------------------------------------------------------------
1 | package com.openconfernce
2 |
3 | import com.openconference.OpenConfApp
4 |
5 | /**
6 | * Application for demo purpose displaying som mocked data
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class PlaygroundApp : OpenConfApp() {
11 |
12 | override fun buildApplicationComponent() =
13 | super.buildApplicationComponent().networkModule(MockNetworkModule(this))
14 |
15 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/openconference/TestApplication.kt:
--------------------------------------------------------------------------------
1 | package com.openconference
2 |
3 | import android.app.Application
4 |
5 | /**
6 | * A test application instance without any additional dependencies (like Robolectric)
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | class TestApplication : Application() {
11 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/openconference/model/database/InstantParcelableTypeAdapterTest.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.database
2 |
3 | import android.os.Parcel
4 | import org.junit.Test
5 | import org.mockito.Mockito
6 | import org.threeten.bp.Instant
7 | import kotlin.test.assertEquals
8 |
9 | class InstantParcelableTypeAdapterTest {
10 |
11 | @Test
12 | fun writeToParcel() {
13 | val now = Instant.now()
14 | val nowMillis = now.toEpochMilli()
15 |
16 | val typeAdapter = InstantParcelableTypeAdapter()
17 | val parcel = Mockito.mock(Parcel::class.java)
18 |
19 | // Write to parcel
20 | typeAdapter.toParcel(now, parcel)
21 | Mockito.verify(parcel).writeLong(nowMillis)
22 |
23 | // Read from Parcel
24 | Mockito.`when`(parcel.readLong()).thenReturn(nowMillis)
25 | val instantFromParcel = typeAdapter.fromParcel(parcel)
26 |
27 | assertEquals(now, instantFromParcel)
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/openconference/model/notification/NotificationSchedulerCommandTest.kt:
--------------------------------------------------------------------------------
1 | package com.openconference.model.notification
2 |
3 | import com.openconference.model.Session
4 | import org.junit.Test
5 | import org.mockito.Mockito
6 |
7 | /**
8 | *
9 | *
10 | * @author Hannes Dorfmann
11 | */
12 | class NotificationSchedulerCommandTest {
13 |
14 | @Test
15 | fun removeScheduledNotification() {
16 | val notificationScheduler = Mockito.mock(NotificationScheduler::class.java)
17 | val session = Mockito.mock(Session::class.java)
18 |
19 | val command = RemoveScheduledNotificationCommand(session, notificationScheduler)
20 | command.execute()
21 |
22 | Mockito.verify(notificationScheduler, Mockito.only()).removeNotification(session)
23 | }
24 |
25 |
26 | @Test
27 | fun addOrRescheduleNotification() {
28 | val notificationScheduler = Mockito.mock(NotificationScheduler::class.java)
29 | val session = Mockito.mock(Session::class.java)
30 |
31 | val command = AddOrRescheduleNotificationCommand(session, notificationScheduler)
32 | command.execute()
33 |
34 | Mockito.verify(notificationScheduler, Mockito.only()).addOrRescheduleNotification(session)
35 | }
36 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenConference/OpenConference-android/b429bbf59b284ff25840f8d608d5fa9e270d4bc8/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 26 13:48:29 CEST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
7 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':stickyheaders'
2 | project(':stickyheaders').projectDir = new File('app/libraries/stickyheaders')
--------------------------------------------------------------------------------