Skip to content

Commit ce7c69e

Browse files
committed
refactor: 重构导航模块
1 parent 1c739bb commit ce7c69e

File tree

22 files changed

+406
-257
lines changed

22 files changed

+406
-257
lines changed

api/api_topics.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,26 @@ func (cli *v2exClient) GetTopics(
1717
return func() tea.Msg {
1818

1919
var (
20-
conf = g.Config.Get()
21-
nodeIndex = conf.ActiveTab
22-
chooseV2 = conf.ChooseAPIV2
23-
node = g.GetGroupNode(nodeIndex)
24-
res []response.TopicResult
25-
total int
26-
err error
20+
conf = g.Config.Get()
21+
nodeIndex = conf.ActiveTab
22+
chooseV2 = conf.ChooseAPIV2
23+
node = g.GetGroupNode(nodeIndex)
24+
res []response.TopicResult
25+
total int
26+
err error
27+
cachePages = -1
2728
)
2829

2930
// 如果是 myNodes, 那么就去用 V2 的接口
30-
v2 := node.Key == g.NodesMy || chooseV2
31+
v2 := chooseV2
3132
// 最新最热, 只能用 v1
3233
if node.Key == g.HotNode || node.Key == g.LatestNode {
3334
v2 = false
3435
}
3536

3637
g.Session.IsApiV2.Store(v2)
3738
if v2 {
38-
res, total, err = cli.v2TopicApi.GetTopicsByGroupNode(ctx, node, page)
39+
res, cachePages, total, err = cli.v2TopicApi.GetTopicsByGroupNode(ctx, node, page)
3940
} else {
4041
res, total, err = cli.v1TopicApi.GetTopicsByGroupNode(ctx, node, page)
4142
}
@@ -50,6 +51,7 @@ func (cli *v2exClient) GetTopics(
5051
TotalCount: total,
5152
CurrPage: page,
5253
},
54+
CachePages: cachePages,
5355
}
5456
}
5557
}

api/internal/api_topics/api_v2.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/puzpuzpuz/xsync/v4"
1313
"github.com/samber/lo"
1414
"github.com/seth-shi/go-v2ex/v2/g"
15+
"github.com/seth-shi/go-v2ex/v2/pkg"
1516
"github.com/seth-shi/go-v2ex/v2/response"
1617
"golang.org/x/sync/errgroup"
1718
"resty.dev/v3"
@@ -52,11 +53,11 @@ func (api *V2TopicApi) GetTopicsByGroupNode(
5253
ctx context.Context,
5354
node g.GroupNode,
5455
page int,
55-
) (res []response.TopicResult, total int, err error) {
56+
) (res []response.TopicResult, cachePages, total int, err error) {
5657

5758
// 只允许单个请求进来获取 数据
5859
if !api.isRequesting.CompareAndSwap(false, true) {
59-
return nil, 0, ErrLockingRequestData
60+
return nil, 0, 0, ErrLockingRequestData
6061
}
6162
defer api.finishRequest(&err)
6263

@@ -80,8 +81,9 @@ func (api *V2TopicApi) GetTopicsByGroupNode(
8081
}
8182

8283
res = lo.Subset(api.cacheData, (page-1)*perPage, perPage)
84+
cachePages = pkg.TotalPages(len(api.cacheData), perPage)
8385
total, _ = api.groupTotalCount.Load(node.Key)
84-
return res, total, nil
86+
return res, cachePages, total, nil
8587
}
8688

8789
func (api *V2TopicApi) prepareRequest(node g.GroupNode, page int) error {

api/v2ex.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ func SetUpHttpClient(conf *model.FileConfig) {
3939
},
4040
)
4141
client.SetTransport(&pkg.MockRoundTripper{Mock: mockApiResp})
42+
} else if conf.IsDevelopmentEnv() {
43+
client.SetResponseBodyUnlimitedReads(true)
4244
}
4345

4446
V2ex = &v2exClient{

messages/boss.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package messages
22

3-
type BossInitMsg struct{}
43
type BossStartInstallPkgMsg struct{}
54
type BossEndInstallPkgMsg string

messages/detail.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ import (
44
"github.com/seth-shi/go-v2ex/v2/response"
55
)
66

7-
type GetDetailRequest struct {
8-
ID int64
9-
}
10-
117
type GetDetailResponse struct {
128
Data response.V2DetailResult
139
}

messages/topic.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
)
66

77
type GetTopicResponse struct {
8-
Data []response.TopicResult
9-
PageInfo *response.PerTenPageInfo
8+
Data []response.TopicResult
9+
PageInfo *response.PerTenPageInfo
10+
CachePages int
1011
}

model/file.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,24 @@ import (
44
"encoding/json"
55
"os"
66
"path"
7+
"strings"
78

89
"github.com/mitchellh/go-homedir"
910
"github.com/seth-shi/go-v2ex/v2/consts"
1011
)
1112

1213
const (
13-
envProduction = "production"
14-
envDevelopment = "development"
15-
envMock = "mock"
14+
envProduction = "production"
1615
)
1716

1817
type FileConfig struct {
19-
Token string `json:"personal_access_token"`
20-
MyNodes string `json:"my_nodes"`
21-
Timeout uint `json:"timeout"`
22-
ActiveTab int `json:"active_tab"`
23-
ShowMode int `json:"show_mode"`
24-
Env string `json:"env"`
25-
ChooseAPIV2 bool `json:"choose_api_v2"`
26-
BossModeBlank bool `json:"boss_mode_blank"`
18+
Token string `json:"personal_access_token"`
19+
MyNodes string `json:"my_nodes"`
20+
Timeout uint `json:"timeout"`
21+
ActiveTab int `json:"active_tab"`
22+
ShowMode int `json:"show_mode"`
23+
Env string `json:"env"`
24+
ChooseAPIV2 bool `json:"choose_api_v2"`
2725
}
2826

2927
func NewDefaultFileConfig() *FileConfig {
@@ -40,13 +38,13 @@ func NewDefaultFileConfig() *FileConfig {
4038
}
4139

4240
func (c *FileConfig) IsProductionEnv() bool {
43-
return c.Env == envProduction
41+
return strings.Contains(c.Env, "prod")
4442
}
4543
func (c *FileConfig) IsDevelopmentEnv() bool {
46-
return c.Env == envDevelopment
44+
return strings.Contains(c.Env, "dev")
4745
}
4846
func (c *FileConfig) IsMockEnv() bool {
49-
return c.Env == envMock
47+
return strings.Contains(c.Env, "mock")
5048
}
5149

5250
func (c *FileConfig) SwitchShowMode() int {

nav/event.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package nav
2+
3+
import (
4+
tea "github.com/charmbracelet/bubbletea"
5+
)
6+
7+
// PageLife will call every time.
8+
type PageLife interface {
9+
OnEntering() (tea.Model, tea.Cmd)
10+
OnLeaving() (tea.Model, tea.Cmd)
11+
}

nav/msg.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package nav
2+
3+
import (
4+
"reflect"
5+
6+
tea "github.com/charmbracelet/bubbletea"
7+
)
8+
9+
type PopNavigationMsg struct{}
10+
type PushNavigationMsg tea.Model
11+
type NoMorePageMsg struct{}
12+
13+
func Push(m tea.Model) tea.Cmd {
14+
return postCmd(PushNavigationMsg(m))
15+
}
16+
17+
func Back() tea.Cmd {
18+
return postCmd(PopNavigationMsg{})
19+
}
20+
21+
func Histories() []tea.Model {
22+
return nav.histories
23+
}
24+
25+
func CurrentPage() tea.Model {
26+
return nav.curr
27+
}
28+
29+
func IsActivePage(m tea.Model) bool {
30+
curr := nav.curr
31+
if curr == nil || m == nil {
32+
return false
33+
}
34+
35+
return reflect.TypeOf(m).String() == reflect.TypeOf(curr).String()
36+
}
37+
38+
func PushOrBack(m tea.Model) tea.Cmd {
39+
40+
// 如果当前无东西, 直接返回
41+
if IsActivePage(m) {
42+
return Back()
43+
}
44+
45+
return Push(m)
46+
}
47+
48+
func postCmd(msg tea.Msg) tea.Cmd {
49+
return func() tea.Msg {
50+
return msg
51+
}
52+
}

nav/nav.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package nav
2+
3+
import (
4+
tea "github.com/charmbracelet/bubbletea"
5+
)
6+
7+
var (
8+
nav = &navigator{}
9+
maxPages = 1000
10+
)
11+
12+
type navigator struct {
13+
histories []tea.Model
14+
curr tea.Model
15+
}
16+
17+
func View() string {
18+
if nav.curr == nil {
19+
return ""
20+
}
21+
22+
return nav.curr.View()
23+
}
24+
25+
func Update(msg tea.Msg) tea.Cmd {
26+
switch msg := msg.(type) {
27+
case PushNavigationMsg:
28+
return handlePushNavigation(msg)
29+
case PopNavigationMsg:
30+
return handlePopNavigation()
31+
}
32+
33+
if nav.curr == nil {
34+
return nil
35+
}
36+
37+
// update page
38+
var c tea.Cmd
39+
nav.curr, c = nav.curr.Update(msg)
40+
return c
41+
}
42+
43+
// handlePushNavigation 处理页面压入导航栈的操作
44+
func handlePushNavigation(msg PushNavigationMsg) tea.Cmd {
45+
var (
46+
cmds []tea.Cmd
47+
c tea.Cmd
48+
)
49+
50+
// 1. 处理当前页面的离开逻辑
51+
if nav.curr != nil {
52+
// 将当前页面存入历史记录
53+
nav.histories = append(nav.histories, nav.curr)
54+
if len(nav.histories) > maxPages {
55+
first := nav.histories[0]
56+
if p, ok := first.(PageLife); ok {
57+
_, c = p.OnLeaving()
58+
cmds = append(cmds, c)
59+
}
60+
61+
nav.histories = nav.histories[1:]
62+
}
63+
64+
// 调用当前页面的离开钩子
65+
if p, ok := nav.curr.(PageLife); ok {
66+
nav.curr, c = p.OnLeaving()
67+
cmds = append(cmds, c)
68+
}
69+
}
70+
71+
// 2. 压入新页面
72+
nav.curr = tea.Model(msg)
73+
// 3. 初始化新页面并处理进入逻辑
74+
cmds = append(cmds, nav.curr.Init())
75+
76+
// 页面离开钩子
77+
if p, ok := nav.curr.(PageLife); ok {
78+
nav.curr, c = p.OnEntering()
79+
cmds = append(cmds, c)
80+
}
81+
82+
return tea.Sequence(cmds...)
83+
}
84+
85+
// handlePopNavigation 处理页面弹出导航栈的操作
86+
func handlePopNavigation() tea.Cmd {
87+
88+
// 尝试弹出页面
89+
if nav.curr == nil {
90+
return postCmd(NoMorePageMsg{})
91+
}
92+
93+
if len(nav.histories) == 0 {
94+
return postCmd(NoMorePageMsg{})
95+
}
96+
97+
var (
98+
cmds []tea.Cmd
99+
c tea.Cmd
100+
)
101+
// 1. 处理旧页面的离开逻辑
102+
if p, ok := nav.curr.(PageLife); ok {
103+
_, c = p.OnLeaving()
104+
cmds = append(cmds, c)
105+
}
106+
107+
// 2. 处理新页面的进入逻辑
108+
nav.curr = nav.histories[len(nav.histories)-1]
109+
nav.histories = nav.histories[:len(nav.histories)-1]
110+
111+
if p, ok := nav.curr.(PageLife); ok {
112+
m, cmd := p.OnEntering()
113+
nav.curr = m
114+
cmds = append(cmds, cmd)
115+
}
116+
117+
return tea.Sequence(cmds...)
118+
}

0 commit comments

Comments
 (0)