昨天我們依照JSON把Flex Message刻了出來,真心覺得應該可以有一個Generate Code的工具,把用Flex Message Simulator產生出來的JSON轉成對應的程式碼,這樣開發應該可以方便很多QQ。
言歸正傳,雖然昨天刻好了Flex Message的程式碼,但是各個欄位顯示什麼都還是寫死的,我們今天就來把各個區塊調整&封裝一下,讓我們能更有彈性&動態的組合出需要的Flex Message。
首先我們把組合的工作移到Domain層來處理,在domain/drive下新增flex.go
接著我們仔細看一下圖片,來拆解&分析一下我們Flex Message的格式
根據上面的分析,我們可以先寫出要組成bubble會需要的4個區塊,讓他們都回傳[]linebot.FlexComponent,等等再組起來就好。
// internal\domain\drive\flex.go
// Title區塊
func folderTitleFlexComponents(folderType string, name string, path string) []linebot.FlexComponent {}
// Folder區塊,folderM是 map[folderID]:folderName
func folderFlexComponents(folderM map[string]string) []linebot.FlexComponent {}
// Files區塊,fileM 是 map[fileID]:fileName
func fileFlexComponents(fileM map[string]string) []linebot.FlexComponent {}
// Button區塊,讓他能回傳當前資料夾ID
func buttonFlexComponents(currentFolderID string) []linebot.FlexComponent {}
接著我們來一一實現,從Title區塊開始,這邊比較單純,只要讓外部傳入的參數對應到Text的部分就好。
func folderTitleFlexComponents(folderType string, name string, path string) []linebot.FlexComponent {
	var title []linebot.FlexComponent
	title = append(title,
		&linebot.TextComponent{
			Type:   linebot.FlexComponentTypeText,
			Text:   folderType,
			Weight: linebot.FlexTextWeightTypeBold,
			Color:  "#1DB446",
			Size:   linebot.FlexTextSizeTypeSm,
		},
		&linebot.TextComponent{
			Type:   linebot.FlexComponentTypeText,
			Text:   name,
			Weight: linebot.FlexTextWeightTypeBold,
			Size:   linebot.FlexTextSizeTypeXxl,
			Margin: linebot.FlexComponentMarginTypeMd,
		},
		&linebot.TextComponent{
			Type:  linebot.FlexComponentTypeText,
			Text:  path,
			Size:  linebot.FlexTextSizeTypeXs,
			Color: "#aaaaaa",
			Wrap:  true,
		},
		&linebot.SeparatorComponent{
			Type:   linebot.FlexComponentTypeSeparator,
			Margin: linebot.FlexComponentMarginTypeXxl,
		})
	return title
}
Folder區塊,我們假設傳入一個folderM是子資料夾的ID與名稱對應的Map,如果map為空代表該資料夾下,沒有其他的子資料夾,我們就做一個”無”的TextComponent回傳。
如果map不為空,我們要遍歷整個folderM,取出folderID跟folderName來製作每顯示一行需要的三個對應的元件(Text+Filler+Button)。
folderID,並且用action來代表對資料夾執行的動作。func folderFlexComponents(folderM map[string]string) []linebot.FlexComponent {
	var folders []linebot.FlexComponent
	var folderFlex []linebot.FlexComponent
	// map為空
	if len(folderM) == 0 {
		folderFlex = append(folderFlex,
			&linebot.BoxComponent{
				Type:    linebot.FlexComponentTypeBox,
				Layout:  linebot.FlexBoxLayoutTypeVertical,
				Margin:  linebot.FlexComponentMarginTypeXxl,
				Spacing: linebot.FlexComponentSpacingTypeSm,
				Contents: []linebot.FlexComponent{
					&linebot.TextComponent{
						Type:       linebot.FlexComponentTypeText,
						Text:       "無",
						Size:       linebot.FlexTextSizeTypeSm,
						Color:      "#555555",
						Decoration: linebot.FlexTextDecorationTypeNone,
						MaxLines:   linebot.IntPtr(25),
						Align:      linebot.FlexComponentAlignTypeStart,
						Margin:     linebot.FlexComponentMarginTypeNone,
						Gravity:    linebot.FlexComponentGravityTypeCenter,
						Flex:       linebot.IntPtr(0),
					},
				},
			},
			// Separator
			&linebot.SeparatorComponent{
				Margin: linebot.FlexComponentMarginTypeXxl,
			},
		)
		return folderFlex
	}
// map不為空
	for folderID, folderName := range folderM {
		folders = append(folders, &linebot.BoxComponent{
			Type:   linebot.FlexComponentTypeBox,
			Layout: linebot.FlexBoxLayoutTypeHorizontal,
			Contents: []linebot.FlexComponent{
				&linebot.TextComponent{
					Type:       linebot.FlexComponentTypeText,
					Text:       folderName,
					Size:       linebot.FlexTextSizeTypeSm,
					Color:      "#555555",
					Decoration: linebot.FlexTextDecorationTypeUnderline,
					MaxLines:   linebot.IntPtr(25),
					Align:      linebot.FlexComponentAlignTypeStart,
					Margin:     linebot.FlexComponentMarginTypeNone,
					Gravity:    linebot.FlexComponentGravityTypeCenter,
					Flex:       linebot.IntPtr(0),
				},
				&linebot.FillerComponent{
					Type: linebot.FlexComponentTypeFiller,
				},
				&linebot.ButtonComponent{
					Type: linebot.FlexComponentTypeButton,
					Action: &linebot.PostbackAction{
						Label:       "進入資料夾",
						Data:        "action=openFolder&folderID=" + folderID,
						DisplayText: "進入" + folderName,
					},
					Style:      linebot.FlexButtonStyleTypeLink,
					Height:     linebot.FlexButtonHeightTypeSm,
					Gravity:    linebot.FlexComponentGravityTypeCenter,
					Flex:       linebot.IntPtr(0),
					AdjustMode: linebot.FlexComponentAdjustModeTypeShrinkToFit,
				},
			},
		})
	}
	folderFlex = append(folderFlex,
		&linebot.BoxComponent{
			Type:     linebot.FlexComponentTypeBox,
			Layout:   linebot.FlexBoxLayoutTypeVertical,
			Margin:   linebot.FlexComponentMarginTypeXxl,
			Spacing:  linebot.FlexComponentSpacingTypeSm,
			Contents: folders,
		},
		// Separator
		&linebot.SeparatorComponent{
			Margin: linebot.FlexComponentMarginTypeXxl,
		},
	)
	return folderFlex
}
Files區塊,跟folderM做法一樣,只是傳入的是檔案ID與名稱組合的Map。透過len(fileM)來製作Total Files的部分,然後一樣遍歷fileM用每一個取到的檔案名稱製作對應的TextComponent。
func fileFlexComponents(fileM map[string]string) []linebot.FlexComponent {
	totalFiles := len(fileM)
	fileFlex := []linebot.FlexComponent{
		&linebot.BoxComponent{
			Type:   linebot.FlexComponentTypeBox,
			Layout: linebot.FlexBoxLayoutTypeHorizontal,
			Margin: linebot.FlexComponentMarginTypeXxl,
			Contents: []linebot.FlexComponent{
				&linebot.TextComponent{
					Type:  linebot.FlexComponentTypeText,
					Text:  "Total Files",
					Size:  linebot.FlexTextSizeTypeSm,
					Color: "#555555",
					Flex:  linebot.IntPtr(0),
				},
				&linebot.TextComponent{
					Type: linebot.FlexComponentTypeText,
					// Insert totalFiles
					Text:  strconv.Itoa(totalFiles),
					Size:  linebot.FlexTextSizeTypeSm,
					Color: "#111111",
					Align: linebot.FlexComponentAlignTypeEnd,
				},
			},
		},
	}
	// Generate files
	var files []linebot.FlexComponent
	for _, name := range fileM {
		files = append(files,
			&linebot.TextComponent{
				Type:  linebot.FlexComponentTypeText,
				Text:  name,
				Size:  linebot.FlexTextSizeTypeSm,
				Color: "#555555",
			},
		)
	}
	fileFlex = append(fileFlex, files...)
	// Add Separator
	fileFlex = append(fileFlex,
		&linebot.SeparatorComponent{
			Margin: linebot.FlexComponentMarginTypeXxl,
		},
	)
	return fileFlex
}
Button區塊,這邊我們將action=setFolder,代表設定當前資料夾為上傳資料夾。之後再處理Button的PostbackAction時,我們也是靠action帶的動作,來認定是哪個按鈕被按下,並進行對應的後續處理。
func buttonFlexComponents(currentFolderID string) []linebot.FlexComponent {
	var buttonFlex []linebot.FlexComponent
	buttonFlex = append(buttonFlex,
		// Button
		&linebot.BoxComponent{
			Type:   linebot.FlexComponentTypeBox,
			Layout: linebot.FlexBoxLayoutTypeHorizontal,
			Margin: linebot.FlexComponentMarginTypeMd,
			Contents: []linebot.FlexComponent{
				&linebot.ButtonComponent{
					Type: linebot.FlexComponentTypeButton,
					Action: &linebot.PostbackAction{
						Label:       "設為上傳資料夾",
						Data:        "action=setFolder&folderID=" + currentFolderID,
						DisplayText: "設為上傳資料夾",
					},
					Style:      linebot.FlexButtonStyleTypePrimary,
					AdjustMode: linebot.FlexComponentAdjustModeTypeShrinkToFit,
				},
			},
		})
	return buttonFlex
}
到這裡我們完成了組成單一個Bubble需要的4個區塊,那我們今天就先寫到這,明天透過這4個區塊,把Bubble跟Carousel組合起來,就可以提供給Service調用了,那我們明天見囉~