427 lines
11 KiB
Ruby
427 lines
11 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'reducers/data'
|
|
|
|
class Reducer < Obredux::Reducer
|
|
combine data: Reducers::Data
|
|
|
|
class << self
|
|
attr_reader :screen_width, :screen_height
|
|
|
|
def screen_width=(value)
|
|
raise TypeError, "expected screen width to be an #{Integer}" unless value.is_a? Integer
|
|
raise ArgumentError, 'expected screen width to be greater than or equal to zero' unless value >= 0
|
|
@screen_width = value
|
|
end
|
|
|
|
def screen_height=(value)
|
|
raise TypeError, "expected screen height to be an #{Integer}" unless value.is_a? Integer
|
|
raise ArgumentError, 'expected screen height to be greater than or equal to zero' unless value >= 0
|
|
@screen_height = value
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def initial_state
|
|
{
|
|
x: 0,
|
|
y: 0,
|
|
width: self.class.screen_width,
|
|
height: self.class.screen_height,
|
|
focus: :sidebar,
|
|
focused: true,
|
|
|
|
sidebar: {
|
|
x: 0,
|
|
y: 0,
|
|
width: Widgets::Logo::WIDTH,
|
|
height: self.class.screen_height,
|
|
focus: :menu,
|
|
focused: true,
|
|
|
|
logo: {
|
|
x: 0,
|
|
y: 0,
|
|
width: Widgets::Logo::WIDTH,
|
|
height: Widgets::Logo::HEIGHT,
|
|
}.freeze,
|
|
|
|
menu: {
|
|
x: 0,
|
|
y: Widgets::Logo::HEIGHT,
|
|
width: Widgets::Logo::WIDTH,
|
|
height: self.class.screen_height - Widgets::Logo::HEIGHT,
|
|
focused: true,
|
|
|
|
active: 0,
|
|
top: 0,
|
|
}.freeze,
|
|
}.freeze,
|
|
|
|
chat: {
|
|
x: Widgets::Logo::WIDTH + 1,
|
|
y: 0,
|
|
width: self.class.screen_width - Widgets::Logo::WIDTH - 1,
|
|
height: self.class.screen_height,
|
|
focus: :new_message,
|
|
focused: false,
|
|
|
|
info: {
|
|
x: Widgets::Logo::WIDTH + 1,
|
|
y: 0,
|
|
width: self.class.screen_width - Widgets::Logo::WIDTH - 1,
|
|
height: 2,
|
|
focused: false,
|
|
}.freeze,
|
|
|
|
new_message: {
|
|
x: Widgets::Logo::WIDTH + 1,
|
|
y: self.class.screen_height - 1,
|
|
width: self.class.screen_width - Widgets::Logo::WIDTH - 1,
|
|
height: 1,
|
|
focused: false,
|
|
}.freeze,
|
|
|
|
history: {
|
|
x: Widgets::Logo::WIDTH + 1,
|
|
y: 3,
|
|
width: self.class.screen_width - Widgets::Logo::WIDTH - 1,
|
|
height: self.class.screen_height - 5,
|
|
focused: true,
|
|
}.freeze,
|
|
}.freeze,
|
|
}.freeze
|
|
end
|
|
|
|
def reduce
|
|
case action
|
|
when Actions::WindowLeft
|
|
window_left
|
|
when Actions::WindowRight
|
|
window_right
|
|
when Actions::MenuUp
|
|
menu_up
|
|
when Actions::MenuDown
|
|
menu_down
|
|
when Actions::NewMessagePutc
|
|
new_message_putc
|
|
when Actions::NewMessageLeft
|
|
new_message_left
|
|
when Actions::NewMessageRight
|
|
new_message_right
|
|
when Actions::NewMessageHome
|
|
new_message_home
|
|
when Actions::NewMessageEnd
|
|
new_message_end
|
|
when Actions::NewMessageBackspace
|
|
new_message_backspace
|
|
when Actions::NewMessageDelete
|
|
new_message_delete
|
|
else
|
|
state
|
|
end
|
|
end
|
|
|
|
def window_left
|
|
state.merge(
|
|
focus: :sidebar,
|
|
|
|
sidebar: state[:sidebar].merge(
|
|
focused: true,
|
|
|
|
logo: state[:sidebar][:logo].merge(focused: state[:sidebar][:focus] == :logo).freeze,
|
|
menu: state[:sidebar][:menu].merge(focused: state[:sidebar][:focus] == :menu).freeze,
|
|
).freeze,
|
|
|
|
chat: state[:chat].merge(
|
|
focused: false,
|
|
|
|
info: state[:chat][:info].merge(focused: false).freeze,
|
|
new_message: state[:chat][:new_message].merge(focused: false).freeze,
|
|
history: state[:chat][:history].merge(focused: false).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def window_right
|
|
state.merge(
|
|
focus: :chat,
|
|
|
|
sidebar: state[:sidebar].merge(
|
|
focused: true,
|
|
|
|
logo: state[:sidebar][:logo].merge(focused: false).freeze,
|
|
menu: state[:sidebar][:menu].merge(focused: false).freeze,
|
|
).freeze,
|
|
|
|
chat: state[:chat].merge(
|
|
focused: false,
|
|
|
|
info: state[:chat][:info].merge(focused: state[:chat][:focus] == :info).freeze,
|
|
new_message: state[:chat][:new_message].merge(focused: state[:chat][:focus] == :new_message).freeze,
|
|
history: state[:chat][:history].merge(focused: state[:chat][:focus] == :history).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def menu_up
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
active_friend_index = state[:data][:active_friend_index] + 1
|
|
top = state[:sidebar][:menu][:top]
|
|
|
|
if active_friend_index.negative?
|
|
active_friend_index = state[:data][:friends].count - 1
|
|
elsif active_friend_index >= state[:data][:friends].count
|
|
active_friend_index = 0
|
|
end
|
|
|
|
if active_friend_index < top
|
|
top = active_friend_index
|
|
elsif active_friend_index >= top + state[:height]
|
|
top = active_friend_index - state[:height] + 1
|
|
end
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
active_friend_index: active_friend_index,
|
|
).freeze,
|
|
|
|
sidebar: state[:sidebar].merge(
|
|
menu: state[:sidebar][:menu].merge(
|
|
top: top,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def menu_down
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
active_friend_index = state[:data][:active_friend_index] + 1
|
|
top = state[:sidebar][:menu][:top]
|
|
|
|
if active_friend_index.negative?
|
|
active_friend_index = state[:data][:friends].count - 1
|
|
elsif active_friend_index >= state[:data][:friends].count
|
|
active_friend_index = 0
|
|
end
|
|
|
|
if active_friend_index < top
|
|
top = active_friend_index
|
|
elsif active_friend_index >= top + state[:height]
|
|
top = active_friend_index - state[:height] + 1
|
|
end
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
active_friend_index: active_friend_index,
|
|
).freeze,
|
|
|
|
sidebar: state[:sidebar].merge(
|
|
menu: state[:sidebar][:menu].merge(
|
|
top: top,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_putc
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
text = new_message[:text]
|
|
cursor_pos = new_message[:cursor_pos]
|
|
|
|
text = "#{text[0...cursor_pos]}#{action.char}#{text[cursor_pos..-1]}"
|
|
cursor_pos += 1
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
text: text,
|
|
cursor_pos: cursor_pos,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_left
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
cursor_pos = new_message[:cursor_pos]
|
|
|
|
cursor_pos -= 1
|
|
|
|
cursor_pos = 0 if cursor_pos.negative?
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
cursor_pos: cursor_pos,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_right
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
text = new_message[:text]
|
|
cursor_pos = new_message[:cursor_pos]
|
|
|
|
cursor_pos += 1
|
|
|
|
cursor_pos = text.length if cursor_pos > text.length
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
cursor_pos: cursor_pos,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_home
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
cursor_pos: 0,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_end
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
cursor_pos: new_message[:text].length,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_backspace
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
text = new_message[:text]
|
|
cursor_pos = new_message[:cursor_pos]
|
|
|
|
return state unless cursor_pos.positive?
|
|
|
|
text = "#{text[0...(cursor_pos - 1)]}#{text[cursor_pos..-1]}"
|
|
cursor_pos -= 1
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
text: text,
|
|
cursor_pos: cursor_pos,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
|
|
def new_message_delete
|
|
return state if state[:data][:active_friend_index].nil?
|
|
|
|
friend_number = state[:data][:friends].keys[state[:data][:active_friend_index]]
|
|
|
|
return state if friend_number.nil?
|
|
|
|
friend = state[:data][:friends][friend_number]
|
|
new_message = friend[:new_message]
|
|
|
|
text = new_message[:text]
|
|
cursor_pos = new_message[:cursor_pos]
|
|
|
|
return state if cursor_pos > text.length
|
|
|
|
text = "#{text[0...cursor_pos]}#{text[(cursor_pos + 1)..-1]}"
|
|
|
|
state.merge(
|
|
data: state[:data].merge(
|
|
friends: state[:data][:friends].merge(
|
|
friend_number => friend.merge(
|
|
new_message: new_message.merge(
|
|
text: text,
|
|
cursor_pos: cursor_pos,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze,
|
|
).freeze
|
|
end
|
|
end
|