Browse Source

add warehouse code,pass 1st complie,app_notifier needs installation function

cuu 2 years ago
parent
commit
94245a58e8

+ 2 - 0
Menu/GameShell/10_Settings/Settings.go

@@ -30,6 +30,8 @@ import (
 	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/10_Settings/TimeZone"
 	//"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/10_Settings/Lima"
 	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/10_Settings/GateWay"
+
+		
 )
 
 type SettingsPageSelector struct {

+ 47 - 0
Menu/GameShell/21_Warehouse/app_notifier.go

@@ -0,0 +1,47 @@
+package Warehouse
+
+import(
+	"log"
+	//"os"
+	"github.com/zyxar/argo/rpc"
+	
+)
+
+
+
+type AppNotifier struct {
+	Parent *WareHouse
+}
+
+func (self AppNotifier) OnDownloadStart(events []rpc.Event) {
+	log.Printf("warehouse %s started.", events)
+}
+
+func (self AppNotifier) OnDownloadPause(events []rpc.Event){
+	log.Printf("warehouse %s paused.", events)
+}
+
+func (self AppNotifier) OnDownloadStop(events []rpc.Event){
+	log.Printf("warehouse %s stopped.", events)
+}
+
+
+func (self AppNotifier) OnDownloadComplete(events []rpc.Event){
+	
+	log.Printf("warehouse %s complete",events)
+	for _,v := range events {
+		self.Parent.OnAria2CompleteCb(v.Gid)
+	}
+}
+
+
+func (self AppNotifier) OnDownloadError(events []rpc.Event) { 
+	log.Printf("warehouse %s error.", events) 
+}
+
+func (self AppNotifier) OnBtDownloadComplete(events []rpc.Event) { 
+	
+	log.Printf("warehouse bt %s completed.", events) 
+
+}
+

+ 2 - 2
Menu/GameShell/21_Warehouse/aria2_download_process_page.go

@@ -24,7 +24,7 @@ type Aria2DownloadProcessPage struct {
 
 func NewAria2DownloadProcessPage() *Aria2DownloadProcessPage {
 	p := &Aria2DownloadProcessPage{}
-	p.Icons = make(map[string]UI.IconItemInterfac)
+	p.Icons = make(map[string]UI.IconItemInterface)
 	
 	p.URLColor = UI.MySkinManager.GiveColor("URL")
 	p.TextColor = UI.MySkinManager.GiveColor("Text")
@@ -42,7 +42,7 @@ func (self *Aria2DownloadProcessPage) Init() {
 	self.CanvasHWND = self.Screen.CanvasHWND
 
 	bgpng := UI.NewIconItem()
-	bgpng.ImgSurf = UI.MyIconPool.GiveIconSurface("rom_download")
+	bgpng.ImgSurf = UI.MyIconPool.GetImgSurf("rom_download")
 	bgpng.MyType = UI.ICON_TYPES["STAT"]
 	bgpng.Parent = self
 	bgpng.Adjust(0,0,UI.MyIconPool.Width("rom_download"),UI.MyIconPool.Height("rom_download"),0)

+ 29 - 18
Menu/GameShell/21_Warehouse/image_download_process_page.go

@@ -4,13 +4,21 @@ import (
 	"fmt"
 	"os"
 	gotime "time"
-	"encoding/json"
+	"strings"
+	"path"
+	
+	//"encoding/json"
 
 	"github.com/veandco/go-sdl2/ttf"
+	"github.com/veandco/go-sdl2/sdl"
+	
 	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
 	"github.com/cuu/gogame/image"
 	"github.com/cuu/gogame/draw"
 	"github.com/cuu/gogame/color"
+	"github.com/cuu/gogame/event"
+	"github.com/cuu/gogame/surface"
+
 	"github.com/cuu/grab"
 )
 
@@ -32,7 +40,7 @@ type ImageDownloadProcessPage struct {
 	req        *grab.Request
 	URL        string
 	Value      int
-	LoadingLabel *UI.LabelInterface
+	LoadingLabel UI.LabelInterface
 
 	Img        *sdl.Surface
 	Downloading chan bool
@@ -57,11 +65,12 @@ func (self *ImageDownloadProcessPage) Init() {
 	self.Height = self.Screen.Height
 
 	self.CanvasHWND = self.Screen.CanvasHWND
-	self.LoadingLabel = UI.NewLabel()
-	self.LoadingLabel.SetCanvasHWND(self.CanvasHWND)
-	self.LoadingLabel.Init("Loading",self.ListFontObj,nil)
-	self.LoadingLabel.SetColor(self.TextColor)
-
+	LoadingLabel := UI.NewLabel()
+	LoadingLabel.SetCanvasHWND(self.CanvasHWND)
+	LoadingLabel.Init("Loading",self.ListFontObj,nil)
+	LoadingLabel.SetColor(self.TextColor)
+	self.LoadingLabel = LoadingLabel
+	
 	self.Downloader = grab.NewClient()
 	self.Downloading = make(chan bool)
 }
@@ -77,8 +86,8 @@ func (self *ImageDownloadProcessPage) OnLoadCb() {
 	self.Screen.Draw()
 	self.Screen.SwapAndShow()
 
-	parts := strings.Split(self.URL,"/")
-	filename := strings.TrimSpace(parts[len(parts)-1])
+	//parts := strings.Split(self.URL,"/")
+	//filename := strings.TrimSpace(parts[len(parts)-1])
 	local_dir := strings.Split(self.URL,"raw.githubusercontent.com")
 	home_path, _ := os.UserHomeDir()
 	
@@ -108,7 +117,7 @@ func (self *ImageDownloadProcessPage) OnLoadCb() {
 
 func (self *ImageDownloadProcessPage) UpdateProcessInterval(ms int) {
 	
-	t := gotime.NewTicker(ms * time.Millisecond)
+	t := gotime.NewTicker(gotime.Duration(ms) * gotime.Millisecond)
 	defer t.Stop()
 
 	for {
@@ -122,7 +131,7 @@ func (self *ImageDownloadProcessPage) UpdateProcessInterval(ms int) {
 		case <-self.resp.Done:
 			// download is complete
 			break
-		case v:= <-self.Downloading
+		case v:= <-self.Downloading:
 			if v == false {
 				t.Stop()
 				break
@@ -148,8 +157,8 @@ func (self *ImageDownloadProcessPage) UpdateProcessInterval(ms int) {
 		}
 
 		dl_file := path.Join("/tmp",filename)
-		if UI.IsDirectory( Path.Base(local_menu_file) ) == false {
-			merr := os.MkdirAll( Path.Base(local_menu_file), os.ModePerm)
+		if UI.IsDirectory( path.Base(local_menu_file) ) == false {
+			merr := os.MkdirAll( path.Base(local_menu_file), os.ModePerm)
 			if merr != nil {
 				panic(merr)
 			}
@@ -173,7 +182,7 @@ func (self *ImageDownloadProcessPage) UpdateProcessInterval(ms int) {
 
 func (self *ImageDownloadProcessPage) KeyDown(ev  *event.Event) {
 
-	if IsKeyMenuOrB(ev.Data["Key")) {
+	if UI.IsKeyMenuOrB(ev.Data["Key"]) {
 
 		self.Downloading <- false
 
@@ -186,12 +195,14 @@ func (self *ImageDownloadProcessPage) KeyDown(ev  *event.Event) {
 
 func (self *ImageDownloadProcessPage) Draw() {
 	self.ClearCanvas()
-	self.LoadingLabel.NewCoord( (UI.Width - self.LoadingLabel.Width)/2,(UI.Height-44)/2);
+	w,_ := self.LoadingLabel.Size()
+	self.LoadingLabel.NewCoord( (UI.Width - w)/2,(UI.Height-44)/2);
 	self.LoadingLabel.Draw()
 	if self.Img != nil {
-		self.CanvasHWND.Blit(self.Img,draw.MidRect(UI.Width/2,(UI.Height-44)/2,
-			self.Img.Width,self.Img.Height,
-			UI.Width,UI.Height-44))
+		surface.Blit(self.CanvasHWND,
+			self.Img,
+			draw.MidRect(UI.Width/2,(UI.Height-44)/2,int(self.Img.W),int(self.Img.H),UI.Width,UI.Height-44),
+			nil)
 	}
 }
 

+ 33 - 14
Menu/GameShell/21_Warehouse/load_house_page.go

@@ -3,14 +3,18 @@ package Warehouse
 import (
 	"fmt"
 	"os"
+	"io/ioutil"
 	gotime "time"
+	"strings"
 	"encoding/json"
+	"path"
 	
 	"github.com/veandco/go-sdl2/ttf"
 	
-	"github.com/cuu/gogame/image"
-	"github.com/cuu/gogame/draw"
+	//"github.com/cuu/gogame/image"
+	//"github.com/cuu/gogame/draw"
 	"github.com/cuu/gogame/color"
+	"github.com/cuu/gogame/event"
 	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
 	"github.com/cuu/grab"
 )
@@ -27,7 +31,7 @@ type LoadHousePage struct {
 	
 	URL  string
 	Downloading chan bool
-	LoadingLabel *UI.LabelInterface
+	LoadingLabel UI.LabelInterface
 
 	Parent *WareHouse
 }
@@ -69,8 +73,8 @@ func (self *LoadHousePage) OnLoadCb() {
 	self.Screen.Draw()
 	self.Screen.SwapAndShow()
 
-	parts := strings.Split(self.URL,"/")
-	filename := strings.TrimSpace(parts[len(parts)-1])
+	//parts := strings.Split(self.URL,"/")
+	//filename := strings.TrimSpace(parts[len(parts)-1])
 	local_dir := strings.Split(self.URL,"raw.githubusercontent.com")
 	home_path, _ := os.UserHomeDir()
 	
@@ -88,7 +92,7 @@ func (self *LoadHousePage) OnLoadCb() {
 			}
 			defer jsonFile.Close()
 			byteValue, _ := ioutil.ReadAll(jsonFile)
-			json.Unmarshal([]byte(JSON), &result)
+			json.Unmarshal(byteValue, &result)
 			
 			for _, repo := range result.List {
 				self.Parent.MyStack.Push(repo)
@@ -98,7 +102,7 @@ func (self *LoadHousePage) OnLoadCb() {
 		} else {
 			self.req,_ = grab.NewRequest("/tmp",self.URL)
 			self.resp = self.Downloader.Do(self.req)
-
+	
 			for len(self.Downloading) > 0 {
 				<-self.Downloading
 			}
@@ -111,7 +115,7 @@ func (self *LoadHousePage) OnLoadCb() {
 }
 
 func (self *LoadHousePage) UpdateProcessInterval(ms int) {
-	t := gotime.NewTicker(ms * time.Millisecond)
+	t := gotime.NewTicker(gotime.Duration(ms) * gotime.Millisecond)
 	defer t.Stop()
 
 	for {
@@ -125,7 +129,7 @@ func (self *LoadHousePage) UpdateProcessInterval(ms int) {
 		case <-self.resp.Done:
 			// download is complete
 			break
-		case v:= <-self.Downloading
+		case v:= <-self.Downloading:
 			if v == false {
 				t.Stop()
 				break
@@ -133,7 +137,7 @@ func (self *LoadHousePage) UpdateProcessInterval(ms int) {
 		}		
 	}
 	
-	dst_filename := self.resp.Filename
+	//dst_filename := self.resp.Filename
 
 	if err := self.resp.Err(); err == nil {//download successfully
 		home_path, _ := os.UserHomeDir()
@@ -150,8 +154,8 @@ func (self *LoadHousePage) UpdateProcessInterval(ms int) {
 				home_path,menu_file)
 		}
 		dl_file := path.Join("/tmp",filename)
-		if UI.IsDirectory( Path.Base(local_menu_file) ) == false {
-			merr := os.MkdirAll( Path.Base(local_menu_file), os.ModePerm)
+		if UI.IsDirectory( path.Base(local_menu_file) ) == false {
+			merr := os.MkdirAll( path.Base(local_menu_file), os.ModePerm)
 			if merr != nil {
 				panic(merr)
 			}
@@ -166,7 +170,7 @@ func (self *LoadHousePage) UpdateProcessInterval(ms int) {
 		}
 		defer jsonFile.Close()
 		byteValue, _ := ioutil.ReadAll(jsonFile)
-		json.Unmarshal([]byte(JSON), &result)
+		json.Unmarshal(byteValue, &result)
 		
 		for _, repo := range result.List {
 			self.Parent.MyStack.Push(repo)
@@ -184,7 +188,7 @@ func (self *LoadHousePage) UpdateProcessInterval(ms int) {
 
 func (self *LoadHousePage) Leave() {
 
-	self.Download <- false
+	self.Downloading <- false
 	
 	self.ReturnToUpLevelPage()
 	self.Screen.Draw()
@@ -192,3 +196,18 @@ func (self *LoadHousePage) Leave() {
 	self.URL = ""
 	
 }
+
+func (self *LoadHousePage) KeyDown(ev *event.Event) {
+	if UI.IsKeyMenuOrB(ev.Data["Key"]) {
+		self.Leave()
+	}
+	
+}
+
+func (self *LoadHousePage) Draw() {
+	self.ClearCanvas()
+	w,_ := self.LoadingLabel.Size()
+	self.LoadingLabel.NewCoord( (UI.Width - w)/2,(UI.Height-44)/2);
+	self.LoadingLabel.Draw()
+	
+}

+ 2 - 2
Menu/GameShell/21_Warehouse/plugin_init.go

@@ -16,11 +16,11 @@ import (
 /******************************************************************************/
 type WareHousePlugin struct {
 	UI.Plugin
-	MainPage *WareHousePage
+	MainPage *WareHouse
 }
 
 func (self *WareHousePlugin) Init(main_screen *UI.MainScreen) {
-	self.MainPage = NewWareHousePage()
+	self.MainPage = NewWareHouse()
 	self.MainPage.SetScreen(main_screen)
 	self.MainPage.SetName("Tiny cloud")
 	self.MainPage.Init()

+ 33 - 26
Menu/GameShell/21_Warehouse/ware_house_list_item.go

@@ -1,20 +1,22 @@
 package Warehouse
 
 import (
+	"github.com/veandco/go-sdl2/ttf"
+	"github.com/cuu/gogame/draw"
 	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
 
 )
 
 //GameStoreListItem in py 
 type WareHouseListItem struct {
-    UI.InfoPageListItem
-
-    Type  string
+	UI.InfoPageListItem
+	
+	Type  string
+	Value map[string]string
+	Parent *WareHouse
+	
 }
 
-
-
-
 func NewWareHouseListItem() *WareHouseListItem {
 
 	p := &WareHouseListItem{}
@@ -32,33 +34,33 @@ func (self *WareHouseListItem) Init( text string) {
 	l := UI.NewLabel()
 	l.CanvasHWND = self.Parent.GetCanvasHWND()
 	l.PosX = 10
-	l.Init(text,self.Fonts["normal"])
+	l.Init(text,self.Fonts["normal"],nil)
 
 	self.Labels["text"] = l
 
-	add_icon := NewIconItem()
+	add_icon := UI.NewIconItem()
 	add_icon.ImgSurf = UI.MyIconPool.GetImgSurf("add")
-	add_icon.Parent = self
+	add_icon.Parent = self.Parent
 	add_icon.Init(0,0,UI.MyIconPool.Width("add"),UI.MyIconPool.Height("add"),0)
 
-	ware_icon := NewIconItem()
+	ware_icon := UI.NewIconItem()
 	ware_icon.ImgSurf = UI.MyIconPool.GetImgSurf("ware")
-	ware_icon.Parent = self
+	ware_icon.Parent = self.Parent
 	ware_icon.Init(0,0,UI.MyIconPool.Width("ware"),UI.MyIconPool.Height("ware"),0)
 
-	app_icon := NewIconItem()
+	app_icon := UI.NewIconItem()
 	app_icon.ImgSurf = UI.MyIconPool.GetImgSurf("app")
-	app_icon.Parent = self
+	app_icon.Parent = self.Parent
 	app_icon.Init(0,0,UI.MyIconPool.Width("app"),UI.MyIconPool.Height("app"),0)
 
-	appdling_icon := NewIconItem()
+	appdling_icon := UI.NewIconItem()
 	appdling_icon.ImgSurf = UI.MyIconPool.GetImgSurf("appdling")
-	appdling_icon.Parent = self
+	appdling_icon.Parent = self.Parent
 	appdling_icon.Init(0,0,UI.MyIconPool.Width("appdling"),UI.MyIconPool.Height("appdling"),0)
 
-	blackheart_icon := NewIconItem()
+	blackheart_icon := UI.NewIconItem()
 	blackheart_icon.ImgSurf = UI.MyIconPool.GetImgSurf("blackheart")
-	blackheart_icon.Parent = self
+	blackheart_icon.Parent = self.Parent
 	blackheart_icon.Init(0,0,UI.MyIconPool.Width("blackheart"),UI.MyIconPool.Height("blackheart"),0)
 
 	self.Icons["add"] = add_icon
@@ -83,32 +85,37 @@ func (self *WareHouseListItem) Draw() {
 	}
 
 	if self.Type == "source" || self.Type == "dir" {
-		self.Icons["ware"].NewCoord(4,(self.Height - self.Icons["ware"].Height)/2)
+		_,h := self.Icons["ware"].Size()
+		self.Icons["ware"].NewCoord(4,(self.Height - h)/2)
 		self.Icons["ware"].DrawTopLeft()
 	}
 
 	if self.Type == "launcher" || self.Type == "pico8" || self.Type == "tic80" {
-		_icon :=  app
+		_icon :=  "app"
 		if self.ReadOnly == true {
 			_icon = "appdling"
 		}
-		self.Icons[_icon].NewCoord(4,(self.Height - self.Icons[_icon].Height)/2)
+		_,h := self.Icons[_icon].Size()
+		self.Icons[_icon].NewCoord(4,(self.Height - h )/2)
 		self.Icons[_icon].DrawTopLeft()
 	}
 
 	if self.Type == "add_house" {
-		self.Icons["add"].NewCoord(4,(self.Height-self.Icons["add"].Height)/2)
+		_,h := self.Icons["add"].Size()
+		self.Icons["add"].NewCoord(4,(self.Height - h)/2)
 		self.Icons["add"].DrawTopLeft()
 	}
-	
-	self.Labels["text"].PosX = self.Labels["text"].PosX + self.PosX + padding
-	self.Labels["text"].PosY = self.PosY + (self.Height-self.Labels["text"].Height)/2
+
+	x,_ := self.Labels["text"].Coord()
+	_,h := self.Labels["text"].Size()
+	self.Labels["text"].NewCoord(x + self.PosX + padding, self.PosY + (self.Height-h)/2)
 	self.Labels["text"].Draw()
-	self.Labels["text"].PosX = self.Labels["text"].PosX - self.PosX - padding
+	x,y := self.Labels["text"].Coord()
+	self.Labels["text"].NewCoord( x - self.PosX - padding, y)
 	
 	if _, ok := self.Labels["Small"]; ok {
 		x, _ = self.Labels["Small"].Coord()
-		w, h = self.Labels["Small"].Size()
+		w, h := self.Labels["Small"].Size()
 
 		self.Labels["Small"].NewCoord(self.Width-w-5, self.PosY+(self.Height-h)/2)
 		self.Labels["Small"].Draw()	

+ 699 - 17
Menu/GameShell/21_Warehouse/ware_house_page.go

@@ -1,12 +1,31 @@
 package Warehouse
 
 import (
+	"context"
 	"fmt"
 	"log"
-	
+	gotime "time"
+	"strconv"
+	"strings"
+	"os"
+	"io/ioutil"
+	"path/filepath"
+	"encoding/json"
 	"database/sql"
 	_ "github.com/mattn/go-sqlite3"
 	
+	"github.com/zyxar/argo/rpc"
+
+	//"github.com/veandco/go-sdl2/sdl"
+	"github.com/veandco/go-sdl2/ttf"
+	"github.com/cuu/gogame/surface"
+	"github.com/cuu/gogame/time"
+	"github.com/cuu/gogame/event"
+	"github.com/cuu/gogame/rect"
+	
+	"github.com/cuu/grab"
+	"github.com/clockworkpi/LauncherGoDev/sysgo"
+	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
 )
 
 type WareHouse struct {
@@ -15,6 +34,7 @@ type WareHouse struct {
 
 	ListFontObj15 *ttf.Font
 	ListFontObj12 *ttf.Font
+	Icons  map[string]UI.IconItemInterface
 	
 	BGwidth     int
 	BGheight    int
@@ -22,9 +42,27 @@ type WareHouse struct {
 	Scroller    *UI.ListScroller
 	RemovePage *UI.YesCancelConfirmPage
 	Keyboard   *UI.Keyboard
-	
+	PreviewPage *ImageDownloadProcessPage
+	LoadHousePage *LoadHousePage
+
 	WareHouseDB string
 	MyStack  *WareHouseStack
+	
+	rpcc               rpc.Client
+	rpcSecret          string
+	rpcURI             string
+
+	Aria2DownloadingGid     string // the Downloading Gid of aria2c
+	
+	Downloading  chan bool        
+
+	Downloader *grab.Client
+	resp       *grab.Response
+	req        *grab.Request
+
+	RefreshTicker *gotime.Ticker
+	ScrolledCnt   int
+	
 }
 
 func NewWareHouse() *WareHouse {
@@ -32,12 +70,13 @@ func NewWareHouse() *WareHouse {
 	p := &WareHouse{}
 	p.ListFontObj12 = UI.MyLangManager.TrFont("notosanscjk12")
 	p.ListFontObj15 = UI.MyLangManager.TrFont("varela15")
-
+	p.Icons = make(map[string]UI.IconItemInterface)
+	
 	p.FootMsg = [5]string{"Nav","Update","Up","Back","Select"}
 
 	p.WareHouseDB = "foo.db"
 
-	p.BGWidth = 320
+	p.BGwidth = 320
 	p.BGheight = 240-24-20
 	
 	p.MyStack = NewWareHouseStack()
@@ -48,25 +87,70 @@ func NewWareHouse() *WareHouse {
 	repo["type"]  = "source"
 
 	p.MyStack.Push(repo)
+
+	p.rpcURI = sysgo.Aria2Url
 	
 	return p
 }
 
-func (self*WareHouse) UpdateProcessInterval(ms int) {
-	dirty := false
+func (self *WareHouse) GetAria2DownloadingPercent(url string) int {
 	
+	if resp,err := self.rpcc.TellActive();err == nil {
+		for _,v := range resp {
+			if uris,err := self.rpcc.GetURIs(v.Gid); err == nil {
+				for _,x := range uris {
+					if x.URI == url {
+						comp_len,_ := strconv.ParseInt(v.CompletedLength,10,64)
+						totl_len,_ := strconv.ParseInt(v.TotalLength,10,64)
+						pct := float64(comp_len)/float64(totl_len)
+						pct = pct * 100.0
+						return int(pct)
+					}
+				}	
+			}
+		}
+	}
+	return -1;///None
 }
+func (self *WareHouse) UpdateProcessInterval(ms int) {
+	dirty := false
+	for {
+		select {
+		case <- self.RefreshTicker.C:
+			for _,i := range self.MyList {
+				x := i.(*WareHouseListItem)
+				if x.Type == "launcher" || x.Type == "pico8" || x.Type == "tic80" {
+					percent := self.GetAria2DownloadingPercent(x.Value["file"])
+					if percent < 0 {
+						x.SetSmallText("")
+					}else {
+						x.SetSmallText(fmt.Sprintf("%d%%",percent))
+						dirty = true
+					}
+				}
+			}
+
+			if self.Screen.CurPage() == self && dirty == true {
+				self.Screen.Draw()
+				self.Screen.SwapAndShow()
+			}
+			dirty = false
+		}
+	}
+}
+
 
 func (self *WareHouse) SyncWareHouse() []map[string]string {
 	db, err := sql.Open("sqlite3", self.WareHouseDB)
 	if err != nil {
 		log.Fatal(err)
+		return nil
 	}
 	defer db.Close()
 
 	
 	//id,title,file,type
-	rows, err = db.Query("select * from warehouse")
+	rows, err := db.Query("select * from warehouse")
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -85,7 +169,7 @@ func (self *WareHouse) SyncWareHouse() []map[string]string {
 			log.Fatal(err)
 		}
 
-		w_dbt := m = make(map[string]string)
+		w_dbt :=  make(map[string]string)
 		w_dbt["title"] = title
 		w_dbt["file"]  = file
 		w_dbt["type"] = type_
@@ -99,12 +183,13 @@ func (self *WareHouse) SyncTasks() []map[string]string {
 	db, err := sql.Open("sqlite3", self.WareHouseDB)
 	if err != nil {
 		log.Fatal(err)
+		return nil
 	}
 	defer db.Close()
 
 	
 	//id,gid,title,file,type,status,totalLength,completedLength,fav
-	rows, err = db.Query("select * from tasks")
+	rows, err := db.Query("select * from tasks")
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -158,7 +243,7 @@ func (self *WareHouse) SyncList()  {
 	stk := self.MyStack.Last()
 	stk_len := self.MyStack.Length()
 
-	repos = append(repos, stk)
+	repos = append(repos, stk.(map[string]string))
 	
 	add_new_house := make(map[string]string)
 	add_new_house["title"]  = "Add new warehouse..."
@@ -180,8 +265,8 @@ func (self *WareHouse) SyncList()  {
 		repos = append(repos,add_new_house)
 	}
 
-	for i, u := range repos {
-		li := WareHouseListItem{}
+	for _, u := range repos {
+		li := &WareHouseListItem{}
 		li.Parent = self
 		li.PosX = start_x
 		li.PosY = start_y + last_height
@@ -190,7 +275,8 @@ func (self *WareHouse) SyncList()  {
 		li.Fonts["small"] = self.ListFontObj12
 		li.ReadOnly = true
 		li.Type = u["type"]
-		li.init(u["title"])
+		li.Value = u
+		li.Init(u["title"])
 
 		if stk_len > 1 {
 			remote_file_url := u["file"]
@@ -240,8 +326,8 @@ func (self *WareHouse) Init()  {
 		self.Width = self.Screen.Width //equal to screen width
 		self.Height = self.Screen.Height
 
-		done := NewIconItem()
-		done.ImgSurf = UI.MyIconPool.GetImgSurf()
+		done := UI.NewIconItem()
+		done.ImgSurf = UI.MyIconPool.GetImgSurf("done")
 		done.MyType = UI.ICON_TYPES["STAT"]
 		done.Parent = self
 
@@ -252,8 +338,6 @@ func (self *WareHouse) Init()  {
 		self.Ps = ps
 		self.PsIndex = 0
 
-		self.SyncList()
-
 		self.Scroller = UI.NewListScroller()
 		self.Scroller.Parent = self
 		self.Scroller.PosX = self.Width - 10
@@ -261,9 +345,607 @@ func (self *WareHouse) Init()  {
 		self.Scroller.Init()
 		self.Scroller.SetCanvasHWND(self.CanvasHWND)
 
+		self.RemovePage = UI.NewYesCancelConfirmPage()
+		self.RemovePage.Screen = self.Screen
+		self.RemovePage.StartOrAEvent = self.RemoveGame
+		self.RemovePage.Name = "Are you sure?"
+		
+		self.Keyboard = UI.NewKeyboard()
+		self.Keyboard.Name = "Enter warehouse addr"
+		self.Keyboard.FootMsg = [5]string{"Nav.","Add","ABC","Backspace","Enter"}
+		self.Keyboard.Screen = self.Screen
+		self.Keyboard.Init()
+
+		self.PreviewPage = NewImageDownloadProcessPage()
+		self.PreviewPage.Screen = self.Screen
+		self.PreviewPage.Name ="Preview"
+		self.PreviewPage.Init()
+
+		self.LoadHousePage = NewLoadHousePage()
+		self.LoadHousePage.Screen = self.Screen
+		self.LoadHousePage.Name = "Warehouse"
+		self.LoadHousePage.Parent = self
+		self.LoadHousePage.Init()
+		
+		rpcc, err := rpc.New(context.Background(),
+			self.rpcURI,
+			self.rpcSecret,
+			gotime.Second, AppNotifier{Parent:self})
+		
+    if err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			os.Exit(2)
+    }
+		self.rpcc = rpcc
+		self.Downloader = grab.NewClient()
+		self.Downloading = make(chan bool)
+
+		self.RefreshTicker = gotime.NewTicker(500 * gotime.Millisecond)
+		//self.RefreshTicker.Stop()
+		go self.UpdateProcessInterval(500)
+		
+	}
+
+}
+
+func (self *WareHouse) ResetHouse() {
+	if self.PsIndex > len(self.MyList) -1 {
+		return
+	}
+	cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+	home_path, _ := os.UserHomeDir()
+	
+	if cur_li.Value["type"] == "source" {
+		remote_file_url := cur_li.Value["file"]
+		parts := strings.Split(remote_file_url,"raw.githubusercontent.com")
+		menu_file := parts[1]
+		local_menu_file := fmt.Sprintf("%s/aria2download%s",home_path,menu_file)
+		local_menu_file_path := filepath.Dir(local_menu_file)
+		
+		fmt.Println(local_menu_file)
+		local_jsons,err := filepath.Glob(local_menu_file_path+"/**/*.json")
+		if err != nil {
+			fmt.Println(err)
+		}
+		if UI.FileExists(local_menu_file) {
+			os.Remove(local_menu_file)
+		}
+		if UI.FileExists(local_menu_file+".aria2") {
+			os.Remove(local_menu_file+".aria2")
+		}
+
+		for _,x :=  range local_jsons {
+			os.Remove(x)
+		}
+
+		self.Screen.MsgBox.SetText("Done")
+		self.Screen.MsgBox.Draw()
+		self.Screen.SwapAndShow()
+		
+	}
+}
+
+func (self *WareHouse) LoadHouse() {
+	if self.PsIndex > len(self.MyList) -1 {
+		return
+	}
+
+	cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+	if cur_li.Value["type"] == "source" || cur_li.Value["type"] == "dir" {
+		self.LoadHousePage.URL = cur_li.Value["file"]
+		self.Screen.PushPage(self.LoadHousePage)
+		self.Screen.Draw()
+		self.Screen.SwapAndShow()
+	}
+	
+}
+
+func (self *WareHouse) PreviewGame() {
+	if self.PsIndex > len(self.MyList) -1 {
+		return
+	}
+
+	cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+
+	if cur_li.Value["type"] == "launcher" ||
+		cur_li.Value["type"] == "pico8" ||
+		cur_li.Value["type"] == "tic80" {
+
+		if _,ok := cur_li.Value["shots"];ok {
+			fmt.Println(cur_li.Value["shots"])
+			self.PreviewPage.URL = cur_li.Value["shots"]
+			self.Screen.PushPage(self.PreviewPage)
+			self.Screen.Draw()
+			self.Screen.SwapAndShow()
+		}
+	}
+}
+//check if an Url is downloading in aria2c
+func (self *WareHouse) UrlIsDownloading(url string) (string,bool) {
+	if resp,err := self.rpcc.TellActive();err == nil {
+		for _,v := range resp {
+			if uris,err := self.rpcc.GetURIs(v.Gid);err == nil {
+				for _,x := range uris {
+					if x.URI == url {
+						return v.Gid,true
+					}
+				}
+			}
+		}
+	}
+	return "",false
+}
+
+func (self *WareHouse) RemoveGame() {
+	if self.PsIndex > len(self.MyList) -1 {
+		return
+	}
+	cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+
+	fmt.Println("Remove cur_li._Value",cur_li.Value)
+	home_path, _ := os.UserHomeDir()
+	
+	if cur_li.Value["type"] == "source" {
+		db, err := sql.Open("sqlite3", self.WareHouseDB)
+		if err != nil {
+			log.Fatal(err)
+		}
+		defer db.Close()
+		_, err = db.Exec(fmt.Sprintf("DELETE FROM warehouse WHERE file = '%s'",
+			cur_li.Value["file"]))
 		
+		if err != nil {
+			log.Fatal(err)
+		}
+		
+	} else if cur_li.Value["type"] == "launcher" ||
+		cur_li.Value["type"] == "pico8" ||
+		cur_li.Value["type"] == "tic80" {
+
+		remote_file_url := cur_li.Value["file"]
+		parts := strings.Split(remote_file_url,"raw.githubusercontent.com")
+		menu_file := parts[1]
+		local_menu_file := fmt.Sprintf("%s/aria2download%s",home_path,menu_file)
+		local_menu_file_path := filepath.Dir(local_menu_file)
+
+		gid,ret := self.UrlIsDownloading(remote_file_url)
+		if ret == true {
+			self.rpcc.Remove(gid)
+		}
+
+		if UI.FileExists(local_menu_file)  {
+			os.Remove(local_menu_file)
+		}
+		if UI.FileExists(local_menu_file+".aria2") {
+			os.Remove(local_menu_file+".aria2")
+		}
+		if UI.FileExists(filepath.Join(local_menu_file_path,cur_li.Value["title"])) {
+			os.RemoveAll(filepath.Join(local_menu_file_path,cur_li.Value["title"]))
+		}
 		
+	}
+}
+
+func (self *WareHouse) Click() {
+	if self.PsIndex > len(self.MyList) -1 {
+		return
+	}
+	cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+	home_path, _ := os.UserHomeDir()
+	fmt.Println("cur_li._Value",cur_li.Value)
+
+	if cur_li.Value["type"] == "source" || cur_li.Value["type"] == "dir" {
+		remote_file_url := cur_li.Value["file"]
+		parts := strings.Split(remote_file_url,"raw.githubusercontent.com")//assume master branch
+		menu_file := parts[1]
+		local_menu_file := fmt.Sprintf("%s/aria2download%s",home_path,menu_file)
+		fmt.Println(local_menu_file)
+		if UI.FileExists(local_menu_file) == false {
+			self.LoadHouse()
+		}else {
+			//read the local_menu_file,push into stack,display menu
+			self.Aria2DownloadingGid = ""
+			var result WareHouseIndex
+			jsonFile, err := os.Open(local_menu_file)
+			
+			if err != nil {
+        fmt.Println(err)
+				self.Screen.MsgBox.SetText("Open House failed")
+				self.Screen.MsgBox.Draw()
+				self.Screen.SwapAndShow()
+				
+			}else {
+				defer jsonFile.Close()
+				
+				byteValue, _ := ioutil.ReadAll(jsonFile)
+				json.Unmarshal(byteValue, &result)
+				
+				for _, repo := range result.List {
+					self.MyStack.Push(repo)
+				}
+
+				self.SyncList()
+				self.Screen.Draw()
+				self.Screen.SwapAndShow()
+			}
+
+			
+		}
+	} else if cur_li.Value["type"] == "add_house" {
+		fmt.Println("show keyboard to add warehouse")
+		self.Screen.PushCurPage()
+		self.Screen.SetCurPage(self.Keyboard)
 		
+	} else {
+		//download the game probably
+		remote_file_url := cur_li.Value["file"]
+		parts := strings.Split(remote_file_url,"raw.githubusercontent.com")//assume master branch
+		menu_file := parts[1]
+		local_menu_file := fmt.Sprintf("%s/aria2download%s",home_path,menu_file)
+
+		if UI.FileExists(local_menu_file) == false {
+			gid,ret := self.UrlIsDownloading(remote_file_url)
+			if ret == false {
+				gid,err := self.rpcc.AddURI([]string{remote_file_url},"out:"+menu_file)
+				if err != nil {
+					log.Fatal(err)
+				}else {
+					self.Aria2DownloadingGid = gid
+				}
+			} else {
+				fmt.Println(self.rpcc.TellStatus(gid,"status","totalLength","completedLength"))
+				self.Screen.MsgBox.SetText("Getting the game now")
+				self.Screen.MsgBox.Draw()
+				self.Screen.SwapAndShow()
+				time.BlockDelay(800)
+				self.Screen.TitleBar.Redraw()
+			}
+		}else {
+			fmt.Println("file downloaded") //maybe check it if is installed fst,then execute it
+			if cur_li.Value["type"] == "launcher" && cur_li.ReadOnly == false {
+				local_menu_file_path := filepath.Dir(local_menu_file)
+				game_sh := filepath.Join(local_menu_file_path,cur_li.Value["title"],cur_li.Value["title"]+".sh")
+
+				fmt.Println("run game: ",game_sh, UI.FileExists(game_sh))
+				self.Screen.RunEXE(game_sh)
+					
+			}
+			if cur_li.Value["type"] == "pico8" &&  cur_li.ReadOnly == false {
+				if UI.FileExists("/home/cpi/games/PICO-8/pico-8/pico8") {
+					game_sh := "/home/cpi/launcher/Menu/GameShell/50_PICO-8/PICO-8.sh"
+					self.Screen.RunEXE(game_sh) //pico8 manages its games self
+				}
+			}
+			if cur_li.Value["type"] == "tic80" && cur_li.ReadOnly == false {
+				game_sh := "/home/cpi/apps/Menu/51_TIC-80/TIC-80.sh"
+				self.Screen.RunEXE(game_sh)
+			}
+		}
 	}
+}
+
+func (self *WareHouse) OnAria2CompleteCb(gid string) {
+	fmt.Println("OnAria2CompleteCb", gid)
+	self.SyncList()
+	self.Screen.Draw()
+	self.Screen.SwapAndShow()
+	
+	if gid == self.Aria2DownloadingGid {
+		self.Aria2DownloadingGid = ""
+	}
+}
 
+func (self *WareHouse) raw_github_com(url string) (bool,string) {
+	if strings.HasPrefix(url,"github.com") == false {
+		return false,""
+	}
+
+	parts := strings.Split(url,"/")
+
+	if len(parts) != 3 {
+		return false, ""
+	}
+	str := []string{"https://raw.githubusercontent.com",
+		parts[1],
+		parts[2],
+		"master/index.json"}
+	
+	return true,strings.Join(str,"/")
+	
+}
+
+	
+func (self *WareHouse)  OnKbdReturnBackCb() {
+	inputed:= strings.Join(self.Keyboard.Textarea.MyWords,"")
+	inputed = strings.Replace(inputed,"http://","",-1)
+	inputed = strings.Replace(inputed,"https://","",-1)
+
+	if strings.HasSuffix(inputed,".git") {
+		inputed = inputed[:len(inputed)-4]
+	}
+	if strings.HasSuffix(inputed,"/") {
+		inputed = inputed[:len(inputed)-1]
+	}
+
+	fmt.Println("last: ",inputed)
+	db, err := sql.Open("sqlite3", self.WareHouseDB)
+	if err != nil {
+		log.Fatal(err)
+		return
+	}
+	defer db.Close()
+	
+	stmt, err := db.Prepare("SELECT count(*) FROM warehouse WHERE title= ?")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer stmt.Close()
+
+	var cnt_str string
+	cnt := 0
+	err = stmt.QueryRow(inputed).Scan(&cnt_str)
+	if err != nil {
+		log.Fatal(err)
+	}else {
+		cnt,_= strconv.Atoi(cnt_str)
+	}
+	
+	if cnt > 0 {
+		self.Screen.MsgBox.SetText("Warehouse existed")
+		self.Screen.MsgBox.Draw()
+		self.Screen.SwapAndShow()
+	} else {
+		if strings.Contains(inputed,"github.com/clockworkpi/warehouse") {
+			self.Screen.MsgBox.SetText("Warehouse existed")
+			self.Screen.MsgBox.Draw()
+			self.Screen.SwapAndShow()
+		}else {
+			valid_,_url := self.raw_github_com(inputed)
+			
+			if valid_ == false {
+				self.Screen.MsgBox.SetText("Warehouse url error!")
+				self.Screen.MsgBox.Draw()
+				self.Screen.SwapAndShow()
+			} else {
+				sql_insert := fmt.Sprintf("INSERT INTO warehouse(title,file,type) VALUES('%s','%s','source');",
+					inputed,_url)
+				_, err = db.Exec(sql_insert)
+				if err != nil {
+					log.Fatal(err)
+				}
+
+				self.SyncList()
+				self.Screen.Draw()
+				self.Screen.SwapAndShow()
+			}
+		}
+	}	
+}
+
+func (self *WareHouse) OnLoadCb() {
+
+	if self.MyStack.Length() == 1 {
+		self.FootMsg[2] = "Remove"
+		self.FootMsg[1] = "Update"
+	}else {
+		self.FootMsg[2] = "Remove"
+		self.FootMsg[1] = "Preview"		
+	}
+
+	self.RefreshTicker = gotime.NewTicker(500 * gotime.Millisecond)
+	
+	self.SyncList()
+}
+
+
+func (self *WareHouse)  OnReturnBackCb() {
+	if self.MyStack.Length() == 1 {
+		self.FootMsg[2] = "Remove"
+		self.FootMsg[1] = "Update"
+	}else {
+		self.FootMsg[2] = "Remove"
+		self.FootMsg[1] = "Preview"
+	}
+
+	self.SyncList()
+	self.RestoreScrolled()
+	
+	self.Screen.Draw()
+	self.Screen.SwapAndShow()
+	
+}
+
+func (self *WareHouse) ScrollDown() {
+	if len(self.MyList) == 0 {
+		return
+	}
+	self.PsIndex += 1
+
+	if self.PsIndex >= len(self.MyList) {
+		self.PsIndex = len(self.MyList) - 1
+	}
+
+	cur_li := self.MyList[self.PsIndex]
+	x, y := cur_li.Coord()
+	_, h := cur_li.Size()
+	
+	if y+h > self.Height {
+		for i, _ := range self.MyList {
+			x, y = self.MyList[i].Coord()
+			_, h = self.MyList[i].Size()
+			self.MyList[i].NewCoord(x, y-h)
+		}
+		
+		self.ScrolledCnt -= h
+	}
+}
+
+func (self *WareHouse) ScrollUp() {
+	if len(self.MyList) == 0 {
+		return
+	}
+
+	self.PsIndex -= 1
+
+	if self.PsIndex < 0 {
+		self.PsIndex = 0
+	}
+
+	cur_li := self.MyList[self.PsIndex]
+	x, y := cur_li.Coord()
+	_, h := cur_li.Size()
+	if y < 0 {
+		for i, _ := range self.MyList {
+			x, y = self.MyList[i].Coord()
+			_, h = self.MyList[i].Size()
+			self.MyList[i].NewCoord(x, y+h)
+		}
+
+		self.ScrolledCnt += h
+	}
+
+}
+
+func (self *WareHouse) RestoreScrolled() {
+	for i,_ := range self.MyList {
+		x,y := self.MyList[i].Coord()
+		self.MyList[i].NewCoord(x, y+ self.ScrolledCnt)
+	}
+}
+
+func (self *WareHouse) KeyDown(ev *event.Event) {
+	if UI.IsKeyMenuOrB(ev.Data["Key"]) {
+		if self.MyStack.Length() > 1 {
+			self.MyStack.Pop()
+			if self.MyStack.Length() == 1 {
+				self.FootMsg[2] = "Remove"
+				self.FootMsg[1] = "Update"
+				
+			}else {
+				self.FootMsg[2] = "Remove"
+				self.FootMsg[1] = "Preview"
+				if self.MyStack.Length() == 2 {
+					self.FootMsg[2] = ""
+					self.FootMsg[1] = ""
+				}
+			}
+
+			self.SyncList()
+			self.Screen.Draw()
+			self.Screen.SwapAndShow()
+		}else if self.MyStack.Length() == 1 {
+			self.ReturnToUpLevelPage()
+			self.Screen.Draw()
+			self.Screen.SwapAndShow()
+			self.RefreshTicker.Stop()
+		}
+	}
+	
+	if UI.IsKeyStartOrA(ev.Data["Key"]) {
+		self.Click()
+		if self.MyStack.Length() == 1 {
+			self.FootMsg[2] = "Remove"
+			self.FootMsg[1] = "Update"
+		}else {
+			self.FootMsg[2] = "Remove"
+			self.FootMsg[1] = "Preview"
+			if self.MyStack.Length() == 2 {
+				self.FootMsg[2] = ""
+				self.FootMsg[1] = ""
+			}
+		}
+
+		self.Screen.Draw()
+		self.Screen.SwapAndShow()
+	}
+
+	if ev.Data["Key"] == UI.CurKeys["X"] {
+		if self.PsIndex <= len(self.MyList) -1 {
+			cur_li := self.MyList[self.PsIndex].(*WareHouseListItem)
+			if cur_li.Type != "dir" {
+				if self.MyStack.Length() ==1 && self.PsIndex == 0 {
+					//pass
+				}else {
+					self.Screen.PushPage(self.RemovePage)
+					self.RemovePage.StartOrAEvent = self.RemoveGame
+					self.Screen.Draw()
+					self.Screen.SwapAndShow()
+				}
+			}
+			return
+		}
+		self.SyncList()
+		self.Screen.Draw()
+		self.Screen.SwapAndShow()
+	}
+
+	if ev.Data["Key"] == UI.CurKeys["Y"] {
+		if self.MyStack.Length() == 1 {
+			self.ResetHouse()
+		}else {
+			self.PreviewGame()
+		}
+	}
+
+	if ev.Data["Key"] == UI.CurKeys["Up"] {
+		self.ScrollUp()
+		self.Screen.Draw()
+		self.Screen.SwapAndShow()
+	}
+
+	if ev.Data["Key"] == UI.CurKeys["Down"] {
+		self.ScrollDown()
+		self.Screen.Draw()
+		self.Screen.SwapAndShow()
+	}	
+	
+}
+
+func (self *WareHouse) Draw() {
+
+	self.ClearCanvas()
+	if len(self.MyList) == 0 {
+		return
+	} else {
+		if len(self.MyList) * UI.DefaultInfoPageListItemHeight > self.Height {
+			_,h := self.Ps.Size()
+			self.Ps.NewSize(self.Width - 11,h)
+			self.Ps.Draw()
+			for _,v := range self.MyList {
+				_,y := v.Coord()
+				if y > self.Height + self.Height/2 {
+					break
+				}
+				if y < 0 {
+					continue
+				}
+				v.Draw()
+			}
+
+			self.Scroller.UpdateSize(len(self.MyList)*UI.DefaultInfoPageListItemHeight,self.PsIndex*UI.DefaultInfoPageListItemHeight)
+			self.Scroller.Draw()
+		}else {
+			_,h := self.Ps.Size()
+			self.Ps.NewSize(self.Width,h)
+			self.Ps.Draw()
+			for _,v := range self.MyList {
+				_,y := v.Coord()
+				if y > self.Height + self.Height/2 {
+					break
+				}
+				if y < 0 {
+					continue
+				}
+				v.Draw()
+			}	
+		}	
+	}
+	
+	if self.HWND != nil {
+		surface.Fill(self.HWND, UI.MySkinManager.GiveColor("White"))
+		rect_ := rect.Rect(self.PosX, self.PosY, self.Width, self.Height)
+		surface.Blit(self.HWND, self.CanvasHWND, &rect_, nil)
+	}
+	
+	
 }

+ 3 - 0
go.mod

@@ -11,16 +11,19 @@ require (
 	github.com/godbus/dbus v4.1.0+incompatible
 	github.com/godbus/dbus/v5 v5.0.5
 	github.com/itchyny/volume-go v0.2.1
+	github.com/mattn/go-sqlite3 v1.14.9
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d
 	github.com/sirupsen/logrus v1.8.1
 	github.com/veandco/go-sdl2 v0.4.10
 	github.com/vjeantet/jodaTime v1.0.0
 	github.com/yookoala/realpath v1.0.0
+	github.com/zyxar/argo v0.0.0-20210923033329-21abde88a063
 )
 
 require (
 	github.com/go-ole/go-ole v1.2.5 // indirect
+	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/moutend/go-wca v0.2.0 // indirect
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 11 - 0
go.sum

@@ -20,11 +20,19 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
 github.com/godbus/dbus/v5 v5.0.5 h1:9Eg0XUhQxtkV8ykTMKtMMYY72g4NgxtRq4jgh4Ih5YM=
 github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/itchyny/volume-go v0.2.1 h1:NiVdnIp3dyCBnygQoBLV9ecAk7Vk4KHfiZFJGvCCIm0=
 github.com/itchyny/volume-go v0.2.1/go.mod h1:YdvjyTIcPXyGcckaIHTfga+ItdhGZQoWhzOORajlkkE=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
+github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/moutend/go-wca v0.2.0 h1:AEzY6ltC5zPCldKyMYdyXv3TaLqwxSW1TIradqNqRpU=
@@ -32,6 +40,7 @@ github.com/moutend/go-wca v0.2.0/go.mod h1:L/ka++dPvkHYz0UuQ/PIQ3aTuecoXOIM1RSAe
 github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d h1:EG/xyWjHT19rkUpwsWSkyiCCmyqNwFovr9m10rhyOxU=
 github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf/go.mod h1:+AwQL2mK3Pd3S+TUwg0tYQjid0q1txyNUJuuSmz8Kdk=
@@ -57,6 +66,8 @@ github.com/vjeantet/jodaTime v1.0.0/go.mod h1:gA+i8InPfZxL1ToHaDpzi6QT/npjl3uPlc
 github.com/yookoala/realpath v1.0.0 h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=
 github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zyxar/argo v0.0.0-20210923033329-21abde88a063 h1:xCSVbiTicJX7M0l/Uf/91517mou3E57UnzTsp/bol2E=
+github.com/zyxar/argo v0.0.0-20210923033329-21abde88a063/go.mod h1:rXaHR0MNLc/U/lqic2jozgrZDdlpyoxFHgw88oa/kSk=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

+ 1 - 2
main.go

@@ -21,9 +21,8 @@ import (
 	//	"github.com/cuu/gogame/color"
 	"github.com/cuu/gogame/font"
 	//"github.com/cuu/gogame/time"
-
+	
 	"github.com/clockworkpi/LauncherGoDev/sysgo"
-
 	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
 )
 

+ 7 - 3
mainscreen.go

@@ -16,17 +16,21 @@ import (
 	"github.com/go-ini/ini"
 
 	"github.com/yookoala/realpath"
-
+	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
+	"github.com/clockworkpi/LauncherGoDev/sysgo/UI/Emulator"
+	
 	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/10_Settings"
+	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/21_Warehouse"
 	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/98_TinyCloud"
 	"github.com/clockworkpi/LauncherGoDev/Menu/GameShell/99_PowerOFF"
-	"github.com/clockworkpi/LauncherGoDev/sysgo/UI"
-	"github.com/clockworkpi/LauncherGoDev/sysgo/UI/Emulator"
+	
+	
 )
 
 var (
 	UIPluginList = []*UI.UIPlugin{
 		&UI.UIPlugin{1, "", "Menu/GameShell/10_Settings", "Settings", &Settings.APIOBJ},
+		&UI.UIPlugin{1, "", "Menu/GameShell/21_Warehouse", "Warehouse", &Warehouse.APIOBJ},
 		&UI.UIPlugin{1, "", "Menu/GameShell/98_TinyCloud", "TinyCloud", &TinyCloud.APIOBJ},
 		&UI.UIPlugin{1, "", "Menu/GameShell/99_PowerOFF", "PowerOFF", &PowerOFF.APIOBJ},
 	}

+ 44 - 1
sysgo/UI/title_bar.go

@@ -1,6 +1,7 @@
 package UI
 
 import (
+	"context"
 	"bufio"
 	"fmt"
 	"io/ioutil"
@@ -14,6 +15,8 @@ import (
 	"github.com/veandco/go-sdl2/sdl"
 	"github.com/veandco/go-sdl2/ttf"
 
+	"github.com/zyxar/argo/rpc"
+	
 	"github.com/cuu/gogame/draw"
 	"github.com/cuu/gogame/font"
 	"github.com/cuu/gogame/rect"
@@ -137,6 +140,34 @@ func NewTitleBar() *TitleBar {
 
 }
 
+func (self *TitleBar) Redraw() {
+	self.UpdateDownloadStatus()
+	SwapAndShow()
+}
+
+func (self *TitleBar) UpdateDownloadStatus() {
+	
+	rpcc, err := rpc.New(context.Background(), sysgo.Aria2Url, "", gotime.Second, nil)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return
+	}
+
+	if resp,err := rpcc.GetGlobalStat();err == nil {
+		num_active,_ := strconv.Atoi(resp.NumActive)
+		
+		if num_active > 0 {
+			self.Icons["dlstatus"].SetIconIndex(1)
+		}else if num_active == 0 {
+			self.Icons["dlstatus"].SetIconIndex(0)
+		}
+	}
+	
+	
+	defer rpcc.Close()
+
+}
+
 func (self *TitleBar) RoundRobinCheck() {
 	for {
 
@@ -144,6 +175,7 @@ func (self *TitleBar) RoundRobinCheck() {
 			self.CheckBatteryStat()
 			self.CheckBluetooth()
 			self.UpdateWifiStrength()
+			self.UpdateDownloadStatus()
 			SwapAndShow()
 
 		} else if self.InLowBackLight >= 0 {
@@ -153,7 +185,7 @@ func (self *TitleBar) RoundRobinCheck() {
 				self.CheckBatteryStat()
 				self.CheckBluetooth()
 				self.UpdateWifiStrength()
-
+				self.UpdateDownloadStatus()
 				self.InLowBackLight = 0 // reset
 			}
 
@@ -416,6 +448,17 @@ func (self *TitleBar) Init(main_screen *MainScreen) {
 
 	self.Icons["round_corners"] = round_corners
 
+	dlstatus := NewTitleBarIconItem()
+	dlstatus.MyType = ICON_TYPES["STAT"]
+	dlstatus.Parent = self
+	if FileExists(self.icon_base_path + "dlstatus18.png") {
+		dlstatus.ImageName = self.icon_base_path + "dlstatus18.png"
+	}
+	dlstatus.Adjust(start_x+self.IconWidth+self.IconWidth+8, self.IconHeight/2+(self.BarHeight-self.IconHeight)/2, self.IconWidth, self.IconHeight, 0)
+	self.Icons["dlstatus"] = dlstatus
+
+	self.UpdateDownloadStatus()
+	
 	if self.IsWifiConnectedNow() {
 		print("wifi is connected")
 	} else {

+ 3 - 2
sysgo/UI/yes_cancel__confirm_page.go → sysgo/UI/yes_cancel_confirm_page.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/cuu/gogame/event"
 	//"github.com/cuu/gogame/time"
+	
 )
 
 type Func func()
@@ -33,13 +34,13 @@ func NewYesCancelConfirmPage() *YesCancelConfirmPage {
 
 func (self *YesCancelConfirmPage) KeyDown(ev *event.Event) {
 
-	if UI.IsKeyMenuOrB(ev.Data["Key"]) {
+	if IsKeyMenuOrB(ev.Data["Key"]) {
 		self.ReturnToUpLevelPage()
 		self.Screen.Draw()
 		self.Screen.SwapAndShow()
 	}
 
-	if UI.IsKeyStartOrA(ev.Data["Key"]) {
+	if IsKeyStartOrA(ev.Data["Key"]) {
 		if self.StartOrAEvent != nil {
 			self.StartOrAEvent()
 			self.ReturnToUpLevelPage()

+ 2 - 0
sysgo/config.go

@@ -32,6 +32,8 @@ var (
 	CurPowerLevel = "performance"
 	Lang          = "English"
 	WifiDev       = "wlan0"
+
+	Aria2Url      = "ws://localhost:6800/jsonrpc"
 )
 
 func init() {