交互式番茄钟应用开发指南
在开发交互式应用时,界面布局的组织和交互逻辑的构建是关键步骤。本文将详细介绍如何开发一个交互式番茄钟应用,包括界面布局的设计、交互逻辑的实现以及使用 Cobra 框架初始化命令行界面。
1. 组织界面布局
当你拥有界面所需的所有小部件后,需要对它们进行逻辑组织和布局,以构建用户界面。在 Termdash 中,你可以使用
container.Container
类型的容器来定义仪表盘布局。启动应用程序至少需要一个容器,你可以使用多个容器来分割屏幕并组织小部件。
创建容器有两种不同的方法:
- 使用
container
包分割容器,形成二叉树布局。
- 使用
grid
包定义行和列的网格。
对于本应用程序,我们将使用网格方法来组织布局,因为这样更容易组织代码以实现类似番茄钟应用屏幕的布局。应用程序布局由三个主要行组成:
- 第一行分为两列,每列再分为两行。
- 第二行有两列。
- 第三行也有两列。
目前,我们将构建前两行,将第三行留作后续设计的摘要小部件的占位符。
以下是具体的操作步骤:
1. 在应用程序目录的
app
子目录下添加并编辑
grid.go
文件,添加包定义和导入部分:
package app
import (
"github.com/mum4k/termdash/align"
"github.com/mum4k/termdash/container"
"github.com/mum4k/termdash/container/grid"
"github.com/mum4k/termdash/linestyle"
"github.com/mum4k/termdash/terminal/terminalapi"
)
-
定义
newGrid函数来定义新的网格布局:
func newGrid(b *buttonSet, w *widgets,
t terminalapi.Terminal) (*container.Container, error) {
builder := grid.New()
// 添加第一行
builder.Add(
grid.RowHeightPerc(30,
grid.ColWidthPercWithOpts(30,
[]container.Option{
container.Border(linestyle.Light),
container.BorderTitle("Press Q to Quit"),
},
grid.RowHeightPerc(80,
grid.Widget(w.donTimer)),
grid.RowHeightPercWithOpts(20,
[]container.Option{
container.AlignHorizontal(align.HorizontalCenter),
},
grid.Widget(w.txtTimer,
container.AlignHorizontal(align.HorizontalCenter),
container.AlignVertical(align.VerticalMiddle),
container.PaddingLeftPercent(49),
),
),
),
grid.ColWidthPerc(70,
grid.RowHeightPerc(80,
grid.Widget(w.disType, container.Border(linestyle.Light)),
),
grid.RowHeightPerc(20,
grid.Widget(w.txtInfo, container.Border(linestyle.Light)),
),
),
),
)
// 添加第二行
builder.Add(
grid.RowHeightPerc(10,
grid.ColWidthPerc(50,
grid.Widget(b.btStart),
),
grid.ColWidthPerc(50,
grid.Widget(b.btPause),
),
),
)
// 添加第三行
builder.Add(
grid.RowHeightPerc(60),
)
gridOpts, err := builder.Build()
if err != nil {
return nil, err
}
c, err := container.New(t, gridOpts...)
if err != nil {
return nil, err
}
return c, nil
}
2. 构建交互式界面
现在我们已经准备好了小部件和布局,接下来将所有内容组合在一起,创建一个启动和管理界面的应用程序。Termdash 提供了两种运行仪表盘应用程序的方式:
-
termdash.Run
:自动启动和管理应用程序,Termdash 会定期重绘屏幕并处理调整大小。
-
termdash.NewController
:创建一个新的
termdash.Controller
实例,允许你手动管理应用程序的重绘和调整大小过程。
对于番茄钟应用程序,我们将使用
termdash.Controller
实例来管理应用程序,因为
termdash.Run
会在应用程序停止或暂停时持续消耗系统资源。
以下是具体的操作步骤:
1. 确保你位于应用程序目录的
app
子目录下:
$ cd $HOME/pragprog.com/rggo/interactiveTools/pomo/app
-
创建并编辑
app.go文件,添加包定义和导入部分:
package app
import (
"context"
"image"
"time"
"github.com/mum4k/termdash"
"github.com/mum4k/termdash/terminal/tcell"
"github.com/mum4k/termdash/terminal/terminalapi"
"pragprog.com/rggo/interactiveTools/pomo/pomodoro"
)
type App struct {
ctx context.Context
controller *termdash.Controller
redrawCh chan bool
errorCh chan error
term *tcell.Terminal
size image.Point
}
func New(config *pomodoro.IntervalConfig) (*App, error) {
ctx, cancel := context.WithCancel(context.Background())
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {
cancel()
}
}
redrawCh := make(chan bool)
errorCh := make(chan error)
w, err := newWidgets(ctx, errorCh)
if err != nil {
return nil, err
}
b, err := newButtonSet(ctx, config, w, redrawCh, errorCh)
if err != nil {
return nil, err
}
term, err := tcell.New()
if err != nil {
return nil, err
}
c, err := newGrid(b, w, term)
if err != nil {
return nil, err
}
controller, err := termdash.NewController(term, c,
termdash.KeyboardSubscriber(quitter))
if err != nil {
return nil, err
}
return &App{
ctx: ctx,
controller: controller,
redrawCh: redrawCh,
errorCh: errorCh,
term: term,
}, nil
}
func (a *App) resize() error {
if a.size.Eq(a.term.Size()) {
return nil
}
a.size = a.term.Size()
if err := a.term.Clear(); err != nil {
return err
}
return a.controller.Redraw()
}
func (a *App) Run() error {
defer a.term.Close()
defer a.controller.Close()
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-a.redrawCh:
if err := a.controller.Redraw(); err != nil {
return err
}
case err := <-a.errorCh:
if err != nil {
return err
}
case <-a.ctx.Done():
return nil
case <-ticker.C:
if err := a.resize(); err != nil {
return err
}
}
}
}
3. 界面布局和交互逻辑流程图
graph TD;
A[开始] --> B[组织界面布局];
B --> C[构建交互式界面];
C --> D[初始化 CLI 界面];
D --> E[运行应用程序];
E --> F[结束];
4. 总结
通过以上步骤,我们完成了番茄钟应用程序的界面布局和交互逻辑的开发。接下来,我们将使用 Cobra 框架初始化命令行界面,以便用户可以通过命令行参数和配置文件来启动应用程序。
交互式番茄钟应用开发指南(续)
5. 初始化 CLI 界面
现在界面和后端代码都已准备就绪,需要一种方式来启动应用程序。我们将使用 Cobra 框架来处理命令行参数和配置文件。
以下是具体的操作步骤:
1. 切换回应用程序的根目录,并使用 Cobra 框架生成初始样板代码:
$ cd $HOME/pragprog.com/rggo/interactiveTools/pomo
$ cobra init --pkg-name pragprog.com/rggo/interactiveTools/pomo
-
在
go.mod中添加对 Cobra v1.1.3 的依赖,并下载所需的依赖项:
$ go mod edit --require github.com/spf13/cobra@v1.1.3
$ go mod tidy
-
在
cmd子目录下创建并编辑repoinmemory.go文件,添加包定义和导入部分,并定义getRepo函数:
package cmd
import (
"pragprog.com/rggo/interactiveTools/pomo/pomodoro"
"pragprog.com/rggo/interactiveTools/pomo/pomodoro/repository"
)
func getRepo() (pomodoro.Repository, error) {
return repository.NewInMemoryRepo(), nil
}
-
打开 Cobra 生成的
cmd/root.go文件,更新导入部分:
import (
"fmt"
"io"
"os"
"time"
"github.com/spf13/cobra"
"pragprog.com/rggo/interactiveTools/pomo/app"
"pragprog.com/rggo/interactiveTools/pomo/pomodoro"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)
-
编辑
init函数,添加三个命令行参数,允许用户自定义番茄钟、短休息和长休息的间隔时长:
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "",
"config file (default is $HOME/.pomo.yaml)")
rootCmd.Flags().DurationP("pomo", "p", 25*time.Minute,
"Pomodoro duration")
rootCmd.Flags().DurationP("short", "s", 5*time.Minute,
"Short break duration")
rootCmd.Flags().DurationP("long", "l", 15*time.Minute,
"Long break duration")
viper.BindPFlag("pomo", rootCmd.Flags().Lookup("pomo"))
viper.BindPFlag("short", rootCmd.Flags().Lookup("short"))
viper.BindPFlag("long", rootCmd.Flags().Lookup("long"))
}
-
更新
rootCmd命令定义,自定义命令描述,并添加RunE属性:
var rootCmd = &cobra.Command{
Use: "pomo",
Short: "Interactive Pomodoro Timer",
RunE: func (cmd *cobra.Command, args []string) error {
repo, err := getRepo()
if err != nil {
return err
}
config := pomodoro.NewConfig(
repo,
viper.GetDuration("pomo"),
viper.GetDuration("short"),
viper.GetDuration("long"),
)
return rootAction(os.Stdout, config)
},
}
-
定义
rootAction函数来启动应用程序:
func rootAction(out io.Writer, config *pomodoro.IntervalConfig) error {
a, err := app.New(config)
if err != nil {
return err
}
return a.Run()
}
6. 命令行参数和配置文件说明
| 参数 | 缩写 | 描述 | 默认值 |
|---|---|---|---|
| –config | 无 | 配置文件路径 | $HOME/.pomo.yaml |
| –pomo | -p | 番茄钟时长 | 25 分钟 |
| –short | -s | 短休息时长 | 5 分钟 |
| –long | -l | 长休息时长 | 15 分钟 |
用户可以通过命令行参数来临时修改这些值,也可以在配置文件(如
$HOME/.pomo.yaml
)中永久修改。例如,以下是一个配置文件示例:
pomo: 10m
short: 2m
long: 4m
7. 启动和测试应用程序
完成上述步骤后,我们可以构建并运行应用程序:
1. 切换回应用程序的根目录,使用
go build
构建应用程序:
$ cd $HOME/pragprog.com/rggo/interactiveTools/pomo
$ go build
- 运行应用程序:
$ ./pomo
-
若要查看所有选项,可以使用
--help参数:
$ ./pomo --help
8. 应用程序运行流程图
graph TD;
A[启动应用程序] --> B[解析命令行参数和配置文件];
B --> C[获取存储库];
C --> D[创建 Pomodoro 配置];
D --> E[创建 App 实例];
E --> F[运行 App];
F --> G[处理重绘和调整大小];
G --> H[等待用户输入];
H --> I{是否退出};
I -- 是 --> J[关闭应用程序];
I -- 否 --> G;
9. 总结
通过以上步骤,我们完成了交互式番茄钟应用程序的开发,包括界面布局、交互逻辑和命令行界面的初始化。用户可以通过命令行参数和配置文件来定制番茄钟、短休息和长休息的间隔时长。由于使用了内存存储库,每次启动应用程序时,间隔都会重置为番茄钟间隔。后续可以将历史记录保存到 SQL 数据库中,以进一步提升应用程序的功能。同时,用户可以通过调整终端窗口大小来测试应用程序的调整大小功能,应用程序会相应地进行调整。
超级会员免费看
25

被折叠的 条评论
为什么被折叠?



