packages feed

matterhorn 50200.19.0 → 90000.0.0

raw patch · 23 files changed

+233/−67 lines, 23 filesdep +crypton-connectiondep +unix-compatdep +vty-crossplatformdep −connectiondep −unixdep ~brickdep ~mattermost-apidep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: crypton-connection, unix-compat, vty-crossplatform

Dependencies removed: connection, unix

Dependency ranges changed: brick, mattermost-api, text, transformers, vector, vty

API changes (from Hackage documentation)

- Matterhorn.Types.DirectionalSeq: instance (Matterhorn.Types.DirectionalSeq.SeqDirection dir, GHC.Show.Show a) => GHC.Show.Show (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir a)
- Matterhorn.Types.DirectionalSeq: instance Matterhorn.Types.DirectionalSeq.SeqDirection dir => Data.Foldable.Foldable (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
- Matterhorn.Types.DirectionalSeq: instance Matterhorn.Types.DirectionalSeq.SeqDirection dir => Data.Traversable.Traversable (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
- Matterhorn.Types.DirectionalSeq: instance Matterhorn.Types.DirectionalSeq.SeqDirection dir => GHC.Base.Functor (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
+ Matterhorn.Constants: channelListMaxAutoWidth :: Int
+ Matterhorn.Constants: channelListMinAutoWidth :: Int
+ Matterhorn.Draw.ChannelList: channelListWidth :: ChatState -> Int
+ Matterhorn.Events: setWindowSize :: Int -> Int -> MH ()
+ Matterhorn.Types: ChannelListWidthAuto :: ChannelListWidth
+ Matterhorn.Types: ChannelListWidthFixed :: Int -> ChannelListWidth
+ Matterhorn.Types: [_crThemeOriginal] :: ChatResources -> Theme
+ Matterhorn.Types: [_crWindowSize] :: ChatResources -> (Int, Int)
+ Matterhorn.Types: crThemeOriginal :: Lens' ChatResources Theme
+ Matterhorn.Types: crWindowSize :: Lens' ChatResources (Int, Int)
+ Matterhorn.Types: data ChannelListWidth
+ Matterhorn.Types: instance GHC.Classes.Eq Matterhorn.Types.ChannelListWidth
+ Matterhorn.Types: instance GHC.Classes.Ord Matterhorn.Types.ChannelListWidth
+ Matterhorn.Types: instance GHC.Show.Show Matterhorn.Types.ChannelListWidth
+ Matterhorn.Types.Channels: [_cdTotalMessageCount] :: ChannelInfo -> Int
+ Matterhorn.Types.Channels: [_cdViewedMessageCount] :: ChannelInfo -> Int
+ Matterhorn.Types.Channels: cdTotalMessageCount :: Lens' ChannelInfo Int
+ Matterhorn.Types.Channels: cdViewedMessageCount :: Lens' ChannelInfo Int
+ Matterhorn.Types.Channels: incrementTotalMessageCount :: ClientChannel -> ClientChannel
+ Matterhorn.Types.Channels: incrementViewedMessageCount :: ClientChannel -> ClientChannel
+ Matterhorn.Types.DirectionalSeq: instance Data.Foldable.Foldable (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
+ Matterhorn.Types.DirectionalSeq: instance Data.Traversable.Traversable (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
+ Matterhorn.Types.DirectionalSeq: instance GHC.Base.Functor (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir)
+ Matterhorn.Types.DirectionalSeq: instance GHC.Show.Show a => GHC.Show.Show (Matterhorn.Types.DirectionalSeq.DirectionalSeq dir a)
- Matterhorn.Config: Config :: Maybe Text -> Maybe Text -> Maybe Text -> Int -> Maybe Text -> Maybe PasswordSource -> Maybe TokenSource -> Maybe OTPTokenSource -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Bool -> Bool -> Maybe Text -> Bool -> Maybe Text -> NotificationVersion -> Bool -> Maybe Int -> Bool -> BackgroundInfo -> Bool -> Bool -> Bool -> Bool -> Maybe Text -> Bool -> Bool -> Int -> Int -> Bool -> ChannelListSorting -> TeamListSorting -> Bool -> Bool -> Maybe FilePath -> KeyConfig KeyEvent -> Bool -> [FilePath] -> Int -> CPUUsagePolicy -> Maybe FilePath -> ChannelListOrientation -> ThreadOrientation -> Bool -> Bool -> Config
+ Matterhorn.Config: Config :: Maybe Text -> Maybe Text -> Maybe Text -> Int -> Maybe Text -> Maybe PasswordSource -> Maybe TokenSource -> Maybe OTPTokenSource -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Bool -> Bool -> Maybe Text -> Bool -> Maybe Text -> NotificationVersion -> Bool -> Maybe Int -> Bool -> BackgroundInfo -> Bool -> Bool -> Bool -> Bool -> Maybe Text -> Bool -> Bool -> ChannelListWidth -> Int -> Bool -> ChannelListSorting -> TeamListSorting -> Bool -> Bool -> Maybe FilePath -> KeyConfig KeyEvent -> Bool -> [FilePath] -> Int -> CPUUsagePolicy -> Maybe FilePath -> ChannelListOrientation -> ThreadOrientation -> Bool -> Bool -> Config
- Matterhorn.Config: [configChannelListWidth] :: Config -> Int
+ Matterhorn.Config: [configChannelListWidth] :: Config -> ChannelListWidth
- Matterhorn.Prelude: data HashMap k v
+ Matterhorn.Prelude: data () => HashMap k v
- Matterhorn.Prelude: data NominalDiffTime
+ Matterhorn.Prelude: data () => NominalDiffTime
- Matterhorn.Prelude: data Seq a
+ Matterhorn.Prelude: data () => Seq a
- Matterhorn.Prelude: data Set a
+ Matterhorn.Prelude: data () => Set a
- Matterhorn.Prelude: data Text
+ Matterhorn.Prelude: data () => Text
- Matterhorn.Prelude: data TimeZoneSeries
+ Matterhorn.Prelude: data () => TimeZoneSeries
- Matterhorn.Prelude: data UTCTime
+ Matterhorn.Prelude: data () => UTCTime
- Matterhorn.State.Teams: makeClientChannel :: MonadIO m => BChan MHEvent -> Maybe Aspell -> UserId -> Maybe TeamId -> Channel -> m ClientChannel
+ Matterhorn.State.Teams: makeClientChannel :: MonadIO m => BChan MHEvent -> Maybe Aspell -> UserId -> Maybe TeamId -> Channel -> ChannelMember -> m ClientChannel
- Matterhorn.Types: ChatResources :: Session -> Maybe ThreadId -> ConnectionData -> RequestChan -> BChan MHEvent -> TChan ProgramOutput -> TChan WebsocketAction -> AttrMap -> TChan [UserId] -> Config -> Set PostId -> UserPreferences -> SyntaxMap -> LogManager -> EmojiCollection -> Maybe Aspell -> ChatResources
+ Matterhorn.Types: ChatResources :: Session -> Maybe ThreadId -> ConnectionData -> RequestChan -> BChan MHEvent -> TChan ProgramOutput -> TChan WebsocketAction -> AttrMap -> Theme -> TChan [UserId] -> Config -> Set PostId -> UserPreferences -> SyntaxMap -> LogManager -> EmojiCollection -> Maybe Aspell -> (Int, Int) -> ChatResources
- Matterhorn.Types: Config :: Maybe Text -> Maybe Text -> Maybe Text -> Int -> Maybe Text -> Maybe PasswordSource -> Maybe TokenSource -> Maybe OTPTokenSource -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Bool -> Bool -> Maybe Text -> Bool -> Maybe Text -> NotificationVersion -> Bool -> Maybe Int -> Bool -> BackgroundInfo -> Bool -> Bool -> Bool -> Bool -> Maybe Text -> Bool -> Bool -> Int -> Int -> Bool -> ChannelListSorting -> TeamListSorting -> Bool -> Bool -> Maybe FilePath -> KeyConfig KeyEvent -> Bool -> [FilePath] -> Int -> CPUUsagePolicy -> Maybe FilePath -> ChannelListOrientation -> ThreadOrientation -> Bool -> Bool -> Config
+ Matterhorn.Types: Config :: Maybe Text -> Maybe Text -> Maybe Text -> Int -> Maybe Text -> Maybe PasswordSource -> Maybe TokenSource -> Maybe OTPTokenSource -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Bool -> Bool -> Maybe Text -> Bool -> Maybe Text -> NotificationVersion -> Bool -> Maybe Int -> Bool -> BackgroundInfo -> Bool -> Bool -> Bool -> Bool -> Maybe Text -> Bool -> Bool -> ChannelListWidth -> Int -> Bool -> ChannelListSorting -> TeamListSorting -> Bool -> Bool -> Maybe FilePath -> KeyConfig KeyEvent -> Bool -> [FilePath] -> Int -> CPUUsagePolicy -> Maybe FilePath -> ChannelListOrientation -> ThreadOrientation -> Bool -> Bool -> Config
- Matterhorn.Types: [configChannelListWidth] :: Config -> Int
+ Matterhorn.Types: [configChannelListWidth] :: Config -> ChannelListWidth
- Matterhorn.Types: configChannelListWidthL :: Lens' Config Int
+ Matterhorn.Types: configChannelListWidthL :: Lens' Config ChannelListWidth
- Matterhorn.Types: listWindowEnterHandler :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (a_a1p6j -> MH Bool)
+ Matterhorn.Types: listWindowEnterHandler :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (a_a1nZJ -> MH Bool)
- Matterhorn.Types: listWindowFetchResults :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (b_a1p6k -> Session -> Text -> IO (Vector a_a1p6j))
+ Matterhorn.Types: listWindowFetchResults :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (b_a1nZK -> Session -> Text -> IO (Vector a_a1nZJ))
- Matterhorn.Types: listWindowNewList :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (Vector a_a1p6j -> List Name a_a1p6j)
+ Matterhorn.Types: listWindowNewList :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (Vector a_a1nZJ -> List Name a_a1nZJ)
- Matterhorn.Types: listWindowRecordCount :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (Maybe Int)
+ Matterhorn.Types: listWindowRecordCount :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (Maybe Int)
- Matterhorn.Types: listWindowSearchInput :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (Editor Text Name)
+ Matterhorn.Types: listWindowSearchInput :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (Editor Text Name)
- Matterhorn.Types: listWindowSearchResults :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) (List Name a_a1p6j)
+ Matterhorn.Types: listWindowSearchResults :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) (List Name a_a1nZJ)
- Matterhorn.Types: listWindowSearchScope :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) b_a1p6k
+ Matterhorn.Types: listWindowSearchScope :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) b_a1nZK
- Matterhorn.Types: listWindowSearching :: forall a_a1p6j b_a1p6k. Lens' (ListWindowState a_a1p6j b_a1p6k) Bool
+ Matterhorn.Types: listWindowSearching :: forall a_a1nZJ b_a1nZK. Lens' (ListWindowState a_a1nZJ b_a1nZK) Bool
- Matterhorn.Types.Channels: ChannelInfo :: ChannelId -> Maybe TeamId -> Maybe ServerTime -> NewMessageIndicator -> Maybe ServerTime -> Int -> ServerTime -> Text -> Text -> Text -> Text -> Type -> ChannelNotifyProps -> Maybe UserId -> Maybe UTCTime -> Bool -> ChannelInfo
+ Matterhorn.Types.Channels: ChannelInfo :: ChannelId -> Maybe TeamId -> Maybe ServerTime -> NewMessageIndicator -> Maybe ServerTime -> Int -> ServerTime -> Text -> Text -> Text -> Text -> Type -> ChannelNotifyProps -> Maybe UserId -> Maybe UTCTime -> Bool -> Int -> Int -> ChannelInfo
- Matterhorn.Types.EditState: acCachedResponses :: forall n_a19JD. Lens' (AutocompleteState n_a19JD) (HashMap Text [AutocompleteAlternative])
+ Matterhorn.Types.EditState: acCachedResponses :: forall n_a1887. Lens' (AutocompleteState n_a1887) (HashMap Text [AutocompleteAlternative])
- Matterhorn.Types.EditState: acCompletionList :: forall n_a19JD n_a1acH. Lens (AutocompleteState n_a19JD) (AutocompleteState n_a1acH) (List n_a19JD AutocompleteAlternative) (List n_a1acH AutocompleteAlternative)
+ Matterhorn.Types.EditState: acCompletionList :: forall n_a1887 n_a18FF. Lens (AutocompleteState n_a1887) (AutocompleteState n_a18FF) (List n_a1887 AutocompleteAlternative) (List n_a18FF AutocompleteAlternative)
- Matterhorn.Types.EditState: acPreviousSearchString :: forall n_a19JD. Lens' (AutocompleteState n_a19JD) Text
+ Matterhorn.Types.EditState: acPreviousSearchString :: forall n_a1887. Lens' (AutocompleteState n_a1887) Text
- Matterhorn.Types.EditState: acType :: forall n_a19JD. Lens' (AutocompleteState n_a19JD) AutocompletionType
+ Matterhorn.Types.EditState: acType :: forall n_a1887. Lens' (AutocompleteState n_a1887) AutocompletionType
- Matterhorn.Types.EditState: esAttachmentList :: forall n_a19JC. Lens' (EditState n_a19JC) (List n_a19JC AttachmentData)
+ Matterhorn.Types.EditState: esAttachmentList :: forall n_a1886. Lens' (EditState n_a1886) (List n_a1886 AttachmentData)
- Matterhorn.Types.EditState: esAutocomplete :: forall n_a19JC. Lens' (EditState n_a19JC) (Maybe (AutocompleteState n_a19JC))
+ Matterhorn.Types.EditState: esAutocomplete :: forall n_a1886. Lens' (EditState n_a1886) (Maybe (AutocompleteState n_a1886))
- Matterhorn.Types.EditState: esAutocompletePending :: forall n_a19JC. Lens' (EditState n_a19JC) (Maybe Text)
+ Matterhorn.Types.EditState: esAutocompletePending :: forall n_a1886. Lens' (EditState n_a1886) (Maybe Text)
- Matterhorn.Types.EditState: esChannelId :: forall n_a19JC. Lens' (EditState n_a19JC) ChannelId
+ Matterhorn.Types.EditState: esChannelId :: forall n_a1886. Lens' (EditState n_a1886) ChannelId
- Matterhorn.Types.EditState: esEditMode :: forall n_a19JC. Lens' (EditState n_a19JC) EditMode
+ Matterhorn.Types.EditState: esEditMode :: forall n_a1886. Lens' (EditState n_a1886) EditMode
- Matterhorn.Types.EditState: esEditor :: forall n_a19JC. Lens' (EditState n_a19JC) (Editor Text n_a19JC)
+ Matterhorn.Types.EditState: esEditor :: forall n_a1886. Lens' (EditState n_a1886) (Editor Text n_a1886)
- Matterhorn.Types.EditState: esEphemeral :: forall n_a19JC. Lens' (EditState n_a19JC) EphemeralEditState
+ Matterhorn.Types.EditState: esEphemeral :: forall n_a1886. Lens' (EditState n_a1886) EphemeralEditState
- Matterhorn.Types.EditState: esFileBrowser :: forall n_a19JC. Lens' (EditState n_a19JC) (Maybe (FileBrowser n_a19JC))
+ Matterhorn.Types.EditState: esFileBrowser :: forall n_a1886. Lens' (EditState n_a1886) (Maybe (FileBrowser n_a1886))
- Matterhorn.Types.EditState: esJustCompleted :: forall n_a19JC. Lens' (EditState n_a19JC) Bool
+ Matterhorn.Types.EditState: esJustCompleted :: forall n_a1886. Lens' (EditState n_a1886) Bool
- Matterhorn.Types.EditState: esMisspellings :: forall n_a19JC. Lens' (EditState n_a19JC) (Set Text)
+ Matterhorn.Types.EditState: esMisspellings :: forall n_a1886. Lens' (EditState n_a1886) (Set Text)
- Matterhorn.Types.EditState: esResetEditMode :: forall n_a19JC. Lens' (EditState n_a19JC) EditMode
+ Matterhorn.Types.EditState: esResetEditMode :: forall n_a1886. Lens' (EditState n_a1886) EditMode
- Matterhorn.Types.EditState: esShowReplyPrompt :: forall n_a19JC. Lens' (EditState n_a19JC) Bool
+ Matterhorn.Types.EditState: esShowReplyPrompt :: forall n_a1886. Lens' (EditState n_a1886) Bool
- Matterhorn.Types.EditState: esSpellCheckTimerReset :: forall n_a19JC. Lens' (EditState n_a19JC) (Maybe (IO ()))
+ Matterhorn.Types.EditState: esSpellCheckTimerReset :: forall n_a1886. Lens' (EditState n_a1886) (Maybe (IO ()))
- Matterhorn.Types.EditState: esTeamId :: forall n_a19JC. Lens' (EditState n_a19JC) (Maybe TeamId)
+ Matterhorn.Types.EditState: esTeamId :: forall n_a1886. Lens' (EditState n_a1886) (Maybe TeamId)
- Matterhorn.Types.MessageInterface: attachmentPathDialogFocus :: forall n_a1d7T. Lens' (SaveAttachmentDialogState n_a1d7T) (FocusRing n_a1d7T)
+ Matterhorn.Types.MessageInterface: attachmentPathDialogFocus :: forall n_a1bFl. Lens' (SaveAttachmentDialogState n_a1bFl) (FocusRing n_a1bFl)
- Matterhorn.Types.MessageInterface: attachmentPathEditor :: forall n_a1d7T. Lens' (SaveAttachmentDialogState n_a1d7T) (Editor Text n_a1d7T)
+ Matterhorn.Types.MessageInterface: attachmentPathEditor :: forall n_a1bFl. Lens' (SaveAttachmentDialogState n_a1bFl) (Editor Text n_a1bFl)
- Matterhorn.Types.MessageInterface: miChannelId :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) ChannelId
+ Matterhorn.Types.MessageInterface: miChannelId :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) ChannelId
- Matterhorn.Types.MessageInterface: miEditor :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) (EditState n_a1d7V)
+ Matterhorn.Types.MessageInterface: miEditor :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) (EditState n_a1bFn)
- Matterhorn.Types.MessageInterface: miMessageSelect :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) MessageSelectState
+ Matterhorn.Types.MessageInterface: miMessageSelect :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) MessageSelectState
- Matterhorn.Types.MessageInterface: miMessages :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) Messages
+ Matterhorn.Types.MessageInterface: miMessages :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) Messages
- Matterhorn.Types.MessageInterface: miMode :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) MessageInterfaceMode
+ Matterhorn.Types.MessageInterface: miMode :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) MessageInterfaceMode
- Matterhorn.Types.MessageInterface: miRootPostId :: forall n_a1d7V i_a1d7W i_a1dgT. Lens (MessageInterface n_a1d7V i_a1d7W) (MessageInterface n_a1d7V i_a1dgT) i_a1d7W i_a1dgT
+ Matterhorn.Types.MessageInterface: miRootPostId :: forall n_a1bFn i_a1bFo i_a1bQC. Lens (MessageInterface n_a1bFn i_a1bFo) (MessageInterface n_a1bFn i_a1bQC) i_a1bFo i_a1bQC
- Matterhorn.Types.MessageInterface: miSaveAttachmentDialog :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) (SaveAttachmentDialogState n_a1d7V)
+ Matterhorn.Types.MessageInterface: miSaveAttachmentDialog :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) (SaveAttachmentDialogState n_a1bFn)
- Matterhorn.Types.MessageInterface: miTarget :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) MessageInterfaceTarget
+ Matterhorn.Types.MessageInterface: miTarget :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) MessageInterfaceTarget
- Matterhorn.Types.MessageInterface: miUrlList :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) (URLList n_a1d7V)
+ Matterhorn.Types.MessageInterface: miUrlList :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) (URLList n_a1bFn)
- Matterhorn.Types.MessageInterface: miUrlListSource :: forall n_a1d7V i_a1d7W. Lens' (MessageInterface n_a1d7V i_a1d7W) URLListSource
+ Matterhorn.Types.MessageInterface: miUrlListSource :: forall n_a1bFn i_a1bFo. Lens' (MessageInterface n_a1bFn i_a1bFo) URLListSource
- Matterhorn.Types.MessageInterface: ulList :: forall n_a1d7U n_a1dpG. Lens (URLList n_a1d7U) (URLList n_a1dpG) (List n_a1d7U (Int, LinkChoice)) (List n_a1dpG (Int, LinkChoice))
+ Matterhorn.Types.MessageInterface: ulList :: forall n_a1bFm n_a1c0x. Lens (URLList n_a1bFm) (URLList n_a1c0x) (List n_a1bFm (Int, LinkChoice)) (List n_a1c0x (Int, LinkChoice))
- Matterhorn.Types.MessageInterface: ulSource :: forall n_a1d7U. Lens' (URLList n_a1d7U) (Maybe URLListSource)
+ Matterhorn.Types.MessageInterface: ulSource :: forall n_a1bFm. Lens' (URLList n_a1bFm) (Maybe URLListSource)
- Matterhorn.Types.RichText: data ColAlignment
+ Matterhorn.Types.RichText: data () => ColAlignment
- Matterhorn.Types.RichText: data DelimiterType
+ Matterhorn.Types.RichText: data () => DelimiterType
- Matterhorn.Types.RichText: data EnumeratorType
+ Matterhorn.Types.RichText: data () => EnumeratorType
- Matterhorn.Types.RichText: data ListSpacing
+ Matterhorn.Types.RichText: data () => ListSpacing
- Matterhorn.Types.RichText: data ListType
+ Matterhorn.Types.RichText: data () => ListType

Files

CHANGELOG.md view
@@ -1,4 +1,31 @@ +90000.0.0+=========++NOTE: this version of Matterhorn requires server version 9.0 or greater.++Package changes:+* Updated to use Vty 6 for crossplatform terminal support, meaning+  Matterhorn can now be built and run on Windows terminals. Please let+  us know if you try this and encounter any issues!++Enhancements:+* Added support for a new "auto" mode to determine channel list width.+  There is now a new `auto` value for the `channelListWidth`+  configuration file setting. Its default is unchanged and it can still+  take an integer value specifying the channel list width in columns.+  If set to `auto`, its value is determined by Matterhorn, bounded by+  minimum and maximum values, as a function of window width. This is+  intended to give nicer results as font size decreases, up to a point.+* Add a `/write-theme` command to write the current theme to an INI+  file.++Bug fixes:+* Updated channel viewing book-keeping to work with changes in+  Mattermost 9.0.+* Fixed an issue where terminal input provided right before the UI is+  initialized could cause the application to crash.+ 50200.19.0 ========== 
docs/commands.md view
@@ -58,3 +58,4 @@ | `/topic <topic>` | Set the current channel's topic (header) | | `/user` | Show users to initiate a private DM chat channel | | `/username-attribute <@user>` | Display the attribute used to color the specified username |+| `/write-theme <path>` | Write the current theme to a theme settings file |
matterhorn.cabal view
@@ -1,5 +1,5 @@ name:                matterhorn-version:             50200.19.0+version:             90000.0.0 synopsis:            Terminal client for the Mattermost chat system description:         This is a terminal client for the Mattermost chat                      system. Please see the README for a list of@@ -170,31 +170,32 @@     ghc-options: -fhide-source-paths    build-depends:       base                 >=4.8      && <5-                     , mattermost-api       == 50200.15.0+                     , mattermost-api       == 90000.0.0                      , base-compat          >= 0.9     && < 0.13                      , unordered-containers >= 0.2     && < 0.3                      , containers           >= 0.5.7   && < 0.7                      , split                >= 0.2     && < 0.3                      , data-clist           >= 0.1.2   && < 0.2                      , semigroups           >= 0.18    && < 0.20-                     , connection           >= 0.2     && < 0.4-                     , text                 >= 1.2.5.0 && < 2.0+                     , crypton-connection   >= 0.3.1   && < 0.4+                     , text                 >= 1.2.5.0 && < 2.1                      , bytestring           >= 0.10    && < 0.12                      , stm                  >= 2.4     && < 2.6                      , config-ini           >= 0.2.2.0 && < 0.3                      , process              >= 1.4     && < 1.7                      , microlens-platform   >= 0.3     && < 0.5-                     , brick                >= 1.8     && < 1.9+                     , brick                >= 2.0     && < 2.1                      , brick-skylighting    >= 1.0     && < 1.1-                     , vty                  >= 5.38    && < 5.39+                     , vty                  >= 6.0     && < 6.1+                     , vty-crossplatform    >= 0.2.0.0 && < 0.3.0.0                      , word-wrap            >= 0.4.0   && < 0.5-                     , transformers         >= 0.4     && < 0.6+                     , transformers         >= 0.4     && < 0.7                      , text-zipper          >= 0.13    && < 0.14                      , time                 >= 1.6     && < 2.0                      , xdg-basedir          >= 0.2     && < 0.3                      , filepath             >= 1.4     && < 1.5                      , directory            >= 1.3     && < 1.4-                     , vector               < 0.13+                     , vector               < 0.14                      , strict               >= 0.3     && < 0.6                      , hashable             >= 1.2     && < 1.5                      , commonmark           >= 0.2.1   && < 0.3@@ -207,7 +208,7 @@                      , mtl                  >= 2.2     && < 2.4                      , aspell-pipe          >= 0.6     && < 0.7                      , stm-delay            >= 0.1     && < 0.2-                     , unix                 >= 2.7.1.0 && < 2.9+                     , unix-compat          >= 0.6     && < 0.8                      , skylighting-core     >= 0.12    && < 0.13                      , timezone-olson       >= 0.2     && < 0.3                      , timezone-series      >= 0.1.6.1 && < 0.2
src/Matterhorn/App.hs view
@@ -10,9 +10,9 @@ import           Brick import           Control.Monad.Trans.Except ( runExceptT ) import qualified Graphics.Vty as Vty+import qualified Graphics.Vty.CrossPlatform as Vty import           Text.Aspell ( stopAspell ) import           GHC.Conc (getNumProcessors, setNumCapabilities)-import           System.Posix.IO ( stdInput )  import           Network.Mattermost @@ -32,11 +32,14 @@ app =     App { appDraw         = draw         , appHandleEvent  = Events.onEvent-        , appStartEvent   = return ()         , appAttrMap      = (^.csResources.crTheme)         , appChooseCursor = \s cs -> do             tId <- s^.csCurrentTeamId             cursorByMode cs s tId (teamMode $ s^.csTeam(tId))+        , appStartEvent = do+            vty <- getVtyHandle+            (w, h) <- liftIO $ Vty.displayBounds $ Vty.outputIface vty+            runMHEvent $ Events.setWindowSize w h         }  cursorByMode :: [CursorLocation Name] -> ChatState -> TeamId -> Mode -> Maybe (CursorLocation Name)@@ -84,12 +87,7 @@     setupCpuUsage config      let mkVty = do-          mEraseChar <- Vty.getTtyEraseChar stdInput-          let addEraseChar cfg = case mEraseChar of-                  Nothing -> cfg-                  Just ch -> cfg { Vty.inputMap = (Nothing, [ch], Vty.EvKey Vty.KBS []) : Vty.inputMap cfg }--          vty <- Vty.mkVty $ addEraseChar Vty.defaultConfig+          vty <- Vty.mkVty Vty.defaultConfig           let output = Vty.outputIface vty           Vty.setMode output Vty.BracketedPaste True           Vty.setMode output Vty.Hyperlink $ configHyperlinkingMode config
src/Matterhorn/Command.hs view
@@ -12,6 +12,7 @@ import           Matterhorn.Prelude  import           Brick.Main ( invalidateCache )+import           Brick.Themes ( saveTheme ) import qualified Control.Exception as Exn import qualified Data.Char as Char import qualified Data.Text as T@@ -132,6 +133,12 @@   , Cmd "members" "Show the current channel's members"     NoArg $ \ () -> do         withCurrentTeam enterChannelMembersUserList++  , Cmd "write-theme" "Write the current theme to a theme settings file"+    (TokenArg "path" NoArg) $ \(path, ()) -> do+        theme <- use (csResources.crThemeOriginal)+        liftIO $ saveTheme (T.unpack path) theme+        postInfoMessage $ "Current theme written to " <> path    , Cmd "leave" "Leave a normal channel or hide a DM channel" NoArg $ \ () -> do         withCurrentTeam startLeaveCurrentChannel
src/Matterhorn/Config.hs view
@@ -80,7 +80,7 @@     configTeam           <- fieldMbOf "team" stringField     configPort           <- fieldDefOf "port" number (configPort defaultConfig)     configUrlPath        <- fieldMbOf "urlPath" stringField-    configChannelListWidth <- fieldDefOf "channelListWidth" number+    configChannelListWidth <- fieldDefOf "channelListWidth" channelListWidthField                               (configChannelListWidth defaultConfig)     configCpuUsagePolicy <- fieldDefOf "cpuUsagePolicy" cpuUsagePolicy                             (configCpuUsagePolicy defaultConfig)@@ -260,6 +260,14 @@     , (MoveCurrentTeamRightEvent        , [ ])     ] +channelListWidthField :: Text -> Either String ChannelListWidth+channelListWidthField t =+    case T.toLower t of+        "auto" -> return ChannelListWidthAuto+        _ -> case readMaybe (T.unpack t) of+            Nothing -> Left "Invalid value for channelListWidth"+            Just w  -> Right $ ChannelListWidthFixed w+ channelListOrientationField :: Text -> Either String ChannelListOrientation channelListOrientationField t =     case T.toLower t of@@ -416,7 +424,7 @@            , configAspellDictionary            = Nothing            , configUnsafeUseHTTP               = False            , configValidateServerCertificate   = True-           , configChannelListWidth            = 22+           , configChannelListWidth            = ChannelListWidthFixed 22            , configLogMaxBufferSize            = 200            , configShowOlderEdits              = True            , configUserKeys                    = newKeyConfig allEvents [] []
src/Matterhorn/Constants.hs view
@@ -8,6 +8,8 @@   , userSigil   , userSigilChar   , editMarking+  , channelListMinAutoWidth+  , channelListMaxAutoWidth   ) where @@ -16,6 +18,14 @@  import qualified Data.Text as T ++-- | The minimum channel list width when the width is set to 'auto'.+channelListMinAutoWidth :: Int+channelListMinAutoWidth = 24++-- | The maximum channel list width when the width is set to 'auto'.+channelListMaxAutoWidth :: Int+channelListMaxAutoWidth = 44  -- | The number of rows to consider a "page" when scrolling pageAmount :: Int
src/Matterhorn/Draw/Autocomplete.hs view
@@ -18,6 +18,7 @@ import           Network.Mattermost.Types ( User(..), Channel(..), TeamId )  import           Matterhorn.Constants ( normalChannelSigil )+import           Matterhorn.Draw.ChannelList ( channelListWidth ) import           Matterhorn.Draw.Util ( mkChannelName ) import           Matterhorn.Themes import           Matterhorn.Types@@ -93,10 +94,9 @@         curUser = myUsername st         cfg = st^.csResources.crConfiguration         showingChanList = configShowChannelList cfg-        chanListWidth = configChannelListWidth cfg         maybeLimit = fromMaybe id $ do             let sub = if showingChanList-                      then chanListWidth + 1+                      then channelListWidth st + 1                       else 0                 threadNarrow = threadShowing && (cfg^.configThreadOrientationL `elem` [ThreadLeft, ThreadRight])                 threadShowing = isJust $ st^.csTeam(tId).tsThreadInterface
src/Matterhorn/Draw/ChannelList.hs view
@@ -16,7 +16,12 @@ --     channels matching the entered text (and highlighting the --     matching portion). -module Matterhorn.Draw.ChannelList (renderChannelList, renderChannelListHeader) where+module Matterhorn.Draw.ChannelList+  ( renderChannelList+  , renderChannelListHeader+  , channelListWidth+  )+where  import           Prelude () import           Matterhorn.Prelude@@ -34,6 +39,7 @@  import           Matterhorn.Draw.Util import           Matterhorn.State.Channels+import           Matterhorn.Constants ( channelListMinAutoWidth, channelListMaxAutoWidth ) import           Matterhorn.Themes import           Matterhorn.Types import           Matterhorn.Types.Common ( sanitizeUserText )@@ -54,10 +60,17 @@                          , entryUserStatus  :: Maybe UserStatus                          } -sbRenderer :: ScrollbarRenderer n+sbRenderer :: VScrollbarRenderer n sbRenderer =-    verticalScrollbarRenderer { renderScrollbarHandleBefore = str "▲"-                              , renderScrollbarHandleAfter = str "▼"+    verticalScrollbarRenderer { renderVScrollbarHandleBefore = str "▲"+                              , renderVScrollbarHandleAfter = str "▼"+                              , scrollbarWidthAllocation = 2+                              , renderVScrollbar =+                                  hLimit 1 $+                                  renderVScrollbar verticalScrollbarRenderer+                              , renderVScrollbarTrough =+                                  hLimit 1 $+                                  renderVScrollbarTrough verticalScrollbarRenderer                               }  renderChannelListHeader :: ChatState -> MM.TeamId -> Widget Name@@ -84,9 +97,9 @@ renderChannelList st tId =     header <=> vpBody     where-        (sbOrientation, sbPad) = case st^.csResources.crConfiguration.configChannelListOrientationL of-            ChannelListLeft -> (OnLeft, padLeft (Pad 1))-            ChannelListRight -> (OnRight, padRight (Pad 1))+        sbOrientation = case st^.csResources.crConfiguration.configChannelListOrientationL of+            ChannelListLeft -> OnLeft+            ChannelListRight -> OnRight         myUsername_ = myUsername st         channelName e = ClickableChannelListEntry $ channelListEntryChannelId e         renderEntry s e = clickable (channelName e) $@@ -96,7 +109,7 @@                  withVScrollBars sbOrientation $                  withVScrollBarHandles $                  withClickableVScrollBars VScrollBar $-                 viewport (ChannelListViewport tId) Vertical $ sbPad body+                 viewport (ChannelListViewport tId) Vertical body         body = case teamMode $ st^.csTeam(tId) of             ChannelSelect ->                 let zipper = st^.csTeam(tId).tsChannelSelectState.channelSelectMatches@@ -269,3 +282,16 @@  returnChannelSigil :: String returnChannelSigil = "~"++channelListWidthAutoPercent :: Double+channelListWidthAutoPercent = 0.2++channelListWidth :: ChatState -> Int+channelListWidth st =+    case configChannelListWidth $ st^.csResources.crConfiguration of+        ChannelListWidthFixed w -> w+        ChannelListWidthAuto ->+            let calcWidth = round $ channelListWidthAutoPercent * (fromIntegral width :: Double)+                width = fst $ st^.csResources.crWindowSize+            in min channelListMaxAutoWidth $+               max channelListMinAutoWidth calcWidth
src/Matterhorn/Draw/Main.hs view
@@ -20,7 +20,7 @@                                           )  -import           Matterhorn.Draw.ChannelList ( renderChannelList )+import           Matterhorn.Draw.ChannelList ( renderChannelList, channelListWidth ) import           Matterhorn.Draw.Messages import           Matterhorn.Draw.MessageInterface import           Matterhorn.Draw.Autocomplete@@ -76,10 +76,9 @@     mainDisplay = maybeSubdue messageInterface      channelList = channelListMaybeVlimit mode $-                  hLimit channelListWidth $ case mtId of+                  hLimit (channelListWidth st) $ case mtId of                       Nothing -> fill ' '                       Just tId -> renderChannelList st tId-    channelListWidth = configChannelListWidth $ st^.csResources.crConfiguration     channelListMaybeVlimit ChannelSelect w =         Widget (hSize w) (vSize w) $ do             ctx <- getContext
src/Matterhorn/Events.hs view
@@ -1,5 +1,6 @@ module Matterhorn.Events   ( onEvent+  , setWindowSize   ) where @@ -194,20 +195,25 @@                     ]  handleResizeEvent :: Vty.Event -> MH Bool-handleResizeEvent (Vty.EvResize _ _) = do+handleResizeEvent (Vty.EvResize w h) = do+    setWindowSize w h+    return True+handleResizeEvent _ =+    return False++setWindowSize :: Int -> Int -> MH ()+setWindowSize w h = do     -- On resize, invalidate the entire rendering cache since many     -- things depend on the window size.     --     -- Note: we fall through after this because it is sometimes     -- important for modes to have their own additional logic to run     -- when a resize occurs, so we don't want to stop processing here.+    csResources.crWindowSize .= (w, h)+     mh invalidateCache     withCurrentTeam $ \tId ->         mh $ makeVisible $ SelectedChannelListEntry tId--    return True-handleResizeEvent _ =-    return False  handleTeamModeEvent :: Vty.Event -> MH Bool handleTeamModeEvent e = do
src/Matterhorn/Events/Websocket.hs view
@@ -166,8 +166,14 @@             | otherwise -> return ()          WMChannelViewed-            | Just cId <- wepChannelId $ weData we -> refreshChannelById cId+            | Just cId <- wepChannelId $ weData we -> mhLog LogGeneral "WMChannelViewed received" >> refreshChannelById cId             | otherwise -> return ()++        WMMultipleChannelsViewed ->+            case wepChannelTimes $ weData we of+                Nothing -> return ()+                Just m ->+                    forM_ (HM.keys m) refreshChannelById          WMChannelUpdated             | Just cId <- webChannelId $ weBroadcast we -> do
src/Matterhorn/InputHistory.hs view
@@ -20,8 +20,8 @@ import           System.Directory ( createDirectoryIfMissing ) import           System.FilePath ( dropFileName ) import qualified System.IO.Strict as S-import qualified System.Posix.Files as P-import qualified System.Posix.Types as P+import qualified System.PosixCompat.Files as P+import qualified System.PosixCompat.Types as P  import           Network.Mattermost.Types ( ChannelId ) 
src/Matterhorn/LastRunState.hs view
@@ -23,8 +23,8 @@ import           Lens.Micro.Platform ( makeLenses ) import           System.Directory ( createDirectoryIfMissing ) import           System.FilePath ( dropFileName )-import qualified System.Posix.Files as P-import qualified System.Posix.Types as P+import qualified System.PosixCompat.Files as P+import qualified System.PosixCompat.Types as P  import           Network.Mattermost.Lenses import           Network.Mattermost.Types
src/Matterhorn/Login.hs view
@@ -69,7 +69,7 @@ import           Data.List (tails, inits) import           System.IO.Error ( catchIOError ) import qualified Data.Text as T-import           Graphics.Vty hiding (mkVty)+import           Graphics.Vty import           Lens.Micro.Platform ( (.~), (.=), Lens', makeLenses ) import qualified System.IO.Error as Err import           Network.URI ( URI(..), URIAuth(..), parseURI )
src/Matterhorn/State/Channels.hs view
@@ -334,7 +334,7 @@              -- Create a new ClientChannel structure             cChannel <- (ccInfo %~ channelInfoFromChannelWithData nc member) <$>-                       makeClientChannel eventQueue spellChecker (me^.userIdL) (channelTeamId nc) nc+                       makeClientChannel eventQueue spellChecker (me^.userIdL) (channelTeamId nc) nc member              st <- use id @@ -506,8 +506,6 @@  postChangeChannelCommon :: TeamId -> MH () postChangeChannelCommon tId = do-    -- resetEditorState cId-    -- loadLastEdit tId     fetchVisibleIfNeeded tId  loadLastChannelInput :: Lens' ChatState (MessageInterface n i) -> MH ()@@ -524,6 +522,7 @@ preChangeChannelCommon tId = do     withCurrentChannel tId $ \cId _ -> do         csTeam(tId).tsRecentChannel .= Just cId+        csChannel(cId) %= clearEditedThreshold  saveEditorInput :: Lens' ChatState (MessageInterface n i) -> MH () saveEditorInput which = do
src/Matterhorn/State/Messages.hs view
@@ -34,7 +34,7 @@ import qualified Data.Sequence as Seq import qualified Data.Text as T import           Graphics.Vty ( outputIface )-import           Graphics.Vty.Output.Interface ( ringTerminalBell )+import           Graphics.Vty.Output ( ringTerminalBell ) import           Lens.Micro.Platform ( Traversal', (.=), (%=), (%~), (.~)                                      , to, at, traversed, filtered, ix, _1, _Just ) @@ -45,6 +45,7 @@  import           Matterhorn.Constants import           Matterhorn.State.Channels+import           Matterhorn.State.ChannelList ( updateSidebar ) import           Matterhorn.State.Common import           Matterhorn.State.ThreadWindow import           Matterhorn.State.MessageSelect@@ -579,6 +580,34 @@                   not (userPrefs^.userPrefShowJoinLeave) && isJoinOrLeave                 cId = postChannelId new +                -- TODO: match server-side logic to determine whether+                -- this message counts as a post, for post-counting+                -- purposes, to decide whether this should trigger an+                -- increment of the total/viewed post counts+                maybeIncrementTotalMessageCount =+                    let shouldIncrement = case newPostData of+                                              RecentPost {} ->+                                                  True+                                              _ ->+                                                  False+                    in if shouldIncrement+                       then incrementTotalMessageCount+                       else id++                maybeIncrementViewedMessageCount currCId =+                    let shouldIncrement = case newPostData of+                                              RecentPost {} ->+                                                  currCId == Just cId+                                              _ ->+                                                  False+                    in if shouldIncrement+                       then incrementViewedMessageCount+                       else id++                maybeIncrementMessageCounts currCId =+                    maybeIncrementTotalMessageCount .+                    maybeIncrementViewedMessageCount currCId+                 doAddMessage = do                     -- Do we have the user data for the post author?                     case cp^.cpUser of@@ -606,6 +635,7 @@                     csChannels %= modifyChannelById cId                       ((ccMessageInterface.miMessages %~ addMessage msg') .                        (if not ignoredJoinLeaveMessage then adjustUpdated new else id) .+                       maybeIncrementMessageCounts currCId .                        (\c -> if currCId == Just cId                               then c                               else case newPostData of@@ -627,6 +657,8 @@                     -- channel, the currently-selected team (mcurTId)                     -- since all DM channels appear in all teams.                     addPostToOpenThread (mTId <|> mcurTId) new msg'++                    updateSidebar mTId                      postedChanMessage 
src/Matterhorn/State/Setup.hs view
@@ -161,6 +161,7 @@                            , _crSubprocessLog       = slc                            , _crWebsocketActionChan = wac                            , _crTheme               = themeToAttrMap custTheme+                           , _crThemeOriginal       = custTheme                            , _crStatusUpdateChan    = userStatusChan                            , _crConfiguration       = config                            , _crFlaggedPosts        = mempty@@ -169,6 +170,7 @@                            , _crLogManager          = logMgr                            , _crEmoji               = emoji                            , _crSpellChecker        = spResult+                           , _crWindowSize          = (0, 0)                            }      st <- initializeState cr initialTeamId teams me
src/Matterhorn/State/Teams.hs view
@@ -43,6 +43,10 @@                                           , teamOrderPref, Post, ChannelId, postId                                           , emptyChannelNotifyProps, UserId                                           , channelName, Type(..), channelDisplayName+                                          , Channel, ChannelMember+                                          , channelMemberMsgCount+                                          , channelTotalMsgCount+                                          , UserParam(UserById)                                           ) import qualified Network.Mattermost.Endpoints as MM @@ -216,7 +220,8 @@     -- Since the only channel we are dealing with is by construction the     -- last channel, we don't have to consider other cases here:     chanPairs <- forM (toList chans) $ \c -> do-        cChannel <- makeClientChannel eventQueue (cr^.crSpellChecker) (userId me) (Just tId) c+        m <- MM.mmGetChannelMember (getId c) (UserById $ userId me) session+        cChannel <- makeClientChannel eventQueue (cr^.crSpellChecker) (userId me) (Just tId) c m         return (getId c, cChannel)      now <- getCurrentTime@@ -434,16 +439,17 @@                   -> UserId                   -> Maybe TeamId                   -> Channel+                  -> ChannelMember                   -> m ClientChannel-makeClientChannel eventQueue spellChecker myId tId nc = do+makeClientChannel eventQueue spellChecker myId tId nc member = do     msgs <- emptyChannelMessages     mi <- liftIO $ newChannelMessageInterface spellChecker eventQueue tId (getId nc) msgs-    return ClientChannel { _ccInfo = initialChannelInfo myId nc+    return ClientChannel { _ccInfo = initialChannelInfo myId nc member                          , _ccMessageInterface = mi                          } -initialChannelInfo :: UserId -> Channel -> ChannelInfo-initialChannelInfo myId chan =+initialChannelInfo :: UserId -> Channel -> ChannelMember -> ChannelInfo+initialChannelInfo myId chan member =     let updated  = chan ^. channelLastPostAtL     in ChannelInfo { _cdChannelId              = chan^.channelIdL                    , _cdTeamId                 = chan^.channelTeamIdL@@ -464,4 +470,6 @@                                                  else Nothing                    , _cdSidebarShowOverride    = Nothing                    , _cdFetchPending           = False+                   , _cdTotalMessageCount      = channelTotalMsgCount chan+                   , _cdViewedMessageCount     = channelMemberMsgCount member                    }
src/Matterhorn/State/Teams.hs-boot view
@@ -6,9 +6,9 @@ import qualified Brick.BChan as BCH import           Text.Aspell ( Aspell ) -import           Network.Mattermost.Types ( Channel, UserId, TeamId )+import           Network.Mattermost.Types ( Channel, ChannelMember, UserId, TeamId )  import           Matterhorn.Types ( MHEvent ) import           Matterhorn.Types.Channels ( ClientChannel ) -makeClientChannel :: (MonadIO m) => BCH.BChan MHEvent -> Maybe Aspell -> UserId -> Maybe TeamId -> Channel -> m ClientChannel+makeClientChannel :: (MonadIO m) => BCH.BChan MHEvent -> Maybe Aspell -> UserId -> Maybe TeamId -> Channel -> ChannelMember -> m ClientChannel
src/Matterhorn/State/ThemeListWindow.hs view
@@ -85,3 +85,4 @@         Just it -> do             mh invalidateCache             csResources.crTheme .= (themeToAttrMap $ internalTheme it)+            csResources.crThemeOriginal .= internalTheme it
src/Matterhorn/Types.hs view
@@ -99,6 +99,7 @@   , unsafeKeyDispatcher   , bindingConflictMessage +  , ChannelListWidth(..)   , NotificationVersion(..)   , PasswordSource(..)   , TokenSource(..)@@ -235,6 +236,7 @@   , crUserPreferences   , crEventQueue   , crTheme+  , crThemeOriginal   , crStatusUpdateChan   , crSubprocessLog   , crWebsocketActionChan@@ -246,6 +248,7 @@   , crSyntaxMap   , crLogManager   , crSpellChecker+  , crWindowSize   , crEmoji   , getSession   , getResourceSession@@ -485,6 +488,14 @@     | TeamListSortUnreadFirst     deriving (Eq, Show, Ord) +data ChannelListWidth =+    ChannelListWidthFixed Int+    -- ^ A fixed width in columns.+    | ChannelListWidthAuto+    -- ^ Automatically determine a reasonable width based on the window+    -- dimensions.+    deriving (Eq, Show, Ord)+ -- | This is how we represent the user's configuration. Most fields -- correspond to configuration file settings (see Config.hs) but some -- are for internal book-keeping purposes only.@@ -549,7 +560,7 @@            -- ^ Whether to permit an insecure HTTP connection.            , configValidateServerCertificate :: Bool            -- ^ Whether to validate TLS certificates.-           , configChannelListWidth :: Int+           , configChannelListWidth :: ChannelListWidth            -- ^ The width, in columns, of the channel list sidebar.            , configLogMaxBufferSize :: Int            -- ^ The maximum size, in log entries, of the internal log@@ -629,14 +640,18 @@                     , _userPrefTeamOrder :: Maybe [TeamId]                     } -hasUnread' :: ClientChannel -> Bool-hasUnread' chan = fromMaybe False $ do+hasUnread :: ClientChannel -> Type -> Bool+hasUnread chan ty =     let info = _ccInfo chan-    lastViewTime <- _cdViewed info-    return $ _cdMentionCount info > 0 ||-             (not (isMuted chan) &&-              (((_cdUpdated info) > lastViewTime) ||-               (isJust $ _cdEditedMessageThreshold info)))+        hasMentions = countMentions && _cdMentionCount info > 0+        hasNewMessages = _cdTotalMessageCount info > _cdViewedMessageCount info+        hasEditThreshold = isJust $ _cdEditedMessageThreshold info+        countMentions = case ty of+            Direct -> False+            Group -> False+            _ -> True+    in hasMentions ||+       (not (isMuted chan) && (hasNewMessages || hasEditThreshold))  mkChannelZipperList :: ChannelListSorting                     -> UTCTime@@ -701,7 +716,7 @@         mkEntry (cId, ch) = ChannelListEntry { channelListEntryChannelId = cId                                              , channelListEntryType = CLChannel                                              , channelListEntryMuted = isMuted ch-                                             , channelListEntryUnread = hasUnread' ch+                                             , channelListEntryUnread = hasUnread ch ty                                              , channelListEntrySortValue = ch^.ccInfo.cdDisplayName.to T.toLower                                              , channelListEntryFavorite = isFavorite prefs cId                                              }@@ -759,7 +774,7 @@     in fmap (\(cId, ch) -> ChannelListEntry { channelListEntryChannelId = cId                                             , channelListEntryType = CLGroupDM                                             , channelListEntryMuted = isMuted ch-                                            , channelListEntryUnread = hasUnread' ch+                                            , channelListEntryUnread = hasUnread ch Group                                             , channelListEntrySortValue = ch^.ccInfo.cdDisplayName                                             , channelListEntryFavorite = isFavorite prefs cId                                             }) $@@ -785,7 +800,7 @@                     then return (ChannelListEntry { channelListEntryChannelId = cId                                                   , channelListEntryType = CLUserDM uId                                                   , channelListEntryMuted = isMuted c-                                                  , channelListEntryUnread = hasUnread' c+                                                  , channelListEntryUnread = hasUnread c Direct                                                   , channelListEntrySortValue = displayNameForUser u cconfig prefs                                                   , channelListEntryFavorite = isFavorite prefs cId                                                   })@@ -815,7 +830,7 @@         cId = c^.ccInfo.cdChannelId     in if isFavorite prefs cId        then True-       else (if hasUnread' c || maybe False (>= localCutoff) (c^.ccInfo.cdSidebarShowOverride)+       else (if hasUnread c Direct || maybe False (>= localCutoff) (c^.ccInfo.cdSidebarShowOverride)              then True              else case dmChannelShowPreference prefs uId of                     Just False -> False@@ -841,7 +856,7 @@         cId = c^.ccInfo.cdChannelId     in if isFavorite prefs cId        then True-       else (if hasUnread' c || maybe False (>= localCutoff) (c^.ccInfo.cdSidebarShowOverride)+       else (if hasUnread c Group || maybe False (>= localCutoff) (c^.ccInfo.cdSidebarShowOverride)              then True              else case groupChannelShowPreference prefs cId of                     Just False -> False@@ -1070,6 +1085,7 @@                   , _crSubprocessLog       :: STM.TChan ProgramOutput                   , _crWebsocketActionChan :: STM.TChan WebsocketAction                   , _crTheme               :: AttrMap+                  , _crThemeOriginal       :: Theme                   , _crStatusUpdateChan    :: STM.TChan [UserId]                   , _crConfiguration       :: Config                   , _crFlaggedPosts        :: Set PostId@@ -1078,6 +1094,7 @@                   , _crLogManager          :: LogManager                   , _crEmoji               :: EmojiCollection                   , _crSpellChecker        :: Maybe Aspell+                  , _crWindowSize          :: (Int, Int)                   }  -- | The 'GlobalEditState' value contains state not specific to any
src/Matterhorn/Types/Channels.hs view
@@ -19,6 +19,7 @@   , cdName, cdDisplayName, cdHeader, cdPurpose, cdType   , cdMentionCount, cdDMUserId, cdChannelId   , cdSidebarShowOverride, cdNotifyProps, cdTeamId, cdFetchPending+  , cdTotalMessageCount, cdViewedMessageCount   -- * Managing ClientChannel collections   , noChannels, addChannel, removeChannel, findChannelById, modifyChannelById   , channelByIdL, maybeChannelByIdL@@ -33,6 +34,8 @@   , adjustUpdated   , adjustEditedThreshold   , updateNewMessageIndicator+  , incrementTotalMessageCount+  , incrementViewedMessageCount   -- * Notification settings   , notifyPreference   , isMuted@@ -72,6 +75,7 @@                                           , WithDefault(..)                                           , ServerTime                                           , TeamId+                                          , channelTotalMsgCount                                           )  import           Matterhorn.Types.Messages ( Messages, noMessages, addMessage@@ -121,6 +125,8 @@           , _cdPurpose          = (sanitizeUserText $ chan^.channelPurposeL)           , _cdType             = (chan^.channelTypeL)           , _cdMentionCount     = chanMember^.to channelMemberMentionCount+          , _cdTotalMessageCount = channelTotalMsgCount chan+          , _cdViewedMessageCount = chanMember^.to channelMemberMsgCount           , _cdNotifyProps      = chanMember^.to channelMemberNotifyProps           } @@ -174,6 +180,10 @@     -- whether to show the channel.   , _cdFetchPending :: Bool     -- ^ Whether a fetch in this channel is pending+  , _cdTotalMessageCount :: Int+    -- ^ Total message count+  , _cdViewedMessageCount :: Int+    -- ^ Viewed message count, for tracking unread status   }  -- ** Channel-related Lenses@@ -328,6 +338,14 @@  maxPostTimestamp :: Post -> ServerTime maxPostTimestamp m = max (m^.postDeleteAtL . non (m^.postUpdateAtL)) (m^.postCreateAtL)++incrementTotalMessageCount :: ClientChannel -> ClientChannel+incrementTotalMessageCount =+    ccInfo.cdTotalMessageCount %~ succ++incrementViewedMessageCount :: ClientChannel -> ClientChannel+incrementViewedMessageCount =+    ccInfo.cdViewedMessageCount %~ succ  updateNewMessageIndicator :: Post -> ClientChannel -> ClientChannel updateNewMessageIndicator m =