当前位置: 首页 > news >正文

AtomGit Flutter鸿蒙客户端:仓库详情页

路由参数

仓库详情页通过命名路由/repo进入,接收ownername参数:

// 导航到详情页Navigator.pushNamed(context,'/repo',arguments:{'owner':'atomgit','name':'flutter-ohos'});// 详情页提取参数finalargs=ModalRoute.of(context)!.settings.argumentsasMap<String,dynamic>;finalowner=args['owner']asString;finalname=args['name']asString;

RepoDetailProvider

Provider 在创建时即开始加载数据:

classRepoDetailProviderextendsChangeNotifier{finalAtomGitApiClient_apiClient;Repository?_repository;String?_readme;bool _isLoading=false;String?_error;Future<void>load(Stringowner,Stringname)async{_isLoading=true;_error=null;notifyListeners();try{finalencodedOwner=Uri.encodeComponent(owner);finalencodedName=Uri.encodeComponent(name);finalresponse=await_apiClient.get('/repos/$encodedOwner/$encodedName',);finaldata=parseMap(response.data);if(data!=null){_repository=Repository.fromJson(data);}_readme=await_loadReadme(encodedOwner,encodedName,_repository?.defaultBranch??'main');}onApiExceptioncatch(e){_error=e.message;}catch(e){_error='加载失败:$e';}finally{_isLoading=false;notifyListeners();}}}

关键细节:owner 和 name 都经过Uri.encodeComponent编码,处理含特殊字符的仓库路径。

README 加载

README 加载采用静默失败策略 —— 没有 README 不报错,只是不展示:

Future<String?>_loadReadme(Stringowner,Stringrepo,Stringbranch)async{try{finalresponse=await_apiClient.get('/repos/$owner/$repo/readme',queryParams:{'ref':branch},);finaldata=parseMap(response.data);if(data!=null&&data['content']isString){finalcontent=data['content']asString;returnutf8.decode(base64.decode(content));}}onApiException{// README 不存在是正常的,不报错}catch(_){}returnnull;}

API 返回的 README 内容是 Base64 编码的,解码后用MarkdownViewer渲染。

页面结构

RepoDetailScreen 是 StatelessWidget,通过 ChangeNotifierProvider 注入 Provider:

classRepoDetailScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalargs=ModalRoute.of(context)!.settings.argumentsasMap<String,dynamic>;finalowner=args['owner']asString;finalname=args['name']asString;returnChangeNotifierProvider(create:(_)=>RepoDetailProvider(context.read<AtomGitApiClient>())..load(owner,name),child:_RepoDetailBody(owner:owner,name:name),);}}

自定义 Tab 栏

不使用 Flutter 的 TabBar/TabBarView,而是自定义 Row 按钮实现四个标签切换:

enum_DetailTab{code,issues,pulls,readme}class_RepoDetailBodyStateextendsState<_RepoDetailBody>{_DetailTab _currentTab=_DetailTab.readme;Widget_buildTabBar(){returnMaterial(elevation:1,child:Padding(padding:constEdgeInsets.symmetric(horizontal:16,vertical:8),child:Row(children:[_TabButton(label:'代码',isSelected:_currentTab==_DetailTab.code,onTap:(){Navigator.pushNamed(context,'/repo/code',arguments:{'owner':widget.owner,'name':widget.name,'branch':provider.repository?.defaultBranch??'main',});},),_TabButton(label:'Issues',isSelected:_currentTab==_DetailTab.issues,onTap:(){Navigator.pushNamed(context,'/repo/issues',arguments:{'owner':widget.owner,'name':widget.name,'type':'issue',});},),_TabButton(label:'PRs',isSelected:_currentTab==_DetailTab.pulls,onTap:(){Navigator.pushNamed(context,'/repo/pulls',arguments:{'owner':widget.owner,'name':widget.name,'type':'pr',});},),_TabButton(label:'README',isSelected:_currentTab==_DetailTab.readme,onTap:()=>setState(()=>_currentTab=_DetailTab.readme),),],),),);}}

每个按钮的选中态通过底部蓝色指示条实现:

class_TabButtonextendsStatelessWidget{finalStringlabel;finalbool isSelected;finalVoidCallbackonTap;Widgetbuild(BuildContextcontext){returnExpanded(child:GestureDetector(onTap:onTap,child:Column(children:[Text(label,style:TextStyle(color:isSelected?Theme.of(context).colorScheme.primary:null,fontWeight:isSelected?FontWeight.w600:null,)),if(isSelected)Container(height:2,margin:constEdgeInsets.only(top:4),color:Theme.of(context).colorScheme.primary,),],),),);}}

头部信息区

仓库名、描述、统计数据以卡片形式展示:

Widget_buildRepoHeader(Repositoryrepo){returnCard(margin:constEdgeInsets.all(16),child:Padding(padding:constEdgeInsets.all(16),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Row(children:[Icon(repo.isPrivate?Icons.lock_outline:Icons.book_outlined,size:20),constSizedBox(width:8),Expanded(child:Text(repo.fullName,style:Theme.of(context).textTheme.titleMedium)),]),if(repo.description!=null)...[constSizedBox(height:8),Text(repo.description!),],constSizedBox(height:12),Row(children:[_StatItem(Icons.star_border,'${repo.stargazersCount}'),_StatItem(Icons.call_split,'${repo.forksCount}'),_StatItem(Icons.remove_red_eye_outlined,'${repo.watchersCount}'),_StatItem(Icons.error_outline,'${repo.openIssuesCount}'),]),],),),);}

README 渲染

Widget_buildReadme(RepoDetailProviderprovider){if(provider.readme==null||provider.readme!.isEmpty){returnconstCenter(child:Text('暂无 README'));}returnSingleChildScrollView(padding:constEdgeInsets.all(16),child:MarkdownViewer(markdown:provider.readme!),);}

状态处理

三种状态的完整处理:

Widget_buildBody(RepoDetailProviderprovider){if(provider.error!=null&&provider.repository==null){returnErrorRetryWidget(message:provider.error!,onRetry:()=>provider.load(widget.owner,widget.name),);}if(provider.repository==null){returnconstLoadingIndicator(message:'加载仓库信息...');}returnColumn(children:[_buildTabBar(),Expanded(child:_buildReadme(provider)),]);}

错误时展示可重试的错误页面,加载中展示 LoadingIndicator,成功后展示完整内容。

http://www.rkmt.cn/news/1481243.html

相关文章:

  • 2026重庆5天4晚纯玩游怎么选导游|路线解析、口碑对比与选择指南 - 随峰国旅
  • 普林斯顿团队发布Goedel - Architect:低成本开源框架革新形式化定理证明
  • I2C软件模拟驱动开发:从协议原理到稳定调试的实战指南
  • Android 13应用语言独立设置:打破系统限制的技术实现方案
  • CSDN AI数字营销免费试用期到底几天?3大关键限制+2个自动续费陷阱,90%新人不知道
  • Linux内核时间管理与延时机制:从jiffies到高精度定时器实战
  • 探索ComfyUI-KJNodes的3个核心维度:从模块化思维到创意实践
  • 终极抖音下载指南:如何免费批量保存视频、图集和直播回放
  • ArchivePasswordTestTool:基于7zip引擎的企业级加密压缩包密码恢复解决方案架构与实践
  • 终极指南:如何使用TegraRcmGUI图形化工具轻松完成Switch RCM注入
  • DataCleaner 5.1.5 全功能开源数据清洗套件:可视化操作+命令行支持+多源接入+脚本扩展
  • 分子动力学模拟新手必看:3分钟掌握Packmol初始构型构建
  • 终极数据恢复指南:如何使用TestDisk和PhotoRec免费找回丢失的文件
  • 计算机专业学生选AI方向,先分清应用开发和算法研究的差距
  • OpenCore Legacy Patcher终极指南:四步修复老Mac显卡驱动并升级最新macOS
  • 3分钟掌握sg3_utils:你的存储设备管理神器
  • 5分钟实现AI到PSD的无损转换,告别手动分层烦恼
  • 颠覆性网络拓扑可视化:easy-topo如何重塑网络架构设计范式
  • 10分钟彻底解决Windows和Office激活难题的智能方案
  • Verilog generate语句详解:从基础语法到高级应用与避坑指南
  • 如何快速掌握Grasscutter Tools:面向原神私服玩家的完整指南
  • 深度解析:UvSquares如何通过智能算法重塑Blender UV网格
  • OpenCV C++ filter2D三合一图像处理工程:含锐化、高斯模糊、边缘检测完整VS2019项目
  • FlowFuse Dashboard:现代化物联网可视化平台架构解析
  • Windows和Office一键激活终极指南:KMS_VL_ALL_AIO智能脚本详解
  • 5分钟快速上手:yuzu Switch模拟器完整配置指南
  • 重构内容获取:基于异步并发的抖音下载器架构深度解析
  • Keil C51编译器0xFD幽灵Bug:嵌入式汉字显示乱码的根源与解决方案
  • Mac用户终极指南:如何用12306ForMac高效抢票的完整教程
  • 2026丙烯酸聚氨酯面漆优质厂家推荐 优选河北永邯环保科技有限公司 - 奔跑123