├── cats
├── .gitignore
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ └── raw
│ │ │ │ └── cats.txt
│ │ └── java
│ │ │ └── com
│ │ │ └── ubergeek42
│ │ │ └── cats
│ │ │ ├── Printer.java
│ │ │ ├── Root.java
│ │ │ ├── Cat.java
│ │ │ ├── CatD.java
│ │ │ ├── KidKitty.java
│ │ │ └── RootKitty.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── ubergeek42
│ │ └── cats
│ │ └── ExampleInstrumentedTest.java
├── NOTICE.txt
├── proguard-rules.pro
└── build.gradle.kts
├── metadata
└── en-US
│ ├── title.txt
│ ├── changelogs
│ ├── 10401.txt
│ ├── 10301.txt
│ ├── 10701.txt
│ ├── 11001.txt
│ ├── 10402.txt
│ ├── 10400.txt
│ ├── 1200.txt
│ ├── 10501.txt
│ ├── 10700.txt
│ ├── 1000.txt
│ ├── 10801.txt
│ ├── 10500.txt
│ ├── 11000.txt
│ ├── 1100.txt
│ ├── 436.txt
│ ├── 1300.txt
│ ├── 435.txt
│ ├── 431.txt
│ ├── 10900.txt
│ ├── 10800.txt
│ ├── 10600.txt
│ └── 613.txt
│ ├── short_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── screenshot-1.png
│ │ ├── screenshot-2.png
│ │ ├── screenshot-3.png
│ │ ├── screenshot-4.png
│ │ ├── screenshot-5.png
│ │ └── screenshot-6.png
│ └── full_description.txt
├── settings.gradle.kts
├── releases
├── android.jks
├── qr-beta.png
├── qr-main.png
├── google-play-key.p12.enc
└── travis_build.sh
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── app
├── src
│ ├── main
│ │ ├── ic_launcher_kitty-web.png
│ │ ├── ic_launcher_weechat-web.png
│ │ ├── color_scheme_generator
│ │ │ ├── palettes.xcf
│ │ │ └── generate_test.py
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher_kitty.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher_kitty.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher_kitty.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher_kitty.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher_kitty.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_notification_hot.png
│ │ │ │ └── ic_notification_main.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_notification_hot.png
│ │ │ │ └── ic_notification_main.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_notification_hot.png
│ │ │ │ └── ic_notification_main.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_notification_hot.png
│ │ │ │ └── ic_notification_main.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ │ ├── ic_notification_hot.png
│ │ │ │ └── ic_notification_main.png
│ │ │ ├── values-fr-v29
│ │ │ │ └── strings.xml
│ │ │ ├── values-land
│ │ │ │ └── values.xml
│ │ │ ├── values-v29
│ │ │ │ └── strings.xml
│ │ │ ├── values-de-v29
│ │ │ │ └── strings.xml
│ │ │ ├── values-ru-v29
│ │ │ │ └── strings.xml
│ │ │ ├── values-large-land
│ │ │ │ └── values.xml
│ │ │ ├── layout
│ │ │ │ ├── squiggle.xml
│ │ │ │ ├── pref_password_edit_text.xml
│ │ │ │ ├── read_marker.xml
│ │ │ │ ├── dialog_list.xml
│ │ │ │ ├── dialog_paste_list.xml
│ │ │ │ ├── preferences.xml
│ │ │ │ ├── more_button.xml
│ │ │ │ ├── main_screen.xml
│ │ │ │ ├── certificate_dialog.xml
│ │ │ │ ├── certificate_dialog_certificate.xml
│ │ │ │ ├── dialog_copy_line.xml
│ │ │ │ ├── dialog_copy.xml
│ │ │ │ ├── preferences_full_screen_edit_text.xml
│ │ │ │ ├── toolbar_bell.xml
│ │ │ │ ├── about.xml
│ │ │ │ └── weasel.xml
│ │ │ ├── color
│ │ │ │ ├── button_text_color.xml
│ │ │ │ └── toolbar_icon.xml
│ │ │ ├── drawable
│ │ │ │ ├── bg_certificate.xml
│ │ │ │ ├── bg_popup_menu.xml
│ │ │ │ ├── progress_circle.xml
│ │ │ │ ├── bg_rounded_square.xml
│ │ │ │ ├── ic_toolbar_search_up.xml
│ │ │ │ ├── bg_paste_dialog_clipboard.xml
│ │ │ │ ├── ic_toolbar_search_down.xml
│ │ │ │ ├── etc_squiggle.xml
│ │ │ │ ├── ic_cancel.xml
│ │ │ │ ├── ic_toolbar_send.xml
│ │ │ │ ├── ic_fab_go_to_bottom.xml
│ │ │ │ ├── bg_bufferlist_item_hot.xml
│ │ │ │ ├── progress_rotating_dot.xml
│ │ │ │ ├── bg_bufferlist_item_warm.xml
│ │ │ │ ├── ic_toolbar_tab.xml
│ │ │ │ ├── ic_toolbar_bell.xml
│ │ │ │ ├── ic_toolbar_upload.xml
│ │ │ │ ├── ic_toolbar_bell_cracked.xml
│ │ │ │ ├── ic_toolbar_paperclip.xml
│ │ │ │ ├── ic_bufferlist_arrow_down.xml
│ │ │ │ ├── ic_bufferlist_arrow_up.xml
│ │ │ │ ├── ic_close_activity.xml
│ │ │ │ ├── ic_toolbar_magnifying_glass.xml
│ │ │ │ ├── ic_toolbar_upload_cancel.xml
│ │ │ │ ├── ic_big_disconnected.xml
│ │ │ │ ├── ic_toolbar_users.xml
│ │ │ │ ├── ic_big_connecting.xml
│ │ │ │ ├── ic_big_connected.xml
│ │ │ │ └── ic_copy_toolbar_select_text.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ └── ic_launcher_kitty.xml
│ │ │ ├── values-v24
│ │ │ │ └── values.xml
│ │ │ ├── values-night-v27
│ │ │ │ └── style.xml
│ │ │ ├── raw
│ │ │ │ └── cats.txt
│ │ │ ├── values-v27
│ │ │ │ └── style.xml
│ │ │ ├── values-night
│ │ │ │ ├── style.xml
│ │ │ │ └── colors.xml
│ │ │ ├── menu
│ │ │ │ ├── fullscreen_edit_text.xml
│ │ │ │ ├── copy_dialog_fullscreen.xml
│ │ │ │ └── menu_search.xml
│ │ │ ├── values-v23
│ │ │ │ └── style.xml
│ │ │ ├── xml
│ │ │ │ ├── filepaths.xml
│ │ │ │ └── shortcuts.xml
│ │ │ ├── values
│ │ │ │ ├── attrs.xml
│ │ │ │ └── colors.xml
│ │ │ ├── anim
│ │ │ │ ├── fast_out_extra_slow_in.xml
│ │ │ │ ├── activity_like_open_enter.xml
│ │ │ │ └── activity_like_close_exit.xml
│ │ │ ├── layout-large-land
│ │ │ │ └── main_screen.xml
│ │ │ └── drawable-night
│ │ │ │ ├── ic_toolbar_bell.xml
│ │ │ │ ├── ic_toolbar_bell_cracked.xml
│ │ │ │ └── ic_toolbar_users.xml
│ │ ├── java
│ │ │ ├── com
│ │ │ │ └── ubergeek42
│ │ │ │ │ └── WeechatAndroid
│ │ │ │ │ ├── adapters
│ │ │ │ │ └── BufferListClickListener.java
│ │ │ │ │ ├── utils
│ │ │ │ │ ├── ApplicationContext.kt
│ │ │ │ │ ├── WeaselMeasuringViewPager.kt
│ │ │ │ │ ├── ViewPagerFix.kt
│ │ │ │ │ ├── DefaultHashMap.java
│ │ │ │ │ ├── Debug.kt
│ │ │ │ │ ├── ActionEditText.java
│ │ │ │ │ ├── TinyMap.java
│ │ │ │ │ └── Toasts.kt
│ │ │ │ │ ├── relay
│ │ │ │ │ ├── BufferListEye.kt
│ │ │ │ │ ├── BufferNicklistEye.kt
│ │ │ │ │ ├── Nick.kt
│ │ │ │ │ └── BufferEye.kt
│ │ │ │ │ ├── media
│ │ │ │ │ ├── StrategyNull.java
│ │ │ │ │ ├── LineFilter.java
│ │ │ │ │ ├── OkHttpNullifyingInterceptor.java
│ │ │ │ │ ├── OkHttpSecuringInterceptor.java
│ │ │ │ │ ├── LimitedLengthInputStream.java
│ │ │ │ │ ├── HostUtils.java
│ │ │ │ │ └── RequestType.java
│ │ │ │ │ ├── service
│ │ │ │ │ ├── BootUpReceiver.java
│ │ │ │ │ ├── Events.kt
│ │ │ │ │ └── SyncAlarmReceiver.java
│ │ │ │ │ ├── views
│ │ │ │ │ ├── CircleView.kt
│ │ │ │ │ ├── SuppressedLinearLayoutManager.kt
│ │ │ │ │ ├── BackGestureAwareEditText.kt
│ │ │ │ │ └── FullScreenDrawerLinearLayoutManager.kt
│ │ │ │ │ ├── dialogs
│ │ │ │ │ └── FancyAlertDialogBuilder.java
│ │ │ │ │ ├── upload
│ │ │ │ │ └── HttpUriGetter.kt
│ │ │ │ │ ├── notifications
│ │ │ │ │ ├── MapSortedByValue.kt
│ │ │ │ │ └── Persons.kt
│ │ │ │ │ ├── tabcomplete
│ │ │ │ │ └── LocalTabCompleter.kt
│ │ │ │ │ ├── WeechatAboutActivity.kt
│ │ │ │ │ └── copypaste
│ │ │ │ │ └── CopyAdapter.java
│ │ │ └── androidx
│ │ │ │ └── preference
│ │ │ │ ├── DialogFragmentGetter.java
│ │ │ │ ├── ThemePreferenceHelp.kt
│ │ │ │ ├── FontPreferenceHelp.kt
│ │ │ │ ├── ClearKnownHostsPreference.kt
│ │ │ │ ├── HelpPreference.java
│ │ │ │ ├── ClearPreference.kt
│ │ │ │ ├── ClearCertPreference.kt
│ │ │ │ ├── CertPickerPreference.java
│ │ │ │ └── MultiSelectListPreferenceWithSummary.java
│ │ ├── inkscape
│ │ │ └── optimized
│ │ │ │ ├── ic_toolbar_search_up.svg
│ │ │ │ ├── ic_toolbar_search_down.svg
│ │ │ │ ├── ic_toolbar_send.svg
│ │ │ │ ├── etc_squiggle.svg
│ │ │ │ ├── ic_fab_go_to_bottom.svg
│ │ │ │ ├── ic_bufferlist_arrow_down.svg
│ │ │ │ ├── ic_bufferlist_arrow_up.svg
│ │ │ │ ├── ic_toolbar_bell.svg
│ │ │ │ ├── ic_toolbar_bell_dark.svg
│ │ │ │ ├── ic_toolbar_bell_light.svg
│ │ │ │ ├── ic_toolbar_bell_cracked_dark.svg
│ │ │ │ ├── ic_toolbar_bell_cracked_light.svg
│ │ │ │ ├── ic_big_disconnected.svg
│ │ │ │ ├── ic_toolbar_users_dark.svg
│ │ │ │ ├── ic_toolbar_users_light.svg
│ │ │ │ ├── ic_big_connecting.svg
│ │ │ │ ├── ic_big_connected.svg
│ │ │ │ ├── ic_toolbar_magnifying_glass.svg
│ │ │ │ └── ic_copy_toolbar_select_text.svg
│ │ ├── resources
│ │ │ └── android-logger.properties
│ │ └── assets
│ │ │ └── basic-terminal-theme.properties
│ ├── testDebug
│ │ └── java
│ │ │ └── com
│ │ │ └── ubergeek42
│ │ │ └── WeechatAndroid
│ │ │ └── utils
│ │ │ └── ApplicationContext.kt
│ ├── dev
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ └── debug
│ │ └── res
│ │ └── values
│ │ ├── strings.xml
│ │ └── values.xml
└── schemas
│ ├── com.ubergeek42.WeechatAndroid.media.CachePersist.AttemptDatabase
│ └── 1.json
│ ├── com.ubergeek42.WeechatAndroid.upload.UploadDatabase.UploadRecordsDatabase
│ └── 1.json
│ └── com.ubergeek42.WeechatAndroid.notifications.ShortcutStatisticsDatabase.RecordsDatabase
│ └── 1.json
├── relay
├── Readme.md
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── ubergeek42
│ │ │ └── weechat
│ │ │ ├── relay
│ │ │ ├── connection
│ │ │ │ ├── IObserver.java
│ │ │ │ ├── IConnection.java
│ │ │ │ ├── SimpleConnection.kt
│ │ │ │ └── Events.java
│ │ │ ├── messagehandler
│ │ │ │ ├── UpgradeObserver.java
│ │ │ │ ├── HotlistManagerObserver.java
│ │ │ │ ├── BuffersChangedObserver.java
│ │ │ │ └── UpgradeHandler.java
│ │ │ ├── RelayMessageHandler.java
│ │ │ └── protocol
│ │ │ │ ├── Info.java
│ │ │ │ ├── Hashtable.java
│ │ │ │ └── Array.java
│ │ │ ├── SslUtils.kt
│ │ │ ├── HexUtils.kt
│ │ │ ├── BufferObserver.java
│ │ │ └── Helper.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── ubergeek42
│ │ └── weechat
│ │ └── HexUtilsTest.kt
└── build.gradle.kts
├── crowdin.yml
├── .gitignore
├── weechat-relay-example
├── README
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── ubergeek42
│ └── relayexample
│ ├── InfoMessageHandler.java
│ ├── InfolistMessageHandler.java
│ └── TestMessageHandler.java
└── gradle.properties
/cats/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/metadata/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Weechat-Android
2 |
--------------------------------------------------------------------------------
/cats/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10401.txt:
--------------------------------------------------------------------------------
1 | * Fixed a few bugs
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10301.txt:
--------------------------------------------------------------------------------
1 | * Fixed F-Droid builds
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10701.txt:
--------------------------------------------------------------------------------
1 | * Fixed an issue of disappearing bubbles
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/11001.txt:
--------------------------------------------------------------------------------
1 | * Fixed a rare crash when a line gets unhidden
--------------------------------------------------------------------------------
/metadata/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Relay client for the WeeChat IRC client.
2 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | include(":cats")
2 | include(":relay")
3 | include(":app")
4 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10402.txt:
--------------------------------------------------------------------------------
1 | * Fixed freeform window mode
2 | * Fixed a few rare crashes
--------------------------------------------------------------------------------
/releases/android.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/releases/android.jks
--------------------------------------------------------------------------------
/releases/qr-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/releases/qr-beta.png
--------------------------------------------------------------------------------
/releases/qr-main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/releases/qr-main.png
--------------------------------------------------------------------------------
/cats/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Cats
3 |
4 |
--------------------------------------------------------------------------------
/metadata/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/icon.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10400.txt:
--------------------------------------------------------------------------------
1 | * Implemented command and channel name completion
2 | * Updated icons to have wireframe look
--------------------------------------------------------------------------------
/releases/google-play-key.p12.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/releases/google-play-key.p12.enc
--------------------------------------------------------------------------------
/app/src/main/ic_launcher_kitty-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/ic_launcher_kitty-web.png
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/1200.txt:
--------------------------------------------------------------------------------
1 | * Let users interactively accept or reject SSH host keys
2 | * Accept private SSH keys in PKCS #8 format
--------------------------------------------------------------------------------
/app/src/main/ic_launcher_weechat-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/ic_launcher_weechat-web.png
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10501.txt:
--------------------------------------------------------------------------------
1 | * Fixed a crash when the password has never been set
2 | * Fixed a crash when using Modern handshake on Android 7-
--------------------------------------------------------------------------------
/app/src/main/color_scheme_generator/palettes.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/color_scheme_generator/palettes.xcf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_kitty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_kitty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_kitty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_kitty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_kitty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_kitty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_kitty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_kitty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_kitty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_kitty.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_notification_hot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-hdpi/ic_notification_hot.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_notification_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-hdpi/ic_notification_main.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_notification_hot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-mdpi/ic_notification_hot.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_notification_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-mdpi/ic_notification_main.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_notification_hot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xhdpi/ic_notification_hot.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-1.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-2.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-3.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-4.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-5.png
--------------------------------------------------------------------------------
/metadata/en-US/images/phoneScreenshots/screenshot-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/metadata/en-US/images/phoneScreenshots/screenshot-6.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_notification_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xhdpi/ic_notification_main.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_notification_hot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_notification_hot.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_notification_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_notification_main.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_notification_hot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_notification_hot.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_notification_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubergeek42/weechat-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_notification_main.png
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10700.txt:
--------------------------------------------------------------------------------
1 | * Removed storage access permission on Android 9+
2 | * Added launcher and direct share shortcuts
3 | * Added support for Bubbles on Android 11
--------------------------------------------------------------------------------
/relay/Readme.md:
--------------------------------------------------------------------------------
1 | #Build Instructions
2 | This project is designed to be compiled with ant. It will produce a weechat-relay.jar file which you can include in your projects.
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr-v29/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Système
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 26dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v29/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | System default
4 |
--------------------------------------------------------------------------------
/cats/NOTICE.txt:
--------------------------------------------------------------------------------
1 | This product includes code from the project Hugo, licensed under the Apache License, Version 2.0
2 | Copyright 2013 Jake Wharton (https://github.com/JakeWharton/hugo)
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de-v29/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Systemstandardeinstellung
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru-v29/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Устанавливается системой
4 |
--------------------------------------------------------------------------------
/cats/src/main/res/raw/cats.txt:
--------------------------------------------------------------------------------
1 | # disabled tags in format tag, tag/*, tag/subtag, */subtag
2 | # subtags ?, ??, ??? provide increasingly more verbose information
3 |
4 | */?
5 | */??
6 | */???
7 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/1000.txt:
--------------------------------------------------------------------------------
1 | * Added media preview
2 | * Raised minimum Android version to Lollipop (5.0, API level 21)
3 | * Added German translation
4 | * Improved support for notify levels
5 |
--------------------------------------------------------------------------------
/app/src/testDebug/java/com/ubergeek42/WeechatAndroid/utils/ApplicationContext.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import android.content.Context
4 |
5 | lateinit var applicationContext: Context
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10801.txt:
--------------------------------------------------------------------------------
1 | * Fixed an issue with ED25519 keys during upgrade
2 | * Update Android Gradle Plugin to fix build on F-Droid
3 | * Rework ping logic to comply with Google Play requirements
4 |
--------------------------------------------------------------------------------
/app/src/dev/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.ubergeek42.WeechatAndroid.dev
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-large-land/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2dp
4 | false
5 |
6 |
--------------------------------------------------------------------------------
/crowdin.yml:
--------------------------------------------------------------------------------
1 | files:
2 | - source: /app/src/main/res/values/strings.xml
3 | translation: /app/src/main/res/values-%two_letters_code%/strings.xml
4 | translate_attributes: 0
5 | content_segmentation: 0
6 |
--------------------------------------------------------------------------------
/app/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.ubergeek42.WeechatAndroid.debug
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 | #588ab8
6 |
7 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10500.txt:
--------------------------------------------------------------------------------
1 | * Added support for the handshake relay command
2 | * Improved the way URLs are recognized
3 | * Black background is no longer shown when switching buffers
4 | * Fixed a couple of rare crashes
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/adapters/BufferListClickListener.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.adapters;
2 |
3 |
4 | public interface BufferListClickListener {
5 | void onBufferClick(long pointer);
6 | }
7 |
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/Printer.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import android.util.Log;
4 |
5 | class Printer {
6 | void println(int priority, String tag, String msg) {
7 | Log.println(priority, tag, msg);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/11000.txt:
--------------------------------------------------------------------------------
1 | * Added an option to not move hot buffers to the top of the buffer list
2 | * Handle relay events `_buffer_cleared` and `_buffer_line_data_changed`
3 | * Updated the default media preview strategies
4 | * A few minor bug fixes and improvements
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/ApplicationContext.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import android.content.Context
4 | import com.ubergeek42.WeechatAndroid.Weechat
5 |
6 | @JvmField val applicationContext: Context = Weechat.applicationContext
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/DialogFragmentGetter.java:
--------------------------------------------------------------------------------
1 | package androidx.preference;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.fragment.app.DialogFragment;
5 |
6 | public interface DialogFragmentGetter {
7 | @NonNull DialogFragment getDialogFragment();
8 | }
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jul 12 20:01:32 BST 2020
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-8.9-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/squiggle.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/metadata/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | This is a WeeChat relay client for Android.
2 |
3 | This application is not a standalone an IRC client. It connects to WeeChat that has to be running on a remote machine. If you are looking for a standalone IRC client for Android, you will need to look elsewhere.
4 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_search_up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/resources/android-logger.properties:
--------------------------------------------------------------------------------
1 | # suppress inspection "UnusedProperty" for whole file
2 |
3 | # a simple logger suitable for release
4 | # root=INFO:%logger:
5 |
6 | # logger that prints all messages and in addition prints the name of the thread
7 | root=VERBOSE:\ud83d\udc36:%-4.4(%t) : %logger
8 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/1100.txt:
--------------------------------------------------------------------------------
1 | * Added a new certificate dialog that displays the full certificate chain
2 | * Implemented SSL certificate pinning
3 | * Support for client SSL certificates
4 | * Added support for Ed25519 keys thanks to sshlib
5 | * When possible, RSA, EC, DSA keys are stored inside secure hardware
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/436.txt:
--------------------------------------------------------------------------------
1 | * Service to run only while connecting/connected; quit button removed
2 | * “Fetch more” button
3 | * SSH library update; require known hosts; store known hosts and key inside app
4 | * Significant refactoring of connectivity; stunnel removed
5 | * Better logging and error handling
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/BufferListEye.kt:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | package com.ubergeek42.WeechatAndroid.relay
4 |
5 | interface BufferListEye {
6 | fun onBuffersChanged()
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/color/button_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_certificate.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_search_down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/1300.txt:
--------------------------------------------------------------------------------
1 | * Allow uploading files via user-supplied HTTP POST services
2 | * Added file picker/take photo button
3 | * App can be a share target for files as well as text
4 | * App can receive media through keyboard
5 | * Parts of the app are using Kotlin now!
6 | * Toast background is colored to signify success or failure
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Android
2 | local.properties
3 | *.apk
4 |
5 | # Android Studio/InteliJ IDEA
6 | .idea
7 | *.iml
8 |
9 | # Gradle stuff
10 | .gradle
11 | build
12 | /captures
13 | /app/dev
14 | /app/release
15 |
16 | # eclipse project stuff
17 | .settings
18 | .project
19 | .classpath
20 | .metadata
21 |
22 | # vim
23 | *.swp
24 | *.swo
25 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_kitty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/435.txt:
--------------------------------------------------------------------------------
1 | * Material design
2 | * Ping mechanism
3 | * Color schemes
4 | * Read marker line
5 | * Ability to resend lines
6 | * Font preference
7 | * More notification options
8 | * Weechat → relay synchronization every 5 minutes
9 | * Validation of settings
10 | * Better url detection
11 | * A bunch of stability fixes
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_popup_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/431.txt:
--------------------------------------------------------------------------------
1 | * Bundled notifications with instant reply on Android 7+
2 | * A menu switch that instantly turns filtering on or off
3 | * Use RecyclerView that comes with some animations
4 | * Buffer title is now at the top of buffer lines
5 | * Ask user for permission to read external storage
6 | * Library updates and stability fixes
7 |
--------------------------------------------------------------------------------
/weechat-relay-example/README:
--------------------------------------------------------------------------------
1 | This is a simple demo program showing how to connect to a Weechat Relay server, send it messages, and hook responses from it.
2 |
3 | This will gain more documentation and possibly testcases in the future.
4 |
5 | Compile the sample weechat-relay-example.jar using ant. You must have previously built the library in ../weechat-relay
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_rounded_square.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/pref_password_edit_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/connection/IObserver.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat.relay.connection;
2 |
3 | import com.ubergeek42.weechat.relay.RelayMessage;
4 |
5 | public interface IObserver {
6 | void onStateChanged(RelayConnection.STATE state);
7 | void onException(Exception e);
8 | void onMessage(RelayMessage message);
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_send.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/Root.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.FIELD;
8 |
9 | @Retention(RetentionPolicy.CLASS)
10 | @Target(FIELD)
11 | public @interface Root {}
12 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/etc_squiggle.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/toolbar_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/BufferNicklistEye.kt:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | package com.ubergeek42.WeechatAndroid.relay
4 |
5 | import androidx.annotation.AnyThread
6 |
7 | interface BufferNicklistEye {
8 | @AnyThread fun onNicklistChanged()
9 | }
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10900.txt:
--------------------------------------------------------------------------------
1 | * Drag and drop files on buffers to share
2 | * Volume keys can now navigate input history
3 | * Fixed strange behavior resulting from handling WeeChat pointers as signed numbers
4 | * Fixed importing of PKCS #8 Ed25519 keys
5 | * Target Android API 34, ask for notification & exact alarm permissions where applicable
6 | * A few minor bug fixes and improvements
--------------------------------------------------------------------------------
/app/src/main/res/values-v24/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - chat
5 | - paste
6 | - notifications
7 |
8 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10800.txt:
--------------------------------------------------------------------------------
1 | * Render the latest emoji on older systems
2 | * Certificate dialog now shows trusted chain if available
3 | * Fixed not being able to connect to servers that require SNI
4 | * Fixed cleartext web traffic not going through
5 | * Fixed wrong message shown in case of TLS error
6 | * Fixed a crash if an URL with the ellipsis character is encountered
7 | * Fixed a very rare inconsistent Bubble behavior
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_fab_go_to_bottom.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night-v27/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/StrategyNull.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import java.util.List;
4 |
5 | class StrategyNull extends Strategy {
6 | StrategyNull(String name, List hosts) {
7 | super(name, hosts);
8 | }
9 |
10 | @Override Url make(String url, Size size) throws CancelFurtherAttempts {
11 | throw new Strategy.CancelFurtherAttempts();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/cats.txt:
--------------------------------------------------------------------------------
1 | # disabled tags in format tag, tag/*, tag/subtag, */subtag
2 | # subtags ?, ??, ??? provide increasingly more verbose information
3 |
4 | # ui
5 | WA/*
6 | ChatLinesAdapter/Scrolling
7 | BLF
8 | #Notificator
9 |
10 | # service
11 | RelayService
12 | RelayConnection
13 | BufferList/*
14 | Buffer/*
15 | Lines
16 | Line
17 |
18 | # general-purpose
19 | */?
20 | */??
21 | */???
22 |
--------------------------------------------------------------------------------
/weechat-relay-example/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'application'
3 |
4 | dependencies {
5 | compile project(':weechat-relay')
6 | compile 'org.slf4j:slf4j-api:1.7.12'
7 |
8 | runtime 'org.slf4j:slf4j-simple:1.7.12'
9 | }
10 |
11 | mainClassName="com.ubergeek42.relayexample.RelayExample"
12 |
13 | compileJava {
14 | sourceCompatibility = JavaVersion.VERSION_1_7
15 | targetCompatibility = JavaVersion.VERSION_1_7
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/Nick.kt:
--------------------------------------------------------------------------------
1 | //Licensed under the Apache License, Version 2.0 (the "License");
2 | //you may not use this file except in compliance with the License.
3 | package com.ubergeek42.WeechatAndroid.relay
4 |
5 | class Nick(
6 | @JvmField val pointer: Long,
7 | @JvmField val prefix: String,
8 | @JvmField val name: String,
9 | @JvmField val away: Boolean,
10 | ) {
11 | fun asString() = prefix + name
12 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_search_up.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_paste_dialog_clipboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_search_down.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/read_marker.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v27/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/etc_squiggle.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/color_scheme_generator/generate_test.py:
--------------------------------------------------------------------------------
1 | def gen(fg=True):
2 | out = ""
3 | for y in range(32):
4 | out += "/eval /print "
5 | for x in range(8):
6 | out += "${color:"
7 | if not fg:
8 | out += str(y * 8 + x)
9 | out += ","
10 | index = y * 8 + x
11 | out += str(index)
12 | out += "}"
13 | out += f"{index:03}"
14 | out += "\n"
15 | return out
16 |
17 |
18 | print(gen(True) + gen(False))
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cancel.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_send.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/assets/basic-terminal-theme.properties:
--------------------------------------------------------------------------------
1 | # suppress inspection "UnusedProperty" for whole file
2 | name = Basic Terminal
3 |
4 | default = 0xC0C0C0
5 | default_bg = 0x000000
6 |
7 | color0 = 0x000000
8 | color1 = 0x800000
9 | color2 = 0x008000
10 | color3 = 0x808000
11 | color4 = 0x000080
12 | color5 = 0x800080
13 | color6 = 0x008080
14 | color7 = 0xC0C0C0
15 | color8 = 0x808080
16 | color9 = 0xFF0000
17 | color10 = 0x00FF00
18 | color11 = 0xFFFF00
19 | color12 = 0x0000FF
20 | color13 = 0xFF00FF
21 | color14 = 0x00FFFF
22 | color15 = 0xFFFFFF
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_bufferlist_arrow_down.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/fullscreen_edit_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v23/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fab_go_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/10600.txt:
--------------------------------------------------------------------------------
1 | * Added search functionality
2 | * Added a floating “go to bottom” button
3 | * Added a connectivity indicator
4 | * Copy dialog can now select text and copy several messages at once
5 | * Interface is no longer locked up while disconnected
6 | * Chat lines are no longer thrown away when not synchronizing
7 | * Chat scroll position is now remembered on rotation
8 | * App is now drawn behind system bars on supported devices
9 | * Added new chat line change animations
10 | * Local tab completer is no longer used when completing command-like text
11 | * A lot of internal changes and bug fixes
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/Cat.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.CONSTRUCTOR;
8 | import static java.lang.annotation.ElementType.METHOD;
9 | import static java.lang.annotation.ElementType.TYPE;
10 |
11 | @Retention(RetentionPolicy.RUNTIME)
12 | @Target({TYPE, METHOD, CONSTRUCTOR})
13 | public @interface Cat {
14 | String value() default "";
15 | boolean linger() default false;
16 | boolean exit() default false;
17 | }
18 |
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/CatD.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.lang.annotation.Target;
6 |
7 | import static java.lang.annotation.ElementType.CONSTRUCTOR;
8 | import static java.lang.annotation.ElementType.METHOD;
9 | import static java.lang.annotation.ElementType.TYPE;
10 |
11 | @Retention(RetentionPolicy.RUNTIME)
12 | @Target({TYPE, METHOD, CONSTRUCTOR})
13 | public @interface CatD {
14 | String value() default "";
15 | boolean linger() default false;
16 | boolean exit() default false;
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_paste_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_bufferlist_arrow_up.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_bell.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_bufferlist_item_hot.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_rotating_dot.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/relay/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `java-library`
3 | kotlin("jvm")
4 | kotlin("plugin.serialization")
5 | }
6 |
7 | dependencies {
8 | implementation(libs.slf4j.api)
9 |
10 | // "api" because we are calling `SSHConnection.getKnownHosts` from the app
11 | // and it returns something from inside sshlib
12 | api(libs.sshlib)
13 |
14 | implementation(libs.nvwebsocketclient)
15 |
16 | implementation(libs.kotlinx.serialization.json)
17 |
18 | testImplementation(libs.junit.jupiter)
19 | }
20 |
21 | tasks.withType {
22 | options.encoding = "UTF-8"
23 | }
24 |
25 | java.toolchain.languageVersion = JavaLanguageVersion.of(21)
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_bell_dark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_bufferlist_item_warm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_bell_light.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/copy_dialog_fullscreen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_bell_cracked_dark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_bell_cracked_light.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/ThemePreferenceHelp.kt:
--------------------------------------------------------------------------------
1 | package androidx.preference
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import androidx.core.text.HtmlCompat
6 | import com.ubergeek42.WeechatAndroid.R
7 |
8 |
9 | class ThemePreferenceHelp(context: Context?, attrs: AttributeSet?) : HelpPreference(context, attrs) {
10 | override fun getSummary(): CharSequence {
11 | val indent = "
"
12 | val directories = ThemeManager.getThemeSearchDirectories(context)
13 | val message = context.getString(R.string.pref__ThemePreferenceHelp__summary,
14 | indent + directories.joinToString(indent))
15 |
16 | return HtmlCompat.fromHtml(message, HtmlCompat.FROM_HTML_MODE_LEGACY)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/filepaths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/weechat-relay-example/src/main/java/com/ubergeek42/relayexample/InfoMessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.relayexample;
2 | import com.ubergeek42.weechat.relay.RelayMessageHandler;
3 | import com.ubergeek42.weechat.relay.protocol.Info;
4 | import com.ubergeek42.weechat.relay.protocol.RelayObject;
5 |
6 |
7 | public class InfoMessageHandler implements RelayMessageHandler {
8 |
9 | @Override
10 | public void handleMessage(RelayObject obj, String id) {
11 | if (id.equals("info-test")) {
12 | if (!(obj instanceof Info)) {
13 | System.err.println("Error: unexpected object type");
14 | }
15 | Info info = (Info) obj;
16 | System.out.printf("[Info] %s = %s\n", info.getName(), info.getValue());
17 | } else {
18 | System.err.println("Unexpected message ID");
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/LineFilter.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import com.ubergeek42.WeechatAndroid.relay.Line;
6 |
7 | import java.util.List;
8 | import java.util.regex.Pattern;
9 |
10 | class LineFilter {
11 | final private @Nullable List nicks;
12 | final private @Nullable Pattern pattern;
13 |
14 | LineFilter(@Nullable List nicks, @Nullable String regex) {
15 | this.nicks = nicks;
16 | this.pattern = regex == null ? null : Pattern.compile(regex);
17 | }
18 |
19 | boolean filters(Line line) {
20 | return (nicks == null || nicks.contains(line.nick)) &&
21 | (pattern == null || pattern.matcher(line.getMessageString()).find());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/WeaselMeasuringViewPager.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.ubergeek42.WeechatAndroid.service.P
6 | import com.ubergeek42.WeechatAndroid.views.windowInsets
7 |
8 | class WeaselMeasuringViewPager : ViewPagerFix {
9 | constructor(context: Context) : super(context)
10 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
11 |
12 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
13 | super.onMeasure(widthMeasureSpec, heightMeasureSpec)
14 | measuredWidth.let {
15 | if (it > 0) weaselWidth = it - windowInsets.left - windowInsets.right
16 | }
17 | }
18 |
19 | var weaselWidth = 0
20 | }
--------------------------------------------------------------------------------
/releases/travis_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "$DEVSTOREFILE" ]; then
4 | DEVSTOREFILE="releases/android.jks"
5 | fi
6 |
7 | if [ -z "$DEVKEYALIAS" ]; then
8 | DEVKEYALIAS="weechat"
9 | fi
10 |
11 | DEV="1"
12 | if [ -z "$DEVSTOREPASSWORD" ]; then
13 | echo "\$DEVSTOREPASSWORD must be set to build a release"
14 | DEV="0"
15 | fi
16 |
17 | if [ -z "$DEVKEYPASSWORD" ]; then
18 | echo "\$DEVKEYPASSWORD must be set to build a release"
19 | DEV="0"
20 | fi
21 |
22 | if [ "$DEV" == "1" ]; then
23 | ./gradlew --no-daemon clean :app:assembleDev \
24 | -PdevStorefile="$DEVSTOREFILE" \
25 | -PdevStorePassword="$DEVSTOREPASSWORD" \
26 | -PdevKeyAlias="$DEVKEYALIAS" \
27 | -PdevKeyPassword="$DEVKEYPASSWORD"
28 | else
29 | ./gradlew clean :app:assembleDebug
30 | fi
31 |
32 | exit $?
33 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/FontPreferenceHelp.kt:
--------------------------------------------------------------------------------
1 | package androidx.preference
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import androidx.core.text.HtmlCompat
6 | import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
7 | import com.ubergeek42.WeechatAndroid.R
8 |
9 |
10 | class FontPreferenceHelp(context: Context?, attrs: AttributeSet?) : HelpPreference(context, attrs) {
11 | override fun getSummary(): CharSequence {
12 | val indent = "
"
13 | val directories = FontManager.getFontSearchDirectories(context)
14 | val message = context.getString(R.string.pref__FontPreferenceHelp__summary,
15 | indent + directories.joinToString(indent))
16 |
17 | return HtmlCompat.fromHtml(message, FROM_HTML_MODE_LEGACY)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/ViewPagerFix.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import androidx.viewpager.widget.ViewPager
7 |
8 | // this is a workaround for a very rare crash
9 | // https://stackoverflow.com/questions/16459196
10 |
11 | open class ViewPagerFix : ViewPager {
12 | constructor(context: Context) : super(context)
13 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
14 |
15 | override fun onInterceptTouchEvent(ev: MotionEvent?) =
16 | try {
17 | super.onInterceptTouchEvent(ev)
18 | } catch (e: IllegalArgumentException) {
19 | e.printStackTrace()
20 | false
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/relay/BufferEye.kt:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | package com.ubergeek42.WeechatAndroid.relay
4 |
5 | import androidx.annotation.MainThread
6 | import androidx.annotation.WorkerThread
7 |
8 | interface BufferEye {
9 | // server sent us all lines
10 | @WorkerThread fun onLinesListed()
11 |
12 | // 1 line added on bottom
13 | @WorkerThread fun onLineAdded()
14 |
15 | // indicates changed title
16 | @WorkerThread fun onTitleChanged()
17 |
18 | // buffer was closed in weechat
19 | @WorkerThread fun onBufferClosed()
20 |
21 | // all lines should be re-rendered due to font size change and such
22 | @MainThread fun onGlobalPreferencesChanged(numberChanged: Boolean)
23 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_tab.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/OkHttpNullifyingInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import com.ubergeek42.cats.Kitty;
4 | import com.ubergeek42.cats.Root;
5 |
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.io.IOException;
9 |
10 | import okhttp3.Interceptor;
11 | import okhttp3.Request;
12 | import okhttp3.Response;
13 |
14 | class OkHttpNullifyingInterceptor implements Interceptor {
15 | final private static @Root Kitty kitty = Kitty.make();
16 |
17 | @NotNull @Override public Response intercept(@NotNull Chain chain) throws IOException {
18 | Request request = chain.request();
19 |
20 | if (Engine.hasNullStrategyFor(request.url()))
21 | throw new Exceptions.RedirectToNullStrategyException(request.url().toString());
22 |
23 | return chain.proceed(request);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/more_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/DefaultHashMap.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.util.HashMap;
7 |
8 | // this exists because computeIfAbsent(K, Function) requires API 24
9 | public class DefaultHashMap extends HashMap {
10 | public interface Factory {
11 | @NonNull V make(K key);
12 | }
13 |
14 | final private Factory factory;
15 |
16 | public DefaultHashMap(Factory factory) {
17 | super();
18 | this.factory = factory;
19 | }
20 |
21 | @NonNull public V computeIfAbsent(@Nullable K key) {
22 | V value = super.get(key);
23 | if (value == null) {
24 | value = factory.make(key);
25 | put(key, value);
26 | }
27 | return value;
28 | }
29 | }
--------------------------------------------------------------------------------
/cats/src/androidTest/java/com/ubergeek42/cats/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Testo
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ubergeek42.cats.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_big_disconnected.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/service/BootUpReceiver.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.service;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.os.Build;
8 | import android.preference.PreferenceManager;
9 |
10 | import static com.ubergeek42.WeechatAndroid.utils.Constants.*;
11 |
12 |
13 | public class BootUpReceiver extends BroadcastReceiver {
14 |
15 | @Override public void onReceive(Context context, Intent intent) {
16 | if (!"android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) return;
17 |
18 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
19 | if (prefs.getBoolean(PREF_BOOT_CONNECT, PREF_BOOT_CONNECT_D)) {
20 | RelayService.startWithAction(context, RelayService.ACTION_START);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/views/CircleView.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.views
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Paint
6 | import android.util.AttributeSet
7 | import android.view.View
8 | import com.ubergeek42.WeechatAndroid.upload.f
9 |
10 |
11 | class CircleView @JvmOverloads constructor(
12 | context: Context,
13 | attrs: AttributeSet? = null,
14 | ) : View(context, attrs) {
15 |
16 | private val paint = Paint().apply {
17 | isAntiAlias = true
18 | style = Paint.Style.FILL
19 | }
20 |
21 | fun setColor(color: Int) {
22 | if (color != paint.color) {
23 | paint.color = color
24 | invalidate()
25 | }
26 | }
27 |
28 | override fun onDraw(canvas: Canvas) {
29 | val x = width.f / 2
30 | val y = height.f / 2
31 |
32 | canvas.drawCircle(x, y, x, paint)
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/fast_out_extra_slow_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-large-land/main_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/ic_toolbar_bell.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/dialogs/FancyAlertDialogBuilder.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.dialogs;
2 |
3 | import android.content.Context;
4 | import android.graphics.LightingColorFilter;
5 |
6 | import com.ubergeek42.WeechatAndroid.R;
7 | import com.ubergeek42.WeechatAndroid.service.P;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.appcompat.app.AlertDialog;
11 |
12 | public class FancyAlertDialogBuilder extends AlertDialog.Builder {
13 | public FancyAlertDialogBuilder(@NonNull Context context) {
14 | super(context, R.style.AlertDialogTheme);
15 | }
16 |
17 | @Override
18 | public AlertDialog create() {
19 | AlertDialog dialog = super.create();
20 | if (dialog.getWindow() != null) {
21 | dialog.getWindow().getDecorView().getBackground().
22 | setColorFilter(new LightingColorFilter(0xFF000000, P.colorPrimary));
23 | }
24 | return dialog;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_bell.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_upload.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/ic_toolbar_bell_cracked.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/messagehandler/UpgradeObserver.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.messagehandler;
17 |
18 | public interface UpgradeObserver {
19 | public void onUpgrade();
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_bell_cracked.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Debug.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import androidx.recyclerview.widget.ListUpdateCallback
5 |
6 | fun DiffUtil.DiffResult.print(name: String) {
7 | println("diff result: $name")
8 |
9 | dispatchUpdatesTo(object : ListUpdateCallback {
10 | override fun onInserted(position: Int, count: Int) {
11 | println(":: inserting $count items at position $position")
12 | }
13 |
14 | override fun onRemoved(position: Int, count: Int) {
15 | println(":: removing $count items at position $position")
16 | }
17 |
18 | override fun onMoved(fromPosition: Int, toPosition: Int) {
19 | println(":: moving item from $fromPosition to $toPosition")
20 | }
21 |
22 | override fun onChanged(position: Int, count: Int, payload: Any?) {
23 | println(":: changing $count items starting from position $position")
24 | }
25 | })
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/ActionEditText.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils;
2 |
3 | import android.content.Context;
4 | import androidx.appcompat.widget.AppCompatEditText;
5 | import android.util.AttributeSet;
6 | import android.view.inputmethod.EditorInfo;
7 | import android.view.inputmethod.InputConnection;
8 |
9 | public class ActionEditText extends AppCompatEditText {
10 | public ActionEditText(Context context) {
11 | super(context);
12 | }
13 |
14 | public ActionEditText(Context context, AttributeSet attrs) {
15 | super(context, attrs);
16 | }
17 |
18 | public ActionEditText(Context context, AttributeSet attrs, int defStyle) {
19 | super(context, attrs, defStyle);
20 | }
21 |
22 | @Override
23 | public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
24 | InputConnection conn = super.onCreateInputConnection(outAttrs);
25 | outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
26 | return conn;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/KidKitty.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import static com.ubergeek42.cats.Cats.disabled;
7 |
8 |
9 | class KidKitty extends Kitty {
10 | private final @NonNull RootKitty mom;
11 |
12 | KidKitty(@NonNull RootKitty mom, @NonNull String tag) {
13 | super(tag);
14 | this.mom = mom;
15 | enabled = !(disabled.contains(mom.tag + "/*") ||
16 | disabled.contains(mom.tag + "/" + tag) ||
17 | disabled.contains("*/" + tag));
18 | }
19 |
20 | @Override String getTag() {
21 | return mom.tag + "/" + this.tag;
22 | }
23 |
24 | @Override @Nullable String getPrefix() {
25 | return mom.prefix;
26 | }
27 |
28 | @Override public KidKitty kid(@NonNull String tag) {
29 | return mom.kid(tag);
30 | }
31 |
32 | @Override public void setPrefix(@Nullable String prefix) {
33 | mom.setPrefix(prefix);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_paperclip.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/connection/IConnection.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat.relay.connection;
2 |
3 | import com.neovisionaries.ws.client.WebSocketException;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.OutputStream;
8 |
9 | public interface IConnection {
10 |
11 | class Streams {
12 | final InputStream inputStream;
13 | final OutputStream outputStream;
14 |
15 | Streams(InputStream inputStream, OutputStream outputStream) {
16 | this.inputStream = inputStream;
17 | this.outputStream = outputStream;
18 | }
19 | }
20 |
21 | // blocking connect. return 2 streams, output stream is optional
22 | Streams connect() throws IOException, InterruptedException, WebSocketException;
23 |
24 | // non-blocking disconnect. can be called during the connect() call. the connection is supposed
25 | // to be closed immediately or in the next few seconds. can be called several times with no harm
26 | void disconnect() throws IOException;
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bufferlist_arrow_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bufferlist_arrow_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/certificate_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
25 |
--------------------------------------------------------------------------------
/metadata/en-US/changelogs/613.txt:
--------------------------------------------------------------------------------
1 | * Added an optional light theme
2 | * Removed some and added some color schemes, including an AMOLED theme
3 | * Support for coloring UI elements through color schemes
4 | * Ability to tweak the 256 color palette through color schemes
5 | * A new adaptive icon
6 | * Modernized some UI elements: rounded corners, lowercase buttons, etc
7 | * Using vector assets almost everywhere
8 | * Reworked a major part of the networking code—should be more stable now
9 | * Use a different WebSocket library: [nv-websocket-client](https://github.com/TakahikoKawasaki/nv-websocket-client)
10 | * Made the order of open buffers consistent with the buffer list
11 | * Added a filter to the share dialog
12 | * Activity is now no longer destroyed when pressing the back button
13 | * Added an option to use a system gesture exclusion zone on Android Q
14 | * Added Russian translation
15 | * Fixed the way the application detects software keyboard
16 | * Fixed some of the notification glitches and inconsistencies
17 | * Now using LeakCanary to detect memory leaks
18 | * Library updates and stability fixes
19 |
--------------------------------------------------------------------------------
/relay/src/test/java/com/ubergeek42/weechat/HexUtilsTest.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 |
5 | import org.junit.jupiter.api.Test
6 | import org.junit.jupiter.api.assertThrows
7 |
8 |
9 | const val string001077 = "001077abCdfF"
10 | val byteArray001077 = byteArrayOf(0x00, 0x10, 0x77, 0xab.toByte(), 0xcd.toByte(), 0xff.toByte())
11 |
12 |
13 | internal class HexUtilsTest {
14 | @Test fun fromHexStringToByteArray() {
15 | assertArrayEquals("".fromHexStringToByteArray(), byteArrayOf())
16 | assertArrayEquals(string001077.fromHexStringToByteArray(), byteArray001077)
17 |
18 | assertThrows {
19 | "hi".fromHexStringToByteArray()
20 | }
21 |
22 | assertThrows {
23 | "123".fromHexStringToByteArray()
24 | }
25 | }
26 |
27 | @Test fun toHexStringLowercase() {
28 | assertEquals(byteArrayOf().toHexStringLowercase(), "")
29 | assertEquals(byteArray001077.toHexStringLowercase(), string001077.lowercase())
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/certificate_dialog_certificate.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/cats/src/main/java/com/ubergeek42/cats/RootKitty.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.cats;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.util.ArrayList;
7 |
8 | import static com.ubergeek42.cats.Cats.disabled;
9 |
10 | public class RootKitty extends Kitty {
11 | @Nullable String prefix;
12 | private final @NonNull ArrayList kids = new ArrayList<>();
13 |
14 | RootKitty(@NonNull String tag) {
15 | super(tag);
16 | enabled = !disabled.contains(tag);
17 | }
18 |
19 | @SuppressWarnings("StringEquality")
20 | @Override public KidKitty kid(@NonNull String tag) {
21 | for (KidKitty kid : kids) if (kid.tag == tag) return kid;
22 | KidKitty kid = new KidKitty(this, tag);
23 | kids.add(kid);
24 | return kid;
25 | }
26 |
27 | @Override public void setPrefix(@Nullable String prefix) {
28 | this.prefix = prefix;
29 | }
30 |
31 | @Override String getTag() {
32 | return tag;
33 | }
34 |
35 | @Override @Nullable String getPrefix() {
36 | return prefix;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/cats/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | -assumenosideeffects class com.ubergeek42.cats.Kitty {
24 | public void trace*(...);
25 | public void debug*(...);
26 | }
27 |
28 | -assumenosideeffects class com.ubergeek42.cats.Cats {
29 | public void setup(...);
30 | public static com.ubergeek42.cats.Kitty getKitty(...);
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/views/SuppressedLinearLayoutManager.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("PackageDirectoryMismatch")
2 | package androidx.recyclerview.widget
3 |
4 | import android.content.Context
5 | import com.ubergeek42.WeechatAndroid.upload.suppress
6 |
7 |
8 | // this is an attempt to dirty fix some very rare crashes in buffer list recycler view
9 | // see https://github.com/ubergeek42/weechat-android/issues/512
10 |
11 | // the overridden method suppresses:
12 | // * IndexOutOfBoundsException: Inconsistency detected. Invalid item position...
13 | // * IllegalArgumentException: view is not a child, cannot hide...
14 | // * RuntimeException: trying to unhide a view that was not hidden...
15 | internal open class SuppressedLinearLayoutManager(context: Context) : LinearLayoutManager(context) {
16 | override fun layoutChunk(
17 | recycler: RecyclerView.Recycler?,
18 | state: RecyclerView.State?,
19 | layoutState: LayoutState?,
20 | result: LayoutChunkResult?,
21 | ) {
22 | suppress {
23 | super.layoutChunk(recycler, state, layoutState, result)
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/TinyMap.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class TinyMap {
6 | private ArrayList keys = new ArrayList<>();
7 | private ArrayList values = new ArrayList<>();
8 |
9 | public TinyMap() {}
10 |
11 | public TinyMap put(K k, V v) {
12 | keys.add(k);
13 | values.add(v);
14 | return this;
15 | }
16 |
17 | public V get(K k) {
18 | for (int i = 0; i < keys.size(); i++)
19 | if (k.equals(keys.get(i)))
20 | return values.get(i);
21 | throw new RuntimeException("Key " + k + " not found");
22 | }
23 |
24 | public static TinyMap of(K k1, V v1) {
25 | return new TinyMap().put(k1, v1);
26 | }
27 |
28 | public static TinyMap of(K k1, V v1, K k2, V v2) {
29 | return new TinyMap().put(k1, v1).put(k2, v2);
30 | }
31 |
32 | public static TinyMap of(K k1, V v1, K k2, V v2, K k3, V v3) {
33 | return new TinyMap().put(k1, v1).put(k2, v2).put(k3, v3);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/SslUtils.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat
2 |
3 | import java.security.cert.X509Certificate
4 | import javax.net.ssl.HostnameVerifier
5 | import javax.net.ssl.SSLSocketFactory
6 |
7 |
8 | interface RememberingTrustManager {
9 | val lastServerOfferedCertificateChain: Array?
10 | val lastAuthType: String?
11 | }
12 |
13 |
14 | class SslAxolotl(
15 | val sslSocketFactory: SSLSocketFactory,
16 | val rememberingTrustManager: RememberingTrustManager,
17 | val hostnameVerifier: HostnameVerifier,
18 | ) {
19 | class ExceptionWrapper(
20 | val lastServerOfferedCertificateChain: Array?,
21 | val lastAuthType: String?,
22 | exception: Exception
23 | ) : Exception(exception)
24 | }
25 |
26 |
27 | fun SslAxolotl.wrapExceptions(block: () -> T): T {
28 | try {
29 | return block()
30 | } catch (exception: Exception) {
31 | throw SslAxolotl.ExceptionWrapper(
32 | rememberingTrustManager.lastServerOfferedCertificateChain,
33 | rememberingTrustManager.lastAuthType,
34 | exception
35 | )
36 | }
37 | }
--------------------------------------------------------------------------------
/weechat-relay-example/src/main/java/com/ubergeek42/relayexample/InfolistMessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.relayexample;
2 | import java.util.HashMap;
3 |
4 | import com.ubergeek42.weechat.relay.RelayMessage;
5 | import com.ubergeek42.weechat.relay.RelayMessageHandler;
6 | import com.ubergeek42.weechat.relay.protocol.Infolist;
7 | import com.ubergeek42.weechat.relay.protocol.RelayObject;
8 |
9 |
10 | public class InfolistMessageHandler implements RelayMessageHandler {
11 | @Override
12 | public void handleMessage(RelayObject obj, String id) {
13 | if (id.equals("infolist-test")) {
14 | if (!(obj instanceof Infolist)) {
15 | System.err.println("Error: unexpected object type");
16 | }
17 | Infolist infolist = (Infolist) obj;
18 | System.out.println("[Infolist] " + infolist.getName());
19 | for(int i=0;i item = infolist.getItem(i);
22 | for(String key: item.keySet()) {
23 | System.out.format(" %s: %s\n",key, item.get(key));
24 | }
25 | }
26 | } else {
27 | System.err.println("Unexpected message ID");
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_activity.xml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
24 |
27 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/messagehandler/HotlistManagerObserver.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Tor Hveem
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.messagehandler;
17 |
18 | /**
19 | * Observer to receive notifications when buffers change
20 | *
21 | * @author thveem
22 | *
23 | */
24 | public interface HotlistManagerObserver {
25 | /**
26 | * Called whenever the hotlist changes
27 | */
28 | public void onHotlistChanged();
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_users_dark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_copy_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_users_light.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/messagehandler/BuffersChangedObserver.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.messagehandler;
17 |
18 | /**
19 | * Observer to receive notifications when buffers change
20 | *
21 | * @author ubergeek42
22 | *
23 | */
24 | public interface BuffersChangedObserver {
25 | /**
26 | * Called whenever a buffer changes(or is added/removed)
27 | */
28 | public void onBuffersChanged();
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_magnifying_glass.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/ClearKnownHostsPreference.kt:
--------------------------------------------------------------------------------
1 | package androidx.preference
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.ubergeek42.WeechatAndroid.R
6 | import com.ubergeek42.WeechatAndroid.service.P
7 | import com.ubergeek42.WeechatAndroid.utils.Toaster.Companion.SuccessToast
8 |
9 | class ClearKnownHostsPreference(context: Context, attrs: AttributeSet) : ClearPreference(context, attrs) {
10 | override val message = R.string.pref__ClearKnownHostsPreference__prompt
11 | override val negativeButton = R.string.pref__ClearKnownHostsPreference__button_cancel
12 | override val positiveButton = R.string.pref__ClearKnownHostsPreference__button_clear
13 |
14 | override fun update() {
15 | P.loadServerKeyVerifier()
16 | val count = P.sshServerKeyVerifier.numberOfRecords
17 | isEnabled = count > 0
18 |
19 | summary = if (count == 0) context.getString(R.string.pref__ClearKnownHostsPreference__0_entries) else
20 | context.resources.getQuantityString(R.plurals.pref__ClearKnownHostsPreference__n_entries, count, count)
21 | }
22 |
23 | override fun clear() {
24 | P.sshServerKeyVerifier.clear()
25 | SuccessToast.show(R.string.pref__ClearKnownHostsPreference__success_cleared)
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/OkHttpSecuringInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import com.ubergeek42.cats.Kitty;
4 | import com.ubergeek42.cats.Root;
5 |
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.io.IOException;
9 |
10 | import okhttp3.Interceptor;
11 | import okhttp3.Request;
12 | import okhttp3.Response;
13 |
14 | import static com.ubergeek42.WeechatAndroid.utils.Assert.assertThat;
15 |
16 | class OkHttpSecuringInterceptor implements Interceptor {
17 | final private static @Root Kitty kitty = Kitty.make();
18 |
19 | @NotNull @Override public Response intercept(@NotNull Chain chain) throws IOException {
20 | assertThat(Config.secureRequestsPolicy).isAnyOf(Config.SecureRequest.REQUIRED, Config.SecureRequest.REWRITE);
21 | Request request = chain.request();
22 |
23 | if ("http".equals(request.url().scheme())) {
24 | if (Config.secureRequestsPolicy == Config.SecureRequest.REQUIRED) {
25 | throw new Exceptions.SslRequiredException();
26 | } else {
27 | request = request.newBuilder().url(
28 | request.url().newBuilder().scheme("https").build()).build();
29 | }
30 | }
31 |
32 | return chain.proceed(request);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_upload_cancel.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_big_disconnected.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_big_connecting.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #aaffffff
4 |
5 | #10ffffff
6 | #1B1F22
7 | #1B1F22
8 | #588ab8
9 | #55ffffff
10 | #f1ffffff
11 |
12 | #eeffffff
13 | #4cffffff
14 |
15 | #b00000
16 |
17 | #aa525252
18 | #aa6c6c6c
19 | #aa44525f
20 | #aa596c7d
21 | #aa57474f
22 | #aa735e69
23 |
24 | #59ffffff
25 | #29000000
26 | #ffbb6060
27 | #ffbb0000
28 |
29 | #ffff0000
30 | @color/toolbarIconEnabled
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/service/Events.kt:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 |
4 | package com.ubergeek42.WeechatAndroid.service
5 |
6 | import com.ubergeek42.WeechatAndroid.relay.Buffer
7 | import com.ubergeek42.WeechatAndroid.relay.as0x
8 | import com.ubergeek42.WeechatAndroid.utils.Assert
9 | import org.greenrobot.eventbus.EventBus
10 | import java.util.EnumSet
11 | import java.util.Locale
12 |
13 | class Events {
14 | data class StateChangedEvent(@JvmField val state: EnumSet)
15 |
16 | data class ExceptionEvent(@JvmField val e: Exception)
17 |
18 | data class SendMessageEvent(@JvmField val message: String) {
19 | companion object {
20 | fun fire(message: String) {
21 | Assert.assertThat(message.endsWith("\n")).isFalse()
22 | EventBus.getDefault().post(SendMessageEvent(message))
23 | }
24 |
25 | fun fireInput(buffer: Buffer, input: String?) {
26 | if (input.isNullOrEmpty()) return
27 |
28 | P.addSentMessage(input)
29 |
30 | input.lineSequence().filter(String::isNotEmpty).forEach { line ->
31 | fire("input ${buffer.pointer.as0x} $line")
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/HelpPreference.java:
--------------------------------------------------------------------------------
1 | package androidx.preference;
2 |
3 | import android.content.Context;
4 | import android.text.Html;
5 | import android.text.method.LinkMovementMethod;
6 | import android.util.AttributeSet;
7 | import android.widget.TextView;
8 |
9 | @SuppressWarnings({"unused", "WeakerAccess"})
10 | public class HelpPreference extends Preference {
11 | public HelpPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
12 | super(context, attrs, defStyleAttr, defStyleRes);
13 | }
14 |
15 | public HelpPreference(Context context, AttributeSet attrs, int defStyleAttr) {
16 | super(context, attrs, defStyleAttr);
17 | }
18 |
19 | public HelpPreference(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public HelpPreference(Context context) {
24 | super(context);
25 | }
26 |
27 | @Override public CharSequence getSummary() {
28 | return Html.fromHtml(super.getSummary().toString());
29 | }
30 |
31 | @Override public void onBindViewHolder(PreferenceViewHolder holder) {
32 | super.onBindViewHolder(holder);
33 | TextView summary = (TextView) holder.findViewById(android.R.id.summary);
34 | summary.setMovementMethod(LinkMovementMethod.getInstance());
35 | summary.setMaxHeight(Integer.MAX_VALUE);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/weechat-relay-example/src/main/java/com/ubergeek42/relayexample/TestMessageHandler.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.relayexample;
17 |
18 | import com.ubergeek42.weechat.relay.RelayMessageHandler;
19 | import com.ubergeek42.weechat.relay.protocol.RelayObject;
20 |
21 | /**
22 | * Pretty prints any message it receives
23 | * @author ubergeek
24 | *
25 | */
26 | public class TestMessageHandler implements RelayMessageHandler {
27 | public void handleMessage(RelayObject obj, String id) {
28 | System.out.println("\n============"+id+"=================");
29 | System.out.println(obj.getType().toString() + " - " + obj);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_copy.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
18 |
19 |
30 |
31 |
35 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/HexUtils.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat
2 |
3 |
4 | private fun Char.fromHexCharToInt(): Int {
5 | return when (this) {
6 | in '0'..'9' -> this - '0'
7 | in 'a'..'f' -> this - 'a' + 10
8 | in 'A'..'F' -> this - 'A' + 10
9 | else -> throw IllegalArgumentException("Not a hex digit: $this")
10 | }
11 | }
12 |
13 |
14 | fun String.fromHexStringToByteArray(): ByteArray {
15 | if (length % 2 != 0) {
16 | throw IllegalArgumentException("Input must have even character count")
17 | }
18 |
19 | val outputBytes = ByteArray(length / 2)
20 |
21 | outputBytes.indices.forEach { outputIndex ->
22 | val digit1 = this[outputIndex * 2].fromHexCharToInt()
23 | val digit2 = this[outputIndex * 2 + 1].fromHexCharToInt()
24 | outputBytes[outputIndex] = (digit1 * 16 + digit2).toByte()
25 | }
26 |
27 | return outputBytes
28 | }
29 |
30 |
31 | fun ByteArray.toHexStringLowercase(): String {
32 | val outputCharacters = CharArray(size * 2)
33 |
34 | this.forEachIndexed { inputIndex, inputByte ->
35 | val inputByteIntValue = inputByte.toInt() and 0xff
36 | outputCharacters[inputIndex * 2] = HEX_DIGITS[inputByteIntValue ushr 4]
37 | outputCharacters[inputIndex * 2 + 1] = HEX_DIGITS[inputByteIntValue and 0x0f]
38 | }
39 |
40 | return String(outputCharacters)
41 | }
42 |
43 |
44 | private val HEX_DIGITS = "0123456789abcdef".toCharArray()
45 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/RelayMessageHandler.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay;
17 |
18 | import com.ubergeek42.weechat.relay.protocol.RelayObject;
19 |
20 | /**
21 | * An interface for receiving message callbacks from WRelayConnection
22 | *
23 | * @author ubergeek42
24 | */
25 | public interface RelayMessageHandler {
26 | /**
27 | * Called each time a message is received
28 | *
29 | * @param obj
30 | * - A relay protocol object from the message
31 | * @param id
32 | * - The id that triggered this callback
33 | */
34 | void handleMessage(RelayObject obj, String id);
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_big_connected.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_toolbar_magnifying_glass.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/upload/HttpUriGetter.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.upload
2 |
3 | import java.util.regex.PatternSyntaxException
4 |
5 | fun interface HttpUriGetter {
6 | class UriLookupException(text: String) : Exception(text)
7 |
8 | @Throws(UriLookupException::class)
9 | fun getUri(body: String): String
10 |
11 | companion object {
12 | // this getter simply returns the whole body
13 | val simple = HttpUriGetter { body -> body }
14 |
15 | // this getter will find the uri using provided regex.
16 | // if that regex has capture groups, the first one is used
17 | // if there are no capture groups, the whole match is used
18 | @JvmStatic @Throws(PatternSyntaxException::class)
19 | fun fromRegex(string: String): HttpUriGetter {
20 | if (string.isBlank()) throw PatternSyntaxException("Blank regex", string, 0)
21 | val regex = Regex(string)
22 |
23 | return HttpUriGetter { body ->
24 | regex.find(body)?.let {
25 | val httpUri = it.groupValues[if (it.groupValues.size > 1) 1 else 0 ]
26 | if (httpUri.isNotBlank())
27 | return@HttpUriGetter httpUri
28 | }
29 | val tinyBody = if (body.length > 30) body.substring(0..30) + "..." else body
30 | throw UriLookupException("Could not determine HTTP URI using regex $string\n\nBody: $tinyBody")
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/schemas/com.ubergeek42.WeechatAndroid.media.CachePersist.AttemptDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "6742807ec7390b32c40da5498f807c1e",
6 | "entities": [
7 | {
8 | "tableName": "attempts",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `code` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`key`))",
10 | "fields": [
11 | {
12 | "fieldPath": "key",
13 | "columnName": "key",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "code",
19 | "columnName": "code",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "timestamp",
25 | "columnName": "timestamp",
26 | "affinity": "INTEGER",
27 | "notNull": true
28 | }
29 | ],
30 | "primaryKey": {
31 | "columnNames": [
32 | "key"
33 | ],
34 | "autoGenerate": false
35 | },
36 | "indices": [],
37 | "foreignKeys": []
38 | }
39 | ],
40 | "views": [],
41 | "setupQueries": [
42 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
43 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6742807ec7390b32c40da5498f807c1e')"
44 | ]
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/ClearPreference.kt:
--------------------------------------------------------------------------------
1 | package androidx.preference
2 |
3 | import android.content.Context
4 | import android.content.DialogInterface
5 | import android.util.AttributeSet
6 | import androidx.appcompat.app.AlertDialog
7 |
8 |
9 | @Suppress("LeakingThis")
10 | abstract class ClearPreference(context: Context, attrs: AttributeSet?)
11 | : DialogPreference(context, attrs), DialogFragmentGetter {
12 |
13 | abstract val message: Int
14 | abstract val negativeButton: Int
15 | abstract val positiveButton: Int
16 |
17 | init { update() }
18 |
19 | abstract fun update()
20 |
21 | abstract fun clear()
22 |
23 | override fun getDialogFragment() = ClearCertPreferenceFragment()
24 |
25 | class ClearCertPreferenceFragment : PreferenceDialogFragmentCompat(), DialogInterface.OnClickListener {
26 | override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) {
27 | super.onPrepareDialogBuilder(builder)
28 |
29 | val preference = preference as ClearPreference
30 |
31 | builder.apply {
32 | setTitle(null)
33 | setMessage(getString(preference.message))
34 | setNegativeButton(getString(preference.negativeButton), null)
35 | setPositiveButton(getString(preference.positiveButton)) { _, _ -> preference.clear() }
36 | }
37 | }
38 |
39 | override fun onDialogClosed(b: Boolean) {
40 | (preference as ClearPreference).update()
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/messagehandler/UpgradeHandler.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.messagehandler;
17 |
18 | import com.ubergeek42.weechat.relay.RelayMessageHandler;
19 | import com.ubergeek42.weechat.relay.protocol.RelayObject;
20 |
21 | public class UpgradeHandler implements RelayMessageHandler {
22 |
23 | private UpgradeObserver uo;
24 |
25 | public UpgradeHandler(UpgradeObserver uo) {
26 | this.uo = uo;
27 | }
28 |
29 | @Override
30 | public void handleMessage(RelayObject obj, String id) {
31 | System.out.println("Got id: " + id);
32 | if (id.equals("_upgrade_ended") || id.equals("_upgrade")) {
33 | uo.onUpgrade();
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/schemas/com.ubergeek42.WeechatAndroid.upload.UploadDatabase.UploadRecordsDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "05e7fef29bcf91fde37616b9fdeff3b1",
6 | "entities": [
7 | {
8 | "tableName": "upload_records",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `http_uri` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`uri`))",
10 | "fields": [
11 | {
12 | "fieldPath": "uri",
13 | "columnName": "uri",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "httpUri",
19 | "columnName": "http_uri",
20 | "affinity": "TEXT",
21 | "notNull": true
22 | },
23 | {
24 | "fieldPath": "timestamp",
25 | "columnName": "timestamp",
26 | "affinity": "INTEGER",
27 | "notNull": true
28 | }
29 | ],
30 | "primaryKey": {
31 | "columnNames": [
32 | "uri"
33 | ],
34 | "autoGenerate": false
35 | },
36 | "indices": [],
37 | "foreignKeys": []
38 | }
39 | ],
40 | "views": [],
41 | "setupQueries": [
42 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
43 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '05e7fef29bcf91fde37616b9fdeff3b1')"
44 | ]
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/preferences_full_screen_edit_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
30 |
31 |
32 |
35 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/BufferObserver.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat;
17 |
18 | /**
19 | * Allows objects to receive notifications when certain aspects of a buffer change
20 | *
21 | * @author ubergeek42
22 | *
23 | */
24 | public interface BufferObserver {
25 | /**
26 | * Called when a lot of lines are added to a buffer
27 | */
28 | void onManyLinesAdded();
29 |
30 | /**
31 | * Called when a line is added to a buffer
32 | */
33 | void onLineAdded();
34 |
35 | /**
36 | * Called when the buffer is closed in weechat
37 | */
38 | void onBufferClosed();
39 |
40 | /**
41 | * Called when the nicklist changes
42 | */
43 | void onNicklistChanged();
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/ic_toolbar_users.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/LimitedLengthInputStream.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import java.io.FilterInputStream;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 |
9 | import static com.ubergeek42.WeechatAndroid.media.Exceptions.*;
10 |
11 | public class LimitedLengthInputStream extends FilterInputStream {
12 | private long readByteCount = 0;
13 | final private long minByteCount;
14 | final private long maxByteCount;
15 |
16 | LimitedLengthInputStream(InputStream in, long minByteCount, long maxByteCount) {
17 | super(in);
18 | this.minByteCount = minByteCount;
19 | this.maxByteCount = maxByteCount;
20 | }
21 |
22 | @Override public int read() throws IOException {
23 | int data = super.read();
24 | check(data != -1 ? 1 : -1);
25 | return data;
26 | }
27 |
28 | @Override public int read(@NonNull byte[] b, int off, int len) throws IOException {
29 | int read = super.read(b, off, len);
30 | check(read);
31 | return read;
32 | }
33 |
34 | private void check(int read) throws IOException {
35 | if (read < 0) {
36 | if (readByteCount < minByteCount)
37 | throw new BodySizeSmallerThanContentLengthException(readByteCount, minByteCount);
38 | } else {
39 | readByteCount += read;
40 | if (readByteCount > maxByteCount)
41 | throw new UnknownLengthStreamExceedsLimitException(maxByteCount);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_users.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/ClearCertPreference.kt:
--------------------------------------------------------------------------------
1 | package androidx.preference
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.ubergeek42.WeechatAndroid.R
6 | import com.ubergeek42.WeechatAndroid.service.SSLHandler
7 | import com.ubergeek42.WeechatAndroid.utils.Toaster.Companion.ErrorToast
8 | import com.ubergeek42.WeechatAndroid.utils.Toaster.Companion.SuccessToast
9 |
10 | class ClearCertPreference(context: Context, attrs: AttributeSet) : ClearPreference(context, attrs) {
11 | override val message = R.string.pref__ClearCertPreference__prompt
12 | override val negativeButton = R.string.pref__ClearCertPreference__button_cancel
13 | override val positiveButton = R.string.pref__ClearCertPreference__button_clear
14 |
15 | override fun update() {
16 | val count = SSLHandler.getInstance(context).getUserCertificateCount()
17 | isEnabled = count > 0
18 | summary = when (count) {
19 | 0 -> context.getString(R.string.pref__ClearCertPreference__0_entries)
20 | 1 -> context.getString(R.string.pref__ClearCertPreference__1_entries)
21 | else -> context.resources.getQuantityString(R.plurals.pref__ClearCertPreference__n_entries, count, count)
22 | }
23 | }
24 |
25 | override fun clear() {
26 | val removed = SSLHandler.getInstance(context).removeUserKeystore()
27 | if (removed) {
28 | SuccessToast.show(R.string.pref__ClearCertPreference__success_cleared)
29 | } else {
30 | ErrorToast.show(R.string.pref__ClearCertPreference__error_could_not_clear)
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar_bell.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
41 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/Helper.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat;
17 |
18 | /**
19 | * Provides some helper functions that are required by the library
20 | *
21 | * @author ubergeek42
22 | *
23 | */
24 | public class Helper {
25 | // Basically Arrays.copyOfRange, included as android 2.1 is missing this
26 | // See http://stackoverflow.com/a/7970678 (taken from the OpenJDK source)
27 | public static byte[] copyOfRange(byte[] original, int from, int to) {
28 | int newLength = to - from;
29 | if (newLength < 0) {
30 | throw new IllegalArgumentException(from + " > " + to);
31 | }
32 | byte[] copy = new byte[newLength];
33 | System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
34 | return copy;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/activity_like_open_enter.xml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
22 |
31 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/activity_like_close_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
32 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff3e3e3e
4 |
5 | #202B2F32
6 | #eeeeee
7 | #eeeeee
8 | #597d9e
9 | #55000000
10 | #bb000000
11 |
12 | #9a000000
13 | #3c000000
14 |
15 | #44525252
16 | #44cccccc
17 | #4400225f
18 | #440052ed
19 | #44570022
20 | #44e30052
21 | @color/textColor
22 |
23 | #66ffffff
24 | #11000000
25 | #ffffaaaa
26 | #ffff6666
27 |
28 | @color/toolbarIconEnabled
29 | #d00000
30 |
31 | #d00000
32 | @color/primary
33 |
34 | #800000
35 |
36 | #ff6666
37 | #aaee88
38 | #597d9e
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/views/BackGestureAwareEditText.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.views
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.KeyEvent
6 | import android.view.KeyEvent.ACTION_UP
7 | import androidx.appcompat.widget.AppCompatEditText
8 |
9 |
10 | fun interface OnBackGestureListener {
11 | fun onBackGesture(): Boolean
12 | }
13 |
14 |
15 | // the idea here is to listen to back gesture events,
16 | // as opposed to back button presses (3 button navigation, etc).
17 | // this is useful because with gestures there's 2 ways to minimize the keyboard,
18 | // via the gesture and also via the gesture minimization button.
19 | // this allows closing the search instantly on back press
20 | // and leaving it open on keyboard minimization.
21 | class BackGestureAwareEditText @JvmOverloads constructor(
22 | context: Context,
23 | attrs: AttributeSet? = null,
24 | ) : AppCompatEditText(context, attrs) {
25 |
26 | var onBackGestureListener: OnBackGestureListener? = null
27 |
28 | override fun onKeyPreIme(keyCode: Int, event: KeyEvent?): Boolean {
29 | if (event != null && event.isBackGesture && event.action == ACTION_UP) {
30 | if (onBackGestureListener?.onBackGesture() == true) return true
31 | }
32 |
33 | return super.onKeyPreIme(keyCode, event)
34 | }
35 | }
36 |
37 |
38 | // this is super hacky but probably safe.
39 | // with the back gesture the display ID is -1, or INVALID_DISPLAY
40 | // the field is hidden but present in toString()
41 | private val KeyEvent.isBackGesture get() =
42 | keyCode == KeyEvent.KEYCODE_BACK && toString().contains("displayId=-1")
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/MapSortedByValue.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.notifications
2 |
3 | import java.util.*
4 | import kotlin.collections.ArrayList
5 | import kotlin.collections.HashMap
6 |
7 |
8 | interface PrimitiveMap> {
9 | fun get(key: K): V?
10 | fun put(key: K, value: V)
11 | fun getSomeKeys(upTo: Int): List
12 |
13 | data class Entry>(
14 | val key: K,
15 | val value: V
16 | )
17 | }
18 |
19 |
20 | inline fun , V : Comparable> mapSortedByValue(
21 | crossinline selector: (V) -> Comparable<*>
22 | ): PrimitiveMap {
23 | val keyToEntry = HashMap>()
24 | val sortedSet = sortedSetOf(
25 | compareBy> { selector(it.value) }.thenBy { it.key }
26 | )
27 |
28 | return object: PrimitiveMap {
29 | override fun get(key: K): V? {
30 | return keyToEntry[key]?.value
31 | }
32 |
33 | override fun put(key: K, value: V) {
34 | keyToEntry[key]?.let { sortedSet.remove(it) }
35 | val entry = PrimitiveMap.Entry(key, value)
36 | keyToEntry[key] = entry
37 | sortedSet.add(entry)
38 | }
39 |
40 | override fun getSomeKeys(upTo: Int): List {
41 | val result = ArrayList(upTo)
42 | sortedSet.forEachIndexed { index, value ->
43 | if (index < upTo) {
44 | result.add(value.key)
45 | } else {
46 | return@forEachIndexed
47 | }
48 | }
49 | return result
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_big_connecting.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/connection/SimpleConnection.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat.relay.connection
2 |
3 | import com.ubergeek42.weechat.SslAxolotl
4 | import com.ubergeek42.weechat.wrapExceptions
5 | import kotlin.Throws
6 | import java.io.IOException
7 | import java.net.InetSocketAddress
8 | import java.net.Socket
9 | import javax.net.ssl.SSLSocket
10 |
11 |
12 | class SimpleConnection(
13 | private val hostname: String,
14 | private val port: Int,
15 | private val sslAxolotl: SslAxolotl?,
16 | ) : IConnection {
17 | private val socket = Socket()
18 |
19 | // Do NOT call the argument-less `sslSocketFactory.sslSocketFactory()`,
20 | // for on Android 6 it creates a socket that does not play well with SNI
21 | // and won't connect to websites that require it, e.g. badssl.com.
22 | @Suppress("IfThenToElvis")
23 | @Throws(IOException::class)
24 | override fun connect(): IConnection.Streams {
25 | socket.connect(InetSocketAddress(hostname, port), RelayConnection.CONNECTION_TIMEOUT)
26 |
27 | val finalSocket = if (sslAxolotl == null) {
28 | socket
29 | } else {
30 | sslAxolotl.wrapExceptions {
31 | val sslSocket = sslAxolotl.sslSocketFactory
32 | .createSocket(socket, hostname, port, true) as SSLSocket
33 | sslSocket.startHandshake()
34 | Utils.verifyHostname(sslAxolotl.hostnameVerifier, sslSocket, hostname)
35 | sslSocket
36 | }
37 | }
38 |
39 | return IConnection.Streams(finalSocket.getInputStream(), finalSocket.getOutputStream())
40 | }
41 |
42 | @Throws(IOException::class)
43 | override fun disconnect() {
44 | socket.close()
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/tabcomplete/LocalTabCompleter.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.tabcomplete
2 |
3 | import android.widget.EditText
4 | import com.ubergeek42.WeechatAndroid.relay.Buffer
5 |
6 | const val IGNORE_CHARS = "[]`_-^"
7 |
8 | class LocalTabCompleter(
9 | private val buffer: Buffer,
10 | input: EditText,
11 | ) : TabCompleter(input) {
12 |
13 | init {
14 | replacements = retrieveCompletions()
15 | }
16 |
17 | override fun next() {
18 | performCompletion()
19 | }
20 |
21 | private fun retrieveCompletions(): Iterator {
22 | val text = input.text ?: return EmptyReplacements
23 |
24 | // find the end of the word to be completed: "bla-bla nick|"
25 | val end = input.selectionStart
26 | if (end <= 0) return EmptyReplacements
27 |
28 | // find the beginning of the word to be completed "bla-bla |nick"
29 | var start = end
30 | while (start > 0 && text[start - 1] != ' ') start--
31 |
32 | // get the word to be completed, lowercase
33 | if (start == end) return EmptyReplacements
34 | val baseWord = text.subSequence(start, end).toString()
35 |
36 | // nicks is ordered in last used comes first way, so we just pick whatever comes first
37 | val matchingNicks = buffer.getMostRecentNicksMatching(baseWord, IGNORE_CHARS)
38 | if (matchingNicks.size == 0) return EmptyReplacements
39 |
40 | return replacements(completions = matchingNicks,
41 | start = start,
42 | baseWord = baseWord,
43 | suffix = if (start == 0) ": " else "")
44 | }
45 |
46 | fun lacksCompletions() = replacements === EmptyReplacements
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/HostUtils.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.util.Iterator;
7 | import java.util.regex.Matcher;
8 | import java.util.regex.Pattern;
9 |
10 | class HostUtils {
11 | private static final Pattern HOST = Pattern.compile("^https?://([^/:]+)", Pattern.CASE_INSENSITIVE);
12 | static @Nullable String getHost(String url) {
13 | Matcher matcher = HOST.matcher(url);
14 | return matcher.find() ? matcher.group(1) : null;
15 | }
16 |
17 | // given a host in form "a.b.c", yields:
18 | // a.b.c
19 | // *.b.c
20 | // *.c
21 | // *
22 | static class HostIterable implements Iterable {
23 | String host;
24 |
25 | HostIterable(String host) {
26 | this.host = host;
27 | }
28 |
29 | @Override public @NonNull Iterator iterator() {
30 | return new Iterator() {
31 | int index = -2;
32 |
33 | @Override public boolean hasNext() {
34 | return index != -1;
35 | }
36 |
37 | @Override public String next() {
38 | if (index == -2) {
39 | index = 0;
40 | return host;
41 | }
42 |
43 | index = host.indexOf(".", index);
44 | if (index == -1) {
45 | return "*";
46 | } else {
47 | host = host.substring(index + 1);
48 | return "*." + host;
49 | }
50 | }
51 | };
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/CertPickerPreference.java:
--------------------------------------------------------------------------------
1 | package androidx.preference;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.ubergeek42.WeechatAndroid.R;
10 | import com.ubergeek42.WeechatAndroid.service.SSLHandlerKt;
11 | import com.ubergeek42.WeechatAndroid.utils.TinyMap;
12 |
13 | import static com.ubergeek42.WeechatAndroid.utils.AndroidKeyStoreUtils.InsideSecureHardware;
14 | import static com.ubergeek42.WeechatAndroid.utils.AndroidKeyStoreUtils.areAllInsideSecurityHardware;
15 |
16 | public class CertPickerPreference extends PasswordedFilePickerPreference implements DialogFragmentGetter {
17 | public CertPickerPreference(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | @Override protected String saveData(@Nullable byte[] bytes, @NonNull String password) throws Exception {
22 | Context context = getContext();
23 | SSLHandlerKt.setClientCertificate(bytes, password);
24 | persistString(bytes != null ? "ok" : null);
25 | notifyChanged();
26 | if (bytes == null) {
27 | return context.getString(R.string.pref__CertPickerPreference__success_certificate_forgotten);
28 | }
29 |
30 | return context.getString(TinyMap.of(
31 | InsideSecureHardware.YES, R.string.pref__CertPickerPreference__success_stored_inside_secure_hardware_yes,
32 | InsideSecureHardware.NO, R.string.pref__CertPickerPreference__success_stored_inside_secure_hardware_no,
33 | InsideSecureHardware.CANT_TELL, R.string.pref__CertPickerPreference__success_stored_inside_secure_hardware_cant_tell
34 | ).get(areAllInsideSecurityHardware(SSLHandlerKt.KEYSTORE_ALIAS_PREFIX)));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/protocol/Info.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.protocol;
17 |
18 | /**
19 | * An Info item, basically a name and value pair See the following URL for more information:
20 | * http://www.weechat.org/files/doc/devel/weechat_relay_protocol.en.html#object_info
21 | *
22 | * @author ubergeek42
23 | *
24 | */
25 | public class Info extends RelayObject {
26 | private String value;
27 | private String name;
28 |
29 | protected Info(String name, String value) {
30 | this.name = name;
31 | this.value = value;
32 | }
33 |
34 | /**
35 | * @return The name of the Info item
36 | */
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | /**
42 | * @return The value of the Info item
43 | */
44 | public String getValue() {
45 | return value;
46 | }
47 |
48 | /**
49 | * Debug toString
50 | */
51 | @Override
52 | public String toString() {
53 | return "[WInfo]:\n " + name + " -> " + value;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/connection/Events.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.weechat.relay.connection;
2 |
3 | import java.util.Arrays;
4 | import java.util.concurrent.LinkedBlockingQueue;
5 |
6 | public class Events {
7 |
8 | @FunctionalInterface
9 | interface ThrowingEvent {
10 | void run() throws Exception;
11 | }
12 |
13 | @FunctionalInterface
14 | interface Event extends Runnable {
15 | void run();
16 | }
17 |
18 | @FunctionalInterface
19 | interface PoisonEvent extends Event {
20 | @Override void run();
21 | }
22 |
23 | static class EventStream {
24 | final private LinkedBlockingQueue queue = new LinkedBlockingQueue<>();
25 | final private Thread thread;
26 |
27 | EventStream(String name, int iteration) {
28 | this.thread = new Utils.FriendlyThread(name, iteration, runnable);
29 | }
30 |
31 | void start() {
32 | thread.start();
33 | }
34 |
35 | synchronized void post(Event... events) {
36 | queue.addAll(Arrays.asList(events));
37 | }
38 |
39 | synchronized void close(PoisonEvent poisonEvent) {
40 | post(poisonEvent);
41 | }
42 |
43 | synchronized void close() {
44 | close(() -> {});
45 | }
46 |
47 | synchronized void clearQueueAndClose(PoisonEvent poisonEvent) {
48 | queue.clear();
49 | close(poisonEvent);
50 | }
51 |
52 | Runnable runnable = () -> {
53 | while (!Thread.interrupted()) {
54 | Event event;
55 | try {
56 | event = queue.take();
57 | } catch (InterruptedException e) {
58 | return;
59 | }
60 | event.run();
61 | if (event instanceof PoisonEvent) return;
62 | }
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/about.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
22 |
28 |
29 |
33 |
34 |
39 |
40 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/service/SyncAlarmReceiver.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.service;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.os.SystemClock;
9 | import androidx.annotation.AnyThread;
10 | import androidx.annotation.MainThread;
11 | import androidx.annotation.WorkerThread;
12 |
13 | import com.ubergeek42.WeechatAndroid.relay.BufferList;
14 |
15 |
16 | public class SyncAlarmReceiver extends BroadcastReceiver {
17 | final private static int SYNC_EVERY_MS = 60 * 5 * 1000; // 5 minutes
18 |
19 | @WorkerThread public static void start(Context context) {
20 | AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
21 | if (am == null) return;
22 | Intent intent = new Intent(context, SyncAlarmReceiver.class);
23 | PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
24 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
25 | am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + SYNC_EVERY_MS, SYNC_EVERY_MS, pi);
26 | }
27 |
28 | @AnyThread public static void stop(Context context) {
29 | AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
30 | PendingIntent pe = PendingIntent.getBroadcast(context, 0, new Intent(context, SyncAlarmReceiver.class),
31 | PendingIntent.FLAG_IMMUTABLE);
32 | if (am != null && pe != null) am.cancel(pe);
33 | }
34 |
35 | @MainThread @Override public void onReceive(Context context, Intent intent) {
36 | boolean authenticated = RelayService.staticState.contains(RelayService.STATE.AUTHENTICATED);
37 | if (authenticated) {
38 | BufferList.syncHotlist();
39 | } else {
40 | stop(context);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/androidx/preference/MultiSelectListPreferenceWithSummary.java:
--------------------------------------------------------------------------------
1 | package androidx.preference;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.text.TextUtils;
6 | import android.util.AttributeSet;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | import com.ubergeek42.WeechatAndroid.R;
11 | import com.ubergeek42.WeechatAndroid.utils.Utils;
12 | import com.ubergeek42.cats.Cat;
13 | import com.ubergeek42.cats.Kitty;
14 | import com.ubergeek42.cats.Root;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Collections;
18 | import java.util.HashSet;
19 | import java.util.List;
20 | import java.util.Set;
21 |
22 | public class MultiSelectListPreferenceWithSummary extends MultiSelectListPreference {
23 | final private @Nullable String emptySummary;
24 |
25 | final private static @Root Kitty kitty = Kitty.make();
26 |
27 | @Cat
28 | public MultiSelectListPreferenceWithSummary(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiSelectListPreferenceWithSummary, 0, 0);
31 | emptySummary = a.getString(R.styleable.MultiSelectListPreferenceWithSummary_emptySummary);
32 | a.recycle();
33 | }
34 |
35 |
36 | @Override public CharSequence getSummary() {
37 | String summary = super.getSummary().toString();
38 | Set values = getSharedPreferences().getStringSet(getKey(), Collections.emptySet());
39 |
40 | Set valueIndices = new HashSet<>();
41 | for (String value : values) valueIndices.add(findIndexOfValue(value));
42 |
43 | List labels = new ArrayList<>();
44 | int i = 0;
45 | for (CharSequence entry: getEntries()) if (valueIndices.contains(i++)) labels.add(entry);
46 |
47 | CharSequence valueString = Utils.join(", ", labels);
48 | return TextUtils.isEmpty(valueString) ? emptySummary : String.format(summary, valueString);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/WeechatAboutActivity.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Keith Johnson
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.ubergeek42.WeechatAndroid
15 |
16 | import android.os.Bundle
17 | import android.text.method.LinkMovementMethod
18 | import android.view.MenuItem
19 | import androidx.appcompat.app.AppCompatActivity
20 | import com.ubergeek42.WeechatAndroid.databinding.AboutBinding
21 |
22 | class WeechatAboutActivity : AppCompatActivity() {
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 |
26 | setContentView(R.layout.about)
27 | val ui = AboutBinding.bind(findViewById(R.id.about))
28 |
29 | setSupportActionBar(ui.toolbar)
30 |
31 | supportActionBar?.run {
32 | setDisplayHomeAsUpEnabled(true)
33 | title = getString(R.string.pref__about_group)
34 | }
35 |
36 | ui.buildId.text = getString(R.string.pref__about__build_id, BuildConfig.VERSION_BANNER)
37 | ui.versionString.text = getString(R.string.pref__about__weechat_android_v, BuildConfig.VERSION_NAME)
38 | ui.libraries.movementMethod = LinkMovementMethod.getInstance()
39 | }
40 |
41 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
42 | return if (item.itemId == android.R.id.home) {
43 | onBackPressed()
44 | true
45 | } else {
46 | super.onOptionsItemSelected(item)
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/cats/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.aspectj.bridge.IMessage
2 | import org.aspectj.bridge.MessageHandler
3 | import org.aspectj.tools.ajc.Main
4 |
5 | plugins {
6 | id("com.android.library")
7 | }
8 |
9 | dependencies {
10 | implementation(libs.aspectj.rt)
11 | implementation(libs.androidx.annotation)
12 |
13 | testImplementation(libs.junit.jupiter)
14 | testImplementation(libs.mockito.core)
15 | }
16 |
17 | android {
18 | namespace = "com.ubergeek42.cats"
19 | compileSdk = 34
20 |
21 | defaultConfig {
22 | minSdk = 16
23 | consumerProguardFile("proguard-rules.pro")
24 | }
25 |
26 | buildFeatures {
27 | buildConfig = true
28 | }
29 | }
30 |
31 | tasks.withType {
32 | doLast {
33 | println("weaving cats...")
34 |
35 | val args = arrayOf("-showWeaveInfo",
36 | "-1.5",
37 | "-inpath", destinationDirectory.asFile.get().toString(),
38 | "-aspectpath", classpath.asPath,
39 | "-d", destinationDirectory.asFile.get().toString(),
40 | "-classpath", classpath.asPath,
41 | "-bootclasspath", android.bootClasspath.joinToString(File.pathSeparator))
42 |
43 | val handler = MessageHandler(true)
44 | Main().run(args, handler)
45 |
46 | val log = project.logger
47 | for (message in handler.getMessages(null, true)) {
48 | when (message.kind) {
49 | IMessage.DEBUG -> log.warn("DEBUG " + message.message, message.thrown)
50 | IMessage.INFO -> log.warn("INFO: " + message.message, message.thrown)
51 | IMessage.WARNING -> log.warn("WARN: " + message.message, message.thrown)
52 | IMessage.FAIL,
53 | IMessage.ERROR,
54 | IMessage.ABORT -> log.error("ERROR: " + message.message, message.thrown)
55 | }
56 | }
57 | }
58 | }
59 |
60 | java.toolchain.languageVersion = JavaLanguageVersion.of(21)
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Toasts.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.utils
2 |
3 | import android.widget.Toast
4 | import androidx.annotation.StringRes
5 | import androidx.core.content.ContextCompat
6 | import com.ubergeek42.WeechatAndroid.R
7 | import com.ubergeek42.WeechatAndroid.Weechat
8 | import com.ubergeek42.cats.Cat
9 |
10 | private val context = applicationContext
11 |
12 |
13 | class Toaster(
14 | private val duration: Int,
15 | private val colorResource: Int?,
16 | ) {
17 | @Cat fun show(message: String) {
18 | Weechat.runOnMainThread {
19 | Toast.makeText(context, message, duration).apply {
20 | colorResource?.let {
21 | val color = ContextCompat.getColor(context, it)
22 | view?.background?.setTint(color)
23 | }
24 | show()
25 | }
26 | }
27 | }
28 |
29 | fun show(message: String, vararg args: Any) {
30 | show(String.format(message, *args))
31 | }
32 |
33 | fun show(@StringRes id: Int) {
34 | show(context.resources.getString(id))
35 | }
36 |
37 | fun show(@StringRes id: Int, vararg args: Any) {
38 | show(context.resources.getString(id, *args))
39 | }
40 |
41 | fun show(e: Throwable) {
42 | show(R.string.error__etc__prefix, FriendlyExceptions(context).getFriendlyException(e).message)
43 | }
44 |
45 | // long and short toasts are insignificant messages that routinely appear during the use
46 | // of the app. info toasts are important messages that should be more noticeable to the user
47 | companion object {
48 | @JvmField val ErrorToast = Toaster(Toast.LENGTH_LONG, R.color.toastError)
49 | @JvmField val SuccessToast = Toaster(Toast.LENGTH_LONG, R.color.toastSuccess)
50 | @JvmField val InfoToast = Toaster(Toast.LENGTH_LONG, R.color.toastInfo)
51 | @JvmField val LongToast = Toaster(Toast.LENGTH_LONG, null)
52 | @JvmField val ShortToast = Toaster(Toast.LENGTH_SHORT, null)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_big_connected.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/views/FullScreenDrawerLinearLayoutManager.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.views
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import androidx.recyclerview.widget.RecyclerView
6 | import androidx.recyclerview.widget.SuppressedLinearLayoutManager
7 |
8 | internal class FullScreenDrawerLinearLayoutManager(
9 | context: Context,
10 | private val recyclerView: RecyclerView,
11 | private val adapter: RecyclerView.Adapter<*>,
12 | ) : SuppressedLinearLayoutManager(context) {
13 |
14 | private var insetTop = 0
15 | private var insetBottom = 0
16 | private var insetLeft = 0
17 |
18 | fun setInsets(top: Int, bottom: Int, left: Int) {
19 | if (insetTop != top || insetBottom != bottom || insetLeft != left) {
20 | insetTop = top
21 | insetBottom = bottom
22 | insetLeft = left
23 | recyclerView.invalidate()
24 | }
25 | }
26 |
27 | private var normalChildHeight = 0
28 |
29 | private inline val canFitAllChildrenOutsideInsets: Boolean get() {
30 | val childrenHeight = normalChildHeight * adapter.itemCount
31 | val heightSansInsets = height - insetTop - insetBottom
32 | return heightSansInsets >= childrenHeight
33 | }
34 |
35 | override fun measureChildWithMargins(child: View, widthUsed: Int, heightUsed: Int) {
36 | val position = getPosition(child)
37 |
38 | when (position) {
39 | 0 -> child.setPadding(insetLeft, insetTop, 0, 0)
40 | adapter.itemCount - 1 -> child.setPadding(insetLeft, 0, 0,
41 | if (canFitAllChildrenOutsideInsets) 0 else insetBottom)
42 | else -> child.setPadding(insetLeft, 0, 0, 0)
43 | }
44 |
45 | super.measureChildWithMargins(child, widthUsed, heightUsed)
46 |
47 | if (position == 0) {
48 | val childHeight = child.measuredHeight
49 | if (childHeight != 0) {
50 | normalChildHeight = childHeight - insetTop
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/media/RequestType.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.media;
2 |
3 | import okhttp3.MediaType;
4 | import okhttp3.Request;
5 |
6 | enum RequestType {
7 | HTML("text/html", "text/html"),
8 | IMAGE("image/bpm, image/gif, image/jpeg, image/png, image/webp, image/heif", "image/..."),
9 | HTML_OR_IMAGE(IMAGE.acceptHeader + ", " + HTML.acceptHeader + ";q=0.5", "image/..., text/html");
10 |
11 | final private String acceptHeader;
12 | final private String shortDescription;
13 |
14 | RequestType(String acceptHeader, String shortDescription) {
15 | this.acceptHeader = acceptHeader;
16 | this.shortDescription = shortDescription;
17 | }
18 |
19 | String getAcceptHeader() {
20 | return acceptHeader;
21 | }
22 |
23 | String getShortDescription() {
24 | return shortDescription;
25 | }
26 |
27 | boolean matches(MediaType responseType) {
28 | if (responseType == null) return false;
29 | String typeWithoutParams = responseType.type() + "/" + responseType.subtype();
30 | return getAcceptHeader().contains(typeWithoutParams);
31 | }
32 |
33 | Request.Builder makeRequest(String url) throws Exceptions.MalformedUrlException {
34 | Request.Builder builder = new Request.Builder().header("Accept", getAcceptHeader());
35 | try {
36 | builder.url(url);
37 |
38 | // While using an invalid URL such as `http://...` will throw IllegalArgumentException,
39 | // OkHttp will happily accept a similarly invalid url `http://…`, normalizing it to `http://...`.
40 | // Using such an URL crashes the dispatcher. So we check if the host contains empty labels.
41 | // TODO remove when fixed in OkHttp; see https://github.com/square/okhttp/issues/7301
42 | if (builder.getUrl$okhttp().host().contains("..")) {
43 | throw new IllegalArgumentException();
44 | }
45 | } catch (IllegalArgumentException e) {
46 | throw new Exceptions.MalformedUrlException(url);
47 | }
48 | return builder;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/copypaste/CopyAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.copypaste;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import com.ubergeek42.WeechatAndroid.R;
13 |
14 | import java.util.List;
15 |
16 | public class CopyAdapter extends RecyclerView.Adapter {
17 | final private LayoutInflater inflater;
18 | final private OnClickListener onClickListener;
19 | final private List items;
20 |
21 | CopyAdapter(Context context, List items, OnClickListener onClickListener) {
22 | this.inflater = LayoutInflater.from(context);
23 | this.onClickListener = onClickListener;
24 | this.items = items;
25 | }
26 |
27 | interface OnClickListener {
28 | void onClick(String item);
29 | }
30 |
31 | class CopyLine extends RecyclerView.ViewHolder implements View.OnClickListener {
32 | final TextView textView;
33 |
34 | CopyLine(@NonNull TextView textView) {
35 | super(textView);
36 | this.textView = textView;
37 | textView.setOnClickListener(this);
38 | }
39 |
40 | void setText(CharSequence text) {
41 | textView.setText(text);
42 | }
43 |
44 | @Override public void onClick(View v) {
45 | onClickListener.onClick(textView.getText().toString());
46 | }
47 | }
48 |
49 | @NonNull @Override public CopyLine onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
50 | TextView view = (TextView) inflater.inflate(R.layout.dialog_copy_line, parent, false);
51 | return new CopyLine(view);
52 | }
53 |
54 | @Override public void onBindViewHolder(@NonNull CopyLine holder, int position) {
55 | holder.setText(items.get(position));
56 | }
57 |
58 | @Override public int getItemCount() {
59 | return items.size();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/schemas/com.ubergeek42.WeechatAndroid.notifications.ShortcutStatisticsDatabase.RecordsDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "39c8ea7dfa8369f015f2e27d55dfb769",
6 | "entities": [
7 | {
8 | "tableName": "manually_focused_events",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `key` TEXT NOT NULL)",
10 | "fields": [
11 | {
12 | "fieldPath": "id",
13 | "columnName": "id",
14 | "affinity": "INTEGER",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "key",
19 | "columnName": "key",
20 | "affinity": "TEXT",
21 | "notNull": true
22 | }
23 | ],
24 | "primaryKey": {
25 | "columnNames": [
26 | "id"
27 | ],
28 | "autoGenerate": true
29 | },
30 | "indices": [],
31 | "foreignKeys": []
32 | },
33 | {
34 | "tableName": "shared_to_events",
35 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `key` TEXT NOT NULL)",
36 | "fields": [
37 | {
38 | "fieldPath": "id",
39 | "columnName": "id",
40 | "affinity": "INTEGER",
41 | "notNull": true
42 | },
43 | {
44 | "fieldPath": "key",
45 | "columnName": "key",
46 | "affinity": "TEXT",
47 | "notNull": true
48 | }
49 | ],
50 | "primaryKey": {
51 | "columnNames": [
52 | "id"
53 | ],
54 | "autoGenerate": true
55 | },
56 | "indices": [],
57 | "foreignKeys": []
58 | }
59 | ],
60 | "views": [],
61 | "setupQueries": [
62 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
63 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '39c8ea7dfa8369f015f2e27d55dfb769')"
64 | ]
65 | }
66 | }
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/protocol/Hashtable.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.protocol;
17 |
18 | import java.util.HashMap;
19 |
20 | /**
21 | * Hashtable implementation from Weechat See the following URL(s) for more information:
22 | * http://www.weechat.org/files/doc/devel/weechat_plugin_api.en.html#hashtables
23 | * http://www.weechat.org/files/doc/devel/weechat_relay_protocol.en.html#object_hashtable
24 | *
25 | * @author ubergeek42
26 | */
27 | public class Hashtable extends RelayObject {
28 |
29 | private HashMap hashtable = new HashMap();
30 |
31 | protected Hashtable(WType keyType, WType valueType) {
32 | }
33 |
34 | protected void put(RelayObject key, RelayObject value) {
35 | hashtable.put(key.toString(), value);
36 | }
37 |
38 | public RelayObject get(String key) {
39 | return hashtable.get(key);
40 | }
41 |
42 | /**
43 | * Debug toString
44 | */
45 | @Override
46 | public String toString() {
47 | StringBuilder map = new StringBuilder();
48 | for (String key : hashtable.keySet()) {
49 | RelayObject value = hashtable.get(key);
50 | map.append(key);
51 | map.append(" -> ");
52 | map.append(value);
53 | map.append(", ");
54 | }
55 | return map.toString();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | #org.gradle.jvmargs=-Xmx1536m
10 |
11 | # This hopefully will get rid of the OOM errors while building
12 | org.gradle.jvmargs=-Xmx1024m -XX:MaxMetaspaceSize=512m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | #org.gradle.parallel=true
18 |
19 | android.enableR8.fullMode=true
20 |
21 | # When set to true, the Android plugin automatically migrates existing third-party libraries to use
22 | # AndroidX by rewriting their binaries. The flag is false by default if it is not specified.
23 | android.useAndroidX=true
24 |
25 | # Add the following to ~/.gradle/gradle.properties to build dev/release
26 |
27 | # Key info for creating the development release in the android market
28 | #devStorefile=/path/to/keystore
29 | #devStorePassword=keystorepassword
30 | #devKeyAlias=devkeyalias
31 | #devKeyPassword=devkeypassword
32 |
33 | # Key info for creating real releases
34 | #releaseStorefile=/path/to/keystore
35 | #releaseStorePassword=keystorepassword
36 | #releaseKeyAlias=releasekeyalias
37 | #releaseKeyPassword=releasekeypassword
38 |
39 | # kapt is the annotation processor for Kotlin
40 | kapt.incremental.apt=true
41 |
42 | android.nonTransitiveRClass=true
43 |
44 | # Using non-final resource IDs is supposed to improve compilation performance.
45 | # The idea is that they must be unique among libraries,
46 | # so in case of a collision recompilation is reqiured.
47 | # However, in practice, after switching this to true (now default) I see
48 | # * no difference in incremental build times, and
49 | # * slight increase in a full build time,
50 | # so let's leave it as it is for now.
51 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_copy_toolbar_select_text.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ubergeek42/WeechatAndroid/notifications/Persons.kt:
--------------------------------------------------------------------------------
1 | package com.ubergeek42.WeechatAndroid.notifications
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import androidx.core.app.Person
6 | import androidx.core.graphics.drawable.IconCompat
7 | import com.ubergeek42.WeechatAndroid.relay.Buffer
8 | import com.ubergeek42.WeechatAndroid.utils.applicationContext
9 |
10 |
11 | data class CachedPerson(
12 | val colorKey: String,
13 | val nick: String,
14 | val person: Person,
15 | )
16 |
17 |
18 | private val cachedPersons = mutableMapOf()
19 |
20 |
21 | fun getPerson(key: String,
22 | colorKey: String,
23 | nick: String,
24 | missing: Boolean
25 | ): Person {
26 | val storageKey = if (missing) "missing_$key" else key
27 |
28 | val cachedPerson = cachedPersons[storageKey]
29 |
30 | return if (cachedPerson != null && cachedPerson.colorKey == colorKey && cachedPerson.nick == nick) {
31 | cachedPerson.person
32 | } else {
33 | val iconText = if (missing) "?" else nick
34 | val icon = obtainAdaptiveIcon(text = iconText, colorKey = colorKey, allowUriIcons = true)
35 |
36 | val person = Person.Builder()
37 | .setKey(storageKey)
38 | .setName(nick)
39 | .setIcon(icon)
40 | .build()
41 |
42 | if (icon.type == IconCompat.TYPE_URI_ADAPTIVE_BITMAP) {
43 | cachedPersons[storageKey] =
44 | CachedPerson(colorKey = colorKey, nick = nick, person = person)
45 | icon.uri.grantReadPermissionToSystem()
46 | }
47 |
48 | return person
49 | }
50 | }
51 |
52 |
53 | fun getPersonByPrivateBuffer(buffer: Buffer): Person {
54 | return getPerson(
55 | key = buffer.fullName,
56 | colorKey = buffer.fullName,
57 | nick = buffer.shortName,
58 | missing = false
59 | )
60 | }
61 |
62 |
63 | fun getPersonByPrivateBuffer(buffer: HotlistBuffer): Person {
64 | return getPerson(
65 | key = buffer.fullName,
66 | colorKey = buffer.fullName,
67 | nick = buffer.shortName,
68 | missing = false
69 | )
70 | }
71 |
72 |
73 | fun Uri.grantReadPermissionToSystem() {
74 | applicationContext.grantUriPermission("com.android.systemui", this,
75 | Intent.FLAG_GRANT_READ_URI_PERMISSION)
76 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/weasel.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
11 |
18 |
19 |
20 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
40 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/relay/src/main/java/com/ubergeek42/weechat/relay/protocol/Array.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2012 Keith Johnson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.ubergeek42.weechat.relay.protocol;
17 |
18 | import java.util.ArrayList;
19 |
20 | public class Array extends RelayObject {
21 |
22 | private final ArrayList array = new ArrayList();
23 |
24 | private final WType arrayType; // One of: Integer, String, Pointer, Buffer, Time
25 | private int arraySize;
26 |
27 | protected Array(WType arrayType, int size) {
28 | this.arrayType = arrayType;
29 | this.setArraySize(size);
30 | }
31 |
32 | protected void add(RelayObject value) {
33 | array.add(value);
34 | }
35 |
36 | public RelayObject get(int index) {
37 | return array.get(index);
38 | }
39 |
40 | public int length() {
41 | return arraySize;
42 | }
43 |
44 | public void setArraySize(int arraySize) {
45 | this.arraySize = arraySize;
46 | }
47 |
48 | public String[] asStringArray() {
49 | if (arrayType != WType.STR) {
50 | return new String[0];
51 | }
52 | String[] ret = new String[length()];
53 | for (int i = 0; i < length(); i++) {
54 | ret[i] = array.get(i).asString();
55 | }
56 | return ret;
57 | }
58 |
59 | /**
60 | * Debug toString
61 | */
62 | @Override
63 | public String toString() {
64 | StringBuilder map = new StringBuilder();
65 | for (RelayObject value : array) {
66 | map.append(value);
67 | map.append(", ");
68 | }
69 | return map.toString();
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/inkscape/optimized/ic_copy_toolbar_select_text.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------