├── .gitignore ├── LICENSE ├── README.md ├── XML.patch ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── litepal.xml │ ├── java │ └── com │ │ └── lfork │ │ └── a98620 │ │ └── lfree │ │ ├── articlecontent │ │ ├── ArticleContentActivity.java │ │ ├── ArticleContentActivityViewModel.java │ │ ├── CommunityComment.java │ │ ├── CommunityCommentAdapter.java │ │ └── LightTextView.java │ │ ├── base │ │ ├── BaseActivity.java │ │ ├── BaseViewModel.java │ │ ├── Config.java │ │ ├── FreeApplication.java │ │ ├── MyApplication.java │ │ ├── adapter │ │ │ ├── ListViewAdapter.java │ │ │ └── RecyclerViewItemAdapter.java │ │ ├── bindingadapter │ │ │ ├── ImageBinding.java │ │ │ └── ListBinding.java │ │ ├── customview │ │ │ ├── MySwipeRefreshLayout.java │ │ │ ├── PopupDialog.java │ │ │ ├── PopupDialogOnclickListener.java │ │ │ └── RefreshFooterView.java │ │ ├── image │ │ │ ├── GlideEngine.java │ │ │ ├── GlideImageLoader.java │ │ │ └── ImageTool.java │ │ ├── network │ │ │ ├── HttpService.java │ │ │ ├── MyRetrofitCallBack.kt │ │ │ └── Result.kt │ │ ├── thread │ │ │ └── MyThreadFactory.java │ │ └── viewmodel │ │ │ ├── GoodsViewModel.java │ │ │ ├── UserViewModel.java │ │ │ └── ViewModelNavigator.java │ │ ├── chatwindow │ │ ├── ChatWindowActivity.java │ │ ├── ChatWindowNavigator.java │ │ ├── ChatWindowViewModel.java │ │ └── MessageListAdapter.java │ │ ├── data │ │ ├── DataSource.kt │ │ ├── base │ │ │ ├── api │ │ │ │ ├── CommunityApi.kt │ │ │ │ ├── GoodsApi.kt │ │ │ │ └── UserApi.kt │ │ │ └── entity │ │ │ │ ├── Category.kt │ │ │ │ ├── Goods.kt │ │ │ │ ├── GoodsDetailInfo.kt │ │ │ │ ├── IMUser.kt │ │ │ │ ├── Review.kt │ │ │ │ ├── School.kt │ │ │ │ └── User.kt │ │ ├── community │ │ │ ├── CommunityDataSource.java │ │ │ ├── local │ │ │ │ └── CommunityLocalDataSource.java │ │ │ └── remote │ │ │ │ └── CommunityRemoteDataSource.java │ │ ├── goods │ │ │ ├── GoodsDataRepository.kt │ │ │ ├── GoodsDataSource.kt │ │ │ ├── local │ │ │ │ └── GoodsLocalDataSource.kt │ │ │ └── remote │ │ │ │ └── GoodsRemoteDataSource.kt │ │ ├── imdata │ │ │ ├── IMDataRepository.kt │ │ │ ├── IMDataSource.kt │ │ │ ├── MessageDataRepository.kt │ │ │ ├── MessageDataSource.kt │ │ │ ├── local │ │ │ │ ├── IMLocalDataSource.kt │ │ │ │ └── MessageLocalDataSource.kt │ │ │ └── remote │ │ │ │ ├── IMRemoteDataSource.kt │ │ │ │ └── MessageRemoteDataSource.kt │ │ └── user │ │ │ ├── UserDataRepository.kt │ │ │ ├── UserDataSource.kt │ │ │ ├── local │ │ │ └── UserLocalDataSource.kt │ │ │ └── remote │ │ │ └── UserRemoteDataSource.kt │ │ ├── goodsdetail │ │ ├── GoodsDetailActivity.java │ │ ├── GoodsDetailNavigator.java │ │ ├── GoodsDetailViewModel.java │ │ └── ReviewItemViewModel.java │ │ ├── goodsuploadupdate │ │ ├── GoodsCategoriesBinding.java │ │ ├── GoodsUploadUpdateActivity.java │ │ ├── GoodsUploadUpdateNavigator.java │ │ └── GoodsUploadUpdateViewModel.java │ │ ├── imagebrowser │ │ └── ImageBrowserActivity.java │ │ ├── imservice │ │ ├── Config.java │ │ ├── MessageListener.java │ │ ├── MessageService.java │ │ ├── MessageTask.java │ │ ├── TCPConnection.java │ │ ├── UDPConnection.java │ │ ├── UDPMessageMaid.java │ │ ├── message │ │ │ ├── Message.java │ │ │ ├── MessageContentType.java │ │ │ ├── MessageHelper.java │ │ │ ├── MessageStatus.java │ │ │ └── MessageType.java │ │ └── request │ │ │ ├── LoginListener.java │ │ │ ├── RegisterListener.java │ │ │ ├── Request.java │ │ │ ├── Result.java │ │ │ └── UserRequestType.java │ │ ├── login │ │ ├── LoginActivity.java │ │ ├── LoginNavigator.java │ │ └── LoginViewModel.java │ │ ├── main │ │ ├── MainActivity.java │ │ ├── chatlist │ │ │ ├── ChatListFragment.java │ │ │ ├── ChatListFragmentViewModel.java │ │ │ ├── ChatListItemNavigator.java │ │ │ └── ChatListItemViewModel.java │ │ ├── community │ │ │ ├── CommunityArticle.java │ │ │ ├── CommunityArticleAdapter.java │ │ │ ├── CommunityBindingAdapter.java │ │ │ ├── CommunityCallback.java │ │ │ ├── CommunityFragment.java │ │ │ └── CommunityFragmentViewModel.java │ │ ├── index │ │ │ ├── GoodsItemNavigator.java │ │ │ ├── GoodsItemViewModel.java │ │ │ ├── GoodsRecyclerViewItemAdapter.java │ │ │ ├── IndexFragment.java │ │ │ ├── IndexFragmentNavigator.java │ │ │ ├── IndexFragmentViewModel.java │ │ │ ├── PagerDataRefreshListener.java │ │ │ ├── PagerItemAdapter.java │ │ │ ├── PagerItemView.java │ │ │ ├── PagerItemViewModel.java │ │ │ ├── PagerItemViewNavigator.java │ │ │ └── PagersDataBinding.java │ │ ├── myinfo │ │ │ ├── MyInfoFragment.java │ │ │ ├── MyInfoFragmentNavigator.java │ │ │ └── MyInfoFragmentViewModel.java │ │ └── publishinfo │ │ │ └── PublishInfoFragment.java │ │ ├── mygoods │ │ ├── MyGoodsActivity.java │ │ ├── MyGoodsActivityNavigator.java │ │ ├── MyGoodsItemNavigator.java │ │ ├── MyGoodsItemViewModel.java │ │ └── MyGoodsViewModel.java │ │ ├── publisharticle │ │ └── PublishArticleActivity.java │ │ ├── register │ │ ├── RegisterActivity.java │ │ ├── RegisterInfoViewModel.java │ │ └── RegisterNavigator.java │ │ ├── searchresult │ │ ├── GoodsSearchActivity.java │ │ ├── GoodsSearchItemViewModel.java │ │ ├── GoodsSearchNavigator.java │ │ └── GoodsSearchViewModel.java │ │ ├── settings │ │ └── SettingsActivity.kt │ │ ├── userinfo │ │ ├── UserInfoActivity.java │ │ └── UserInfoViewModel.java │ │ ├── userinfoedit │ │ ├── UserInfoEditActivity.java │ │ ├── UserInfoEditNavigator.java │ │ └── UserInfoEditViewModel.java │ │ ├── userinfothis │ │ ├── UserInfoThisActivity.java │ │ └── UserInfoThisViewModel.java │ │ ├── util │ │ ├── JSONUtil.java │ │ ├── LFreeGlideModel.java │ │ ├── Print.java │ │ ├── QMUI │ │ │ ├── QMUIDeviceHelper.java │ │ │ ├── QMUIDisplayHelper.java │ │ │ ├── QMUILangHelper.java │ │ │ ├── QMUILog.java │ │ │ └── QMUIStatusBarHelper.java │ │ ├── ShareUtil.java │ │ ├── SharedPrefUtil.java │ │ ├── ThreadUtil.java │ │ ├── TimeUtil.java │ │ ├── ToastUtil.java │ │ ├── UserValidation.java │ │ ├── Utils.java │ │ ├── file │ │ │ ├── FileHelper.java │ │ │ └── UriHelper.java │ │ └── ui │ │ │ └── MyItemDecoration.java │ │ ├── webclient │ │ └── WebClient.java │ │ └── welcome │ │ └── WelcomeActivity.java │ └── res │ ├── drawable-hdpi │ ├── chatwindow_mesage_left.9.png │ ├── chatwindow_message_right.9.png │ └── goods_upload_icon.png │ ├── drawable-mdpi │ ├── chatwindow_mesage_left.9.png │ ├── chatwindow_message_right.9.png │ └── goods_upload_icon.png │ ├── drawable-v24 │ ├── user_detail.png │ ├── user_email.png │ ├── user_phone.png │ └── user_user.png │ ├── drawable-xhdpi │ ├── chatwindow_mesage_left.9.png │ ├── chatwindow_message_right.9.png │ └── goods_upload_icon.png │ ├── drawable-xxhdpi │ ├── chatwindow_mesage_left.9.png │ ├── chatwindow_message_right.9.png │ └── goods_upload_icon.png │ ├── drawable-xxxhdpi │ ├── chatwindow_mesage_left.9.png │ └── chatwindow_message_right.9.png │ ├── drawable │ ├── back.png │ ├── background.jpg │ ├── chatwindow_mesage_left.9.png │ ├── chatwindow_message_right.9.png │ ├── close.png │ ├── dark_gray.xml │ ├── divider.xml │ ├── ic_arrow_upward_black_24dp.xml │ ├── ic_camera.xml │ ├── ic_comment_message.xml │ ├── ic_community_comment.png │ ├── ic_community_in.png │ ├── ic_community_like_in.png │ ├── ic_community_like_side.png │ ├── ic_community_share_side.png │ ├── ic_community_side.png │ ├── ic_contacts_black_24dp.xml │ ├── ic_goods_details.xml │ ├── ic_goods_kinds.xml │ ├── ic_goods_location.xml │ ├── ic_goods_name.xml │ ├── ic_launcher_background.xml │ ├── ic_main_publish_new_community.xml │ ├── ic_main_publish_new_goods.xml │ ├── ic_mygoods_box.png │ ├── ic_photo.xml │ ├── ic_school.png │ ├── ic_school_black_24dp.xml │ ├── ic_search_black_24dp.xml │ ├── ic_talk_notalk.xml │ ├── item_selector.xml │ ├── login_logo.png │ ├── login_shape_user_rectangle.xml │ ├── main_community_btn_selector.xml │ ├── main_goods_btn_selector.xml │ ├── main_goods_in.png │ ├── main_goods_side.png │ ├── main_ic_search_grey_24dp.xml │ ├── main_ic_search_white_24dp.xml │ ├── main_icon.png │ ├── main_index_search.png │ ├── main_my_btn_selector.xml │ ├── main_my_in.png │ ├── main_my_side.png │ ├── main_publish.png │ ├── main_shape_search_rectangle.xml │ ├── main_talk_btn_selector.xml │ ├── main_talk_in.png │ ├── main_talk_side.png │ ├── main_text_color_selector.xml │ ├── my_data.png │ ├── my_mygoods.png │ ├── my_settings.png │ ├── photo_select.png │ ├── red.xml │ ├── trash.png │ ├── trash2.png │ ├── user_default_0.png │ ├── user_default_1.png │ ├── user_detail.png │ ├── user_email.png │ ├── user_no.png │ ├── user_phone.png │ ├── user_user.png │ ├── welcome_pic.png │ └── white.xml │ ├── layout │ ├── activity_publish_article.xml │ ├── chat_window_act.xml │ ├── chat_window_msg_item.xml │ ├── common_goods_recycle_item.xml │ ├── community_comment_include.xml │ ├── community_detail_comment_item.xml │ ├── goods_detail_act.xml │ ├── goods_detail_comment_item.xml │ ├── goods_detail_review_include.xml │ ├── goods_detail_seller_include.xml │ ├── goods_search_act.xml │ ├── goods_search_include.xml │ ├── goods_upload_act.xml │ ├── image_browser_act.xml │ ├── login_act.xml │ ├── main_act.xml │ ├── main_chat_list_contacts_item.xml │ ├── main_chat_list_frag.xml │ ├── main_community_article_content_activity.xml │ ├── main_community_frag.xml │ ├── main_community_frag_recycler_view_item.xml │ ├── main_goods_upload_frag.xml │ ├── main_index_frag.xml │ ├── main_index_viewpager_item.xml │ ├── main_my_infor_frag.xml │ ├── my_goods_act.xml │ ├── my_goods_recycle_item.xml │ ├── refresh_footer.xml │ ├── register_act.xml │ ├── settings_act.xml │ ├── user_info_act.xml │ ├── user_info_this_act.xml │ ├── user_info_this_edit_act.xml │ ├── user_info_this_pop_show_dialog.xml │ ├── web_client_act.xml │ └── welcome_act.xml │ ├── menu │ ├── common_action_bar.xml │ └── goods_detail_action_bar.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-v27 │ └── styles.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── goods_categories.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── file_paths.xml ├── bash.exe.stackdump ├── build.gradle ├── d ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | /.idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 前言 4 | 本项目做的是一个校园信息服务平台(主要做二手交易和社区信息服务),商业价值可能也不是那么大,
所以这个项目的主要价值还是提升自己的技术能力. 5 |
App 下载地址(稳定版) : 6 |
网盘地址: 7 | 8 | ### 一、代码结构 9 | ##### Java + MVVM-DataBinding + OKHttp + LitePal (现在Model层已经换成了Kotlin) 10 | 11 | > Gson 12 |
Luban 13 |
Glide 14 |
Matisse 15 |
UCrop 16 |
PhotoView 17 |
OKHttp 18 |
DataBinding 19 | 20 | 21 | 22 | 23 | ### 二、版本 24 | #### 版本 1.0 25 | + 已经完成了基本的商品系统、用户系统、IM系统、和部份社区系统 26 | 27 | #### 版本 1.1 28 | * 引入 Retrofit2 29 | * 用Thread Pool 来管理线程 30 | 31 | #### 下一计划版本 32 | * 用软件工程的方法写出正式的开发文档。 33 | * 引入RxJava RxKotlin 34 | 35 | 36 | ### 三、功能 37 | * 商品信息管理:分类浏览、上传、修改、删除、查看我的商品、商品评论的发布和删除 38 | * 用户信息管理:注册、登录、上传头像、修改资料 39 | * IM模块:发起聊天(单聊)、消息本地储存、IM消息接收基本功能(乱序处理、断线重连) 40 | * 社区模块:动态的发布和查看 41 | 42 | 43 | ### 四、项目地址 (Android Client) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /XML.patch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/XML.patch -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /src/androidTest 3 | /src/test -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file csName. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/assets/litepal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 21 | 22 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/articlecontent/ArticleContentActivityViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.articlecontent; 2 | 3 | import android.app.Activity; 4 | 5 | import com.lfork.a98620.lfree.base.BaseViewModel; 6 | import com.lfork.a98620.lfree.data.DataSource; 7 | import com.lfork.a98620.lfree.data.community.remote.CommunityRemoteDataSource; 8 | import com.lfork.a98620.lfree.main.community.CommunityCallback; 9 | 10 | public class ArticleContentActivityViewModel extends BaseViewModel { 11 | private Activity context; 12 | private int articleId; 13 | 14 | public ArticleContentActivityViewModel(Activity context, int articleId) { 15 | this.context = context; 16 | this.articleId = articleId; 17 | } 18 | 19 | public void loadData(CommunityCallback callback, boolean isRefresh) { 20 | new Thread(new Runnable() { 21 | @Override 22 | public void run() { 23 | 24 | if (articleId != -1) { 25 | CommunityRemoteDataSource.getINSTANCE().getCommentList(new DataSource.GeneralCallback() { 26 | @Override 27 | public void succeed(Object data) { 28 | if (isRefresh) { 29 | callback.callback(data, 2); 30 | } else { 31 | callback.callback(data, 1); 32 | } 33 | } 34 | 35 | @Override 36 | public void failed(String log) { 37 | callback.callback(null, 2); 38 | } 39 | }, articleId); 40 | } else { 41 | callback.callback(null, 2); 42 | } 43 | } 44 | }).start(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/articlecontent/CommunityComment.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.articlecontent; 2 | 3 | import com.lfork.a98620.lfree.base.BaseViewModel; 4 | 5 | public class CommunityComment extends BaseViewModel { 6 | private int articleId; 7 | private String comment; 8 | private String commentTime; 9 | private int reviewerId; 10 | private String reviewer; 11 | 12 | public void setArticleId(int articleId) { 13 | this.articleId = articleId; 14 | } 15 | 16 | public void setComment(String comment) { 17 | this.comment = comment; 18 | } 19 | 20 | public void setCommentTime(String commentTime) { 21 | this.commentTime = commentTime; 22 | } 23 | 24 | public void setReviewerId(int reviewerID) { 25 | this.reviewerId = reviewerID; 26 | } 27 | 28 | public int getArticleId() { 29 | return articleId; 30 | } 31 | 32 | public String getComment() { 33 | return comment; 34 | } 35 | 36 | public String getCommentTime() { 37 | return commentTime; 38 | } 39 | 40 | public int getReviewerId() { 41 | return reviewerId; 42 | } 43 | 44 | public String getReviewer() { 45 | return reviewer; 46 | } 47 | 48 | public void setReviewer(String reviewer) { 49 | this.reviewer = reviewer; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/articlecontent/CommunityCommentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.articlecontent; 2 | 3 | import android.databinding.DataBindingUtil; 4 | import android.databinding.ViewDataBinding; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.ViewGroup; 9 | 10 | import com.lfork.a98620.lfree.BR; 11 | import com.lfork.a98620.lfree.R; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | 17 | public class CommunityCommentAdapter extends RecyclerView.Adapter { 18 | 19 | private List viewModelList = new ArrayList<>(); 20 | 21 | public CommunityCommentAdapter(List viewModelList) { 22 | this.viewModelList = viewModelList; 23 | } 24 | 25 | @NonNull 26 | @Override 27 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 28 | return ViewHolder.create(LayoutInflater.from(parent.getContext()), parent, viewType); 29 | } 30 | 31 | @Override 32 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 33 | holder.bindTo(viewModelList.get(position)); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return viewModelList.size(); 39 | } 40 | 41 | static class ViewHolder extends RecyclerView.ViewHolder { 42 | 43 | ViewDataBinding binding; 44 | 45 | ViewHolder(ViewDataBinding binding) { 46 | super(binding.getRoot()); 47 | this.binding = binding; 48 | } 49 | 50 | static ViewHolder create(LayoutInflater inflater, ViewGroup parent, int type) { 51 | ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.community_detail_comment_item, parent, false); 52 | return new ViewHolder(binding); 53 | } 54 | 55 | void bindTo(CommunityComment itemViewModel) { 56 | binding.setVariable(BR.viewModel, itemViewModel); 57 | binding.executePendingBindings(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/articlecontent/LightTextView.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.articlecontent; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.LinearGradient; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.graphics.Shader; 10 | import android.support.v7.widget.AppCompatTextView; 11 | import android.util.AttributeSet; 12 | 13 | public class LightTextView extends AppCompatTextView { 14 | private int mViewWidth; 15 | private Paint mPaint; 16 | private LinearGradient mLinearGradient; 17 | private Matrix mGradientMatrix; 18 | private int mTranslate; 19 | 20 | public LightTextView(Context context) 21 | { 22 | super(context); 23 | } 24 | 25 | /** 26 | * 自定义TextView,一定要有这个构造方法 27 | * @param context 28 | * @param attrs 29 | */ 30 | public LightTextView(Context context, AttributeSet attrs) 31 | { 32 | super(context, attrs); 33 | } 34 | 35 | @Override 36 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 37 | 38 | super.onSizeChanged(w, h, oldw, oldh); 39 | if (mViewWidth == 0){ 40 | mViewWidth = getMeasuredWidth(); 41 | if (mViewWidth > 0){ 42 | mPaint = getPaint(); 43 | mLinearGradient = new LinearGradient( 44 | 0, 45 | 0, 46 | mViewWidth, 47 | 0, 48 | new int[]{ Color.BLUE, 0xffffffff, Color.BLUE }, 49 | null, Shader.TileMode.CLAMP 50 | ); 51 | mPaint.setShader(mLinearGradient); 52 | mGradientMatrix = new Matrix(); 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | protected void onDraw(Canvas canvas) { 59 | super.onDraw(canvas); 60 | if (mGradientMatrix != null){ 61 | mTranslate += mViewWidth/5; 62 | if (mTranslate > 2*mViewWidth){ 63 | mTranslate = -mViewWidth; 64 | } 65 | mGradientMatrix.setTranslate(mTranslate, 0); 66 | mLinearGradient.setLocalMatrix(mGradientMatrix); 67 | postInvalidateDelayed(100); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | 8 | /** 9 | * Created by 98620 on 2018/3/19. 10 | */ 11 | 12 | public abstract class BaseActivity extends AppCompatActivity { 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | Log.d("当前的activity的名称:", getClass().getName()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/BaseViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base; 2 | 3 | import android.content.Context; 4 | import android.databinding.BaseObservable; 5 | import android.databinding.ObservableBoolean; 6 | import android.support.annotation.CallSuper; 7 | 8 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 9 | 10 | /** 11 | * Created by 98620 on 2018/3/19. 12 | */ 13 | 14 | public abstract class BaseViewModel extends BaseObservable { 15 | 16 | public final ObservableBoolean dataIsLoading = new ObservableBoolean(true); 17 | 18 | public final ObservableBoolean dataIsEmpty = new ObservableBoolean(false); 19 | 20 | private Context context; 21 | 22 | private ViewModelNavigator navigator; 23 | 24 | public void start() { 25 | } 26 | 27 | /** 28 | * 释放掉一些东西,防止内存泄漏 29 | */ 30 | @CallSuper 31 | public void onDestroy() { 32 | navigator = null; 33 | } 34 | 35 | public BaseViewModel() { 36 | } 37 | 38 | public BaseViewModel(Context context) { 39 | this.context = context.getApplicationContext(); //force to use application context, avoid potential memory leak 40 | } 41 | 42 | public Context getContext() { 43 | return context; 44 | } 45 | 46 | public void setContext(Context context) { 47 | this.context = context; 48 | } 49 | 50 | /** 51 | * 52 | * @param navigator 自定义的navigator 必须是继承自{@link ViewModelNavigator} 53 | * 否则下面会报错 54 | * 继承自{@link ViewModelNavigator} 只有一个作用 ,通用的toast操作 55 | */ 56 | public void setNavigator(Object navigator){ 57 | this.navigator = (ViewModelNavigator) navigator; 58 | } 59 | 60 | // public abstract void showToast(); 大部分viewModel应该都有提示的操作:Toast,SnackBar,自定义提示等等 61 | public void showToast(String msg) { 62 | if (navigator != null) { 63 | navigator.showToast(msg); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/Config.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base; 2 | 3 | /** 4 | * Created by 98620 on 2018/4/7. 5 | */ 6 | 7 | public class Config { 8 | public static String ServerURL = "http://www.lfork.top"; 9 | 10 | public static String BaseURL = "http://www.lfork.top/"; 11 | 12 | public static String ServerImagePathRoot = "http://www.lfork.top/image/"; 13 | 14 | public static String ServerURLTest = "http://www.lfork.top"; 15 | 16 | public final static int BASE_THREAD_POOL_SIZE = 10; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/FreeApplication.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | import org.litepal.LitePal; 8 | 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.LinkedBlockingDeque; 12 | import java.util.concurrent.ThreadPoolExecutor; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Created by 98620 on 2018/3/19. 17 | */ 18 | 19 | public class FreeApplication extends Application implements MyApplication { 20 | 21 | public final static String APP_SHARED_PREF = "application_shared_pref"; 22 | 23 | private static ExecutorService executorService; 24 | 25 | /** 26 | * 这里因为是application context 所以就没有内存泄漏的问题, 27 | * 因为application的生命周期是最长的 28 | * application是最后被jvm释放掉的 29 | */ 30 | @SuppressLint("StaticFieldLeak") 31 | private static Context context; 32 | 33 | @Override 34 | public void onCreate() { 35 | super.onCreate(); 36 | context = getApplicationContext(); 37 | initDataBase(); 38 | initThreadPool(); 39 | } 40 | 41 | @Override 42 | public void initDataBase() { 43 | LitePal.initialize(context); 44 | } 45 | 46 | public static Context getContext() { 47 | return context; 48 | } 49 | 50 | public static void setContext(Context context) { 51 | FreeApplication.context = context; 52 | } 53 | 54 | 55 | /** 56 | * 57 | */ 58 | @Override 59 | public void initThreadPool() { 60 | executorService = new ThreadPoolExecutor( 61 | Config.BASE_THREAD_POOL_SIZE, 62 | Config.BASE_THREAD_POOL_SIZE * 2, 63 | 0L, 64 | TimeUnit.MICROSECONDS, 65 | new LinkedBlockingDeque<>(), 66 | Executors.defaultThreadFactory()); 67 | } 68 | 69 | public static ExecutorService getAppFixedThreadPool() { 70 | return executorService; 71 | } 72 | 73 | public static ExecutorService getDefaultThreadPool() { 74 | return executorService; 75 | } 76 | 77 | public static void executeThreadInDefaultThreadPool(Runnable r) { 78 | executorService.execute(r); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base; 2 | 3 | /** 4 | * 5 | * @author 98620 6 | * @date 2018/7/16 7 | */ 8 | public interface MyApplication { 9 | 10 | /** 11 | * 初始化当前应用(进程)的线程池 12 | */ 13 | void initThreadPool(); 14 | 15 | 16 | /** 17 | * 初始化数据库 18 | */ 19 | void initDataBase(); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/bindingadapter/ListBinding.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.bindingadapter; 2 | 3 | import android.databinding.BindingAdapter; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.widget.ListView; 6 | 7 | import com.lfork.a98620.lfree.base.adapter.ListViewAdapter; 8 | import com.lfork.a98620.lfree.base.adapter.RecyclerViewItemAdapter; 9 | 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * 通用的 ListView和RecyclerView的数据绑定 14 | * Created by 98620 on 2018/6/24. 15 | */ 16 | public class ListBinding { 17 | 18 | /** 19 | * 这个方法只适合一般需求的listView , 20 | * 并且adapter是用的通用adapter {@link com.lfork.a98620.lfree.base.adapter.ListViewAdapter} 21 | * 22 | * @param listView listView 23 | * @param viewModels 各种类型的viewModel 24 | */ 25 | @BindingAdapter({"setListViewItems"}) 26 | public static void refreshListView(ListView listView, ArrayList viewModels) { 27 | ListViewAdapter adapter = (ListViewAdapter) listView.getAdapter(); 28 | if (viewModels == null) { 29 | return; 30 | } 31 | if (adapter != null) { 32 | adapter.setItems(viewModels); 33 | adapter.notifyDataSetChanged(); 34 | } 35 | } 36 | 37 | @BindingAdapter({"setRecyclerViewItems"}) 38 | public static void refreshRecyclerView(RecyclerView listView, ArrayList viewModels) { 39 | RecyclerViewItemAdapter adapter = (RecyclerViewItemAdapter) listView.getAdapter(); 40 | if (viewModels == null) { 41 | return; 42 | } 43 | if (adapter != null) { 44 | adapter.setItems(viewModels); 45 | adapter.notifyDataSetChanged(); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/customview/PopupDialogOnclickListener.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.customview; 2 | 3 | /** 4 | * Created by 98620 on 2018/4/14. 5 | */ 6 | 7 | public interface PopupDialogOnclickListener { 8 | 9 | void onFirstButtonClicked(PopupDialog dialog); 10 | 11 | void onSecondButtonClicked(PopupDialog dialog); 12 | 13 | void onCanceledClicked(PopupDialog dialog); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/customview/RefreshFooterView.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.customview; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.widget.LinearLayout; 8 | 9 | import com.lfork.a98620.lfree.R; 10 | 11 | 12 | /** 13 | * Created by 98620 on 2018/5/5. recyclerView或是ListView下拉刷新时的页脚 14 | */ 15 | public class RefreshFooterView extends LinearLayout { 16 | public RefreshFooterView(Context context, @Nullable AttributeSet attrs) { 17 | super(context, attrs); 18 | LayoutInflater.from (context) . inflate (R.layout.refresh_footer, this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/image/GlideEngine.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.image; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.net.Uri; 6 | import android.widget.ImageView; 7 | 8 | import com.lfork.a98620.lfree.base.bindingadapter.ImageBinding; 9 | import com.zhihu.matisse.engine.ImageEngine; 10 | 11 | /** 12 | * Created by 98620 on 2018/4/14. 13 | */ 14 | 15 | 16 | public class GlideEngine implements ImageEngine { 17 | 18 | @Override 19 | public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { 20 | setImage(imageView, uri); 21 | } 22 | 23 | @Override 24 | public void loadAnimatedGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) { 25 | setImage(imageView, uri); 26 | } 27 | 28 | @Override 29 | public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { 30 | setImage(imageView, uri); 31 | } 32 | 33 | @Override 34 | public void loadAnimatedGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) { 35 | setImage(imageView, uri); 36 | } 37 | 38 | private void setImage(ImageView imageView, Uri uri){ 39 | ImageBinding.setImageWithDiskCache(imageView, uri); 40 | } 41 | 42 | 43 | @Override 44 | public boolean supportAnimatedGif() { 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/image/GlideImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.image; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.widget.ImageView; 6 | 7 | import com.lfork.a98620.lfree.base.bindingadapter.ImageBinding; 8 | import com.youth.banner.loader.ImageLoader; 9 | 10 | public class GlideImageLoader extends ImageLoader { 11 | @Override 12 | public void displayImage(Context context, Object path, ImageView imageView) { 13 | //Glide 加载图片简单用法 14 | if (isValidContextForGlide(context)) 15 | ImageBinding.setImageNoCache(imageView, path); 16 | } 17 | 18 | // final Context context = getContext(); 19 | //if (isValidContextForGlide(context) { 20 | // // Load image via Glide lib using context 21 | // } 22 | 23 | private static boolean isValidContextForGlide(final Context context) { 24 | if (context == null) { 25 | return false; 26 | } 27 | if (context instanceof Activity) { 28 | final Activity activity = (Activity) context; 29 | return !activity.isDestroyed() && !activity.isFinishing(); 30 | } 31 | return true; 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/image/ImageTool.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.image; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Build; 6 | import android.renderscript.Allocation; 7 | import android.renderscript.Element; 8 | import android.renderscript.RenderScript; 9 | import android.renderscript.ScriptIntrinsicBlur; 10 | import android.support.annotation.RequiresApi; 11 | import android.util.Log; 12 | 13 | /** 14 | * Created by 98620 on 2018/1/21. 15 | */ 16 | 17 | public class ImageTool { 18 | 19 | private static final String TAG = "ImageTool"; 20 | 21 | /** 22 | * 图片高斯化处理 23 | */ 24 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) 25 | public static Bitmap rsBlur(Context context, Bitmap source, int radius){ 26 | 27 | if (source == null) { 28 | return null; 29 | } 30 | //(1) 31 | RenderScript renderScript = RenderScript.create(context); 32 | 33 | Log.i(TAG,"scale size:"+ source.getWidth()+"*"+ source.getHeight()); 34 | 35 | // Allocate memory for Renderscript to work with 36 | //(2) 37 | final Allocation input = Allocation.createFromBitmap(renderScript, source); 38 | final Allocation output = Allocation.createTyped(renderScript,input.getType()); 39 | //(3) 40 | // Load up an instance of the specific script that we want to use. 41 | ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); 42 | //(4) 43 | scriptIntrinsicBlur.setInput(input); 44 | //(5) 45 | // Set the blur radius 46 | scriptIntrinsicBlur.setRadius(radius); 47 | //(6) 48 | // Start the ScriptIntrinisicBlur 49 | scriptIntrinsicBlur.forEach(output); 50 | //(7) 51 | // Copy the output to the blurred bitmap 52 | output.copyTo(source); 53 | //(8) 54 | renderScript.destroy(); 55 | return source; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/network/MyRetrofitCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.network 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import retrofit2.Call 5 | import retrofit2.Callback 6 | import retrofit2.Response 7 | 8 | /** 9 | * 10 | * Created by 98620 on 2018/9/12. 11 | * 12 | * 13 | */ 14 | class MyRetrofitCallBack(private val generalCallback: DataSource.GeneralCallback) : Callback> { 15 | override fun onFailure(call: Call>, t: Throwable) { 16 | generalCallback.failed("error:服务器异常、或者是没有网络连接") 17 | } 18 | 19 | override fun onResponse(call: Call>, response: Response>) { 20 | Result.deal(response.body() as Result, generalCallback) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/network/Result.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.network 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import com.lfork.a98620.lfree.data.DataSource 5 | 6 | /** 7 | * 8 | * Created by 98620 on 2018/9/12. 9 | */ 10 | 11 | /** 12 | * 对服务器返回结果的进行JSON封装处理 13 | * @author 98620 14 | */ 15 | class Result { 16 | 17 | @SerializedName("id") 18 | var code: Int = 0 19 | 20 | @SerializedName("msg") 21 | var message: String? = null 22 | 23 | var data: T? = null 24 | 25 | companion object { 26 | fun deal(result: Result?, callback: DataSource.GeneralCallback) { 27 | if (result != null) { 28 | val u = result.data 29 | if (u != null) { 30 | callback.succeed(u) 31 | } else { 32 | callback.failed(result.message?:"error") 33 | } 34 | } else { 35 | callback.failed("error") 36 | } 37 | } 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/thread/MyThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.thread; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.util.concurrent.ThreadFactory; 6 | 7 | /** 8 | * Created by 98620 on 2018/7/16. 9 | */ 10 | public class MyThreadFactory implements ThreadFactory { 11 | @Override 12 | public Thread newThread(@NonNull Runnable r) { 13 | 14 | Thread t = new Thread(r); 15 | 16 | t.setName("ThreadPool"); 17 | 18 | return null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/viewmodel/GoodsViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.viewmodel; 2 | 3 | import android.content.Context; 4 | import android.databinding.ObservableArrayList; 5 | import android.databinding.ObservableField; 6 | 7 | import com.lfork.a98620.lfree.base.BaseViewModel; 8 | import com.lfork.a98620.lfree.data.base.entity.Goods; 9 | import com.lfork.a98620.lfree.base.Config; 10 | 11 | /** 12 | * Created by 98620 on 2018/4/14. 13 | */ 14 | 15 | public abstract class GoodsViewModel extends BaseViewModel { 16 | 17 | 18 | public ObservableField imagePath = new ObservableField<>(); //封面图片 19 | 20 | public ObservableField name = new ObservableField<>(); 21 | 22 | public ObservableField publishDate = new ObservableField<>(); 23 | 24 | public ObservableField price = new ObservableField<>(); 25 | 26 | public ObservableField originPrice = new ObservableField<>(); 27 | 28 | public ObservableField description = new ObservableField<>(); 29 | 30 | public ObservableField type = new ObservableField<>(); 31 | 32 | public ObservableArrayList images = new ObservableArrayList<>(); 33 | 34 | 35 | private int id; 36 | 37 | private int categoryId; 38 | 39 | public GoodsViewModel(Context context, Goods g, int categoryId) { 40 | this(context, g); 41 | g.setCategoryId(categoryId); 42 | this.id = g.getId(); 43 | this.categoryId = categoryId; 44 | } 45 | 46 | 47 | public GoodsViewModel(Context context, Goods g) { 48 | super(context); 49 | name.set(g.getName()); 50 | price.set(g.getPrice() + "元"); 51 | imagePath.set(Config.ServerURL + "/image" + g.getCoverImagePath()); 52 | publishDate.set(g.getPublishDate()); 53 | id = g.getId(); 54 | categoryId = g.getCategoryId(); 55 | } 56 | 57 | public GoodsViewModel() { 58 | } 59 | 60 | public GoodsViewModel(Context context) { 61 | super(context); 62 | } 63 | 64 | 65 | public void onClick() { 66 | } 67 | 68 | ; 69 | 70 | public int getId() { 71 | return id; 72 | } 73 | 74 | public void setId(int id) { 75 | this.id = id; 76 | } 77 | 78 | public int getCategoryId() { 79 | return categoryId; 80 | } 81 | 82 | public void setCategoryId(int categoryId) { 83 | this.categoryId = categoryId; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/viewmodel/UserViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.viewmodel; 2 | 3 | import android.content.Context; 4 | import android.databinding.ObservableField; 5 | 6 | import com.lfork.a98620.lfree.base.BaseViewModel; 7 | 8 | /** 9 | * Created by 98620 on 2018/4/9. 10 | */ 11 | 12 | public abstract class UserViewModel extends BaseViewModel { 13 | 14 | public final ObservableField username = new ObservableField<>(); 15 | 16 | public final ObservableField description = new ObservableField<>(""); 17 | 18 | public final ObservableField imageUrl = new ObservableField<>(); 19 | 20 | public final ObservableField studentNumber = new ObservableField<>(""); 21 | 22 | public final ObservableField phone = new ObservableField<>(); 23 | 24 | public final ObservableField email = new ObservableField<>(""); 25 | 26 | public final ObservableField gender = new ObservableField<>(); 27 | 28 | public final ObservableField school = new ObservableField<>(); 29 | 30 | public UserViewModel() { 31 | super(); 32 | } 33 | 34 | public UserViewModel(Context context) { 35 | super(context); 36 | 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/base/viewmodel/ViewModelNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.base.viewmodel; 2 | 3 | /** 4 | * Created by 98620 on 2018/4/25. 5 | * 6 | * navigator 7 | */ 8 | public interface ViewModelNavigator { 9 | 10 | //大部分ViewModel 应该都有一个Toast的操作:不管是测试也好还是提示用户也行 11 | //I consider that most viewModels all have a need to send a Toast, for testing or giving tips to user 12 | void showToast(String msg); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/chatwindow/ChatWindowNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.chatwindow; 2 | 3 | import com.lfork.a98620.lfree.data.DataSource; 4 | import com.lfork.a98620.lfree.imservice.message.Message; 5 | 6 | /** 7 | * Created by 98620 on 2018/4/22. 8 | */ 9 | public interface ChatWindowNavigator { 10 | void sendMessage(Message message, DataSource.GeneralCallback callback); 11 | 12 | 13 | void showToast(String content); 14 | 15 | void notifyMessagesChanged(); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/chatwindow/MessageListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.chatwindow; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.LinearLayout; 9 | import android.widget.TextView; 10 | 11 | import com.lfork.a98620.lfree.R; 12 | import com.lfork.a98620.lfree.imservice.message.Message; 13 | 14 | import java.util.List; 15 | 16 | ///** 17 | // * Created by 98620 on 2017/7/25. 18 | // */ 19 | 20 | 21 | class MessageListAdapter extends RecyclerView.Adapter { 22 | private static final String TAG="MessageListAdapter"; 23 | private List mMessageList; 24 | 25 | class ViewHolder extends RecyclerView.ViewHolder { 26 | TextView msgView_sent, msgView_rec; 27 | LinearLayout msgView_sent_parent, msgView_rec_parent; 28 | 29 | ViewHolder(View view) { 30 | super(view); 31 | msgView_rec = view.findViewById(R.id.message_rec); 32 | msgView_rec_parent = view.findViewById(R.id.message_rec_parent); 33 | msgView_sent = view.findViewById(R.id.message_sent); 34 | msgView_sent_parent = view.findViewById(R.id.message_sent_parent); 35 | } 36 | } 37 | 38 | MessageListAdapter(List messageList) { 39 | mMessageList = messageList; 40 | } 41 | 42 | //对于listView的点击事件, 只能设置item的点击事件, 不能设置item的子项的点击事件 43 | 44 | @NonNull 45 | @Override 46 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 47 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_window_msg_item, parent, false); 48 | return new ViewHolder(view); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 53 | Message message = mMessageList.get(position); 54 | if (message.getChatType() == Message.ReceiveType) { 55 | 56 | //奇怪的操作 如果这里不设置隐藏属性的话 下面有些地方就会自动的跳出某些内容~~~~ 可是这些隐藏的属性我是默认就设置好了的呀 57 | holder.msgView_rec_parent.setVisibility(View.VISIBLE); 58 | holder.msgView_sent_parent.setVisibility(View.GONE); 59 | holder.msgView_rec.setText(message.getContent()); 60 | } else { 61 | holder.msgView_rec_parent.setVisibility(View.GONE); 62 | holder.msgView_sent_parent.setVisibility(View.VISIBLE); 63 | holder.msgView_sent.setText(message.getContent()); 64 | 65 | } 66 | 67 | } 68 | 69 | @Override 70 | public int getItemCount() { 71 | return mMessageList.size(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/DataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data 2 | 3 | /** 4 | * 5 | * Created by 98620 on 2018/8/30. 6 | */ 7 | interface DataSource { 8 | interface GeneralCallback { 9 | fun succeed(data: T) 10 | fun failed(log: String) 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/api/CommunityApi.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.api 2 | 3 | /** 4 | * 5 | * Created by 98620 on 2018/9/11. 6 | */ 7 | interface CommunityApi { 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/api/GoodsApi.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.api 2 | 3 | import android.util.Log 4 | import com.google.gson.reflect.TypeToken 5 | import com.lfork.a98620.lfree.base.Config 6 | import com.lfork.a98620.lfree.base.network.HttpService 7 | import com.lfork.a98620.lfree.base.network.Result 8 | import com.lfork.a98620.lfree.data.DataSource 9 | import com.lfork.a98620.lfree.data.base.entity.* 10 | import com.lfork.a98620.lfree.data.goods.remote.GoodsRemoteDataSource 11 | import com.lfork.a98620.lfree.util.JSONUtil 12 | import okhttp3.FormBody 13 | import okhttp3.MediaType 14 | import okhttp3.MultipartBody 15 | import okhttp3.RequestBody 16 | import retrofit2.Call 17 | import retrofit2.http.* 18 | import java.io.File 19 | import java.util.ArrayList 20 | 21 | /** 22 | * 23 | * Created by 98620 on 2018/9/11. 24 | */ 25 | interface GoodsApi { 26 | 27 | /** 28 | * 根据商品的种类和当前页面的用于定位的时间信息 @param cursor 来查询商品信息 29 | * 30 | * @param categoryId 商品种类id 31 | * @param cursor 当前显示商品的游标位置(商品的时间信息) 32 | * @return 返回的查询结果 33 | */ 34 | @GET("22y/goodsApp_getGoodsPageApp") 35 | fun getGoodsList(@Query("csId") categoryId: Int, @Query("cursor") cursor: String): Call>> 36 | 37 | 38 | @GET("22y/user_getUserGoodsByUid") 39 | fun getUserGoodsList(@Query("studentId") userId: String, @Query("cursor") cursor: String): Call>> 40 | 41 | 42 | @GET("22y/cs_getCsList") 43 | fun getUserGoodsList(): Call>> 44 | 45 | 46 | @GET("22y/goods_getGoodsById") 47 | fun getGoods(@Query("goodsId") goodsId: String): Call> 48 | 49 | 50 | @GET("22y/goodsSerach_getGoodsByName") 51 | fun goodsSearch(@Query("goodsLikeName") keyword: String): Call>> 52 | 53 | 54 | /** 55 | * 添加商品评论 56 | * 57 | * @param username studentId,email,username都行 58 | * @param password 密码 59 | * @return 指定请求数据的Call对象 60 | */ 61 | @FormUrlEncoded 62 | @POST("22y/review_reviewSave") 63 | fun addReview( 64 | @Field("userId") userId: String, 65 | @Field("goodsId") goodsId: String, 66 | @Field("reviewContext") content: String): Call> 67 | 68 | 69 | /** 70 | * 更新用户头像 单文件上传实例 71 | * Part的普通键值对需要用RequestBody来写 72 | * RequestBody.create(null, studentId) 73 | * @param fileBody . 74 | * @param studentId . 75 | * @return . 76 | */ 77 | @POST("22y/goods_upload") 78 | fun uploadGoods(@Body multipartBody: MultipartBody): Call> 79 | 80 | 81 | companion object { 82 | fun create(): GoodsApi { 83 | val retrofit = HttpService.getRetrofitInstance() 84 | return retrofit.create(GoodsApi::class.java) 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/api/UserApi.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.api 2 | 3 | import com.lfork.a98620.lfree.base.network.HttpService 4 | import com.lfork.a98620.lfree.base.network.Result 5 | import com.lfork.a98620.lfree.data.base.entity.User 6 | import okhttp3.MultipartBody 7 | import okhttp3.RequestBody 8 | import retrofit2.Call 9 | import retrofit2.http.* 10 | 11 | /** 12 | * 13 | * Created by 98620 on 2018/8/26. 14 | */ 15 | interface UserApi { 16 | 17 | /** 18 | * 用户登录 19 | * 20 | * @param username studentId,email,username都行 21 | * @param password 密码 22 | * @return 指定请求数据的Call对象 23 | */ 24 | @FormUrlEncoded 25 | @POST("22y/user_login") 26 | fun login( 27 | @Field("studentId") username: String, 28 | @Field("userPassword") password: String): Call> 29 | 30 | 31 | /** 32 | * 用户注册 33 | * 34 | * @param studentId . 35 | * @param password . 36 | * @param username . 37 | * @param schoolId . 38 | * @return 指定请求数据的Call对象 39 | */ 40 | @FormUrlEncoded 41 | @POST("22y/user_regist") 42 | fun register( 43 | @Field("studentId") studentId: String, 44 | @Field("userPassword") password: String, 45 | @Field("userName") username: String, 46 | @Field("userSchool.id") schoolId: String): Call> 47 | 48 | /** 49 | * 根据Id获取用户的完整信息 50 | * 51 | * @param userId . 52 | * @return . 53 | */ 54 | @GET("22y/user_info") 55 | fun getUserInfo(@Query("studentId") userId: String): Call> 56 | 57 | 58 | /** 59 | * 更新用户头像 单文件上传实例 60 | * Part的普通键值对需要用RequestBody来写 61 | * RequestBody.create(null, studentId) 62 | * @param fileBody . 63 | * @param studentId . 64 | * @return . 65 | */ 66 | @Multipart 67 | @POST("22y/user_imageUpload") 68 | fun updatePortrait( 69 | @Part fileBody: MultipartBody.Part, 70 | @Part("studentId") studentId: RequestBody): Call> 71 | 72 | /** 73 | * @param studentId . 74 | * @param username . 75 | * @param schoolId . 76 | * @param dec . 77 | * @param email . 78 | * @param phone . 79 | * @return . 80 | */ 81 | @FormUrlEncoded 82 | @POST("22y/user_save") 83 | fun updateUserInfo( 84 | @Field("studentId") studentId: Int, 85 | @Field("userName") username: String, 86 | @Field("userSchool.id") schoolId: String, 87 | @Field("userDesc") dec: String, 88 | @Field("userEmail") email: String, 89 | @Field("userPhone") phone: String 90 | ): Call> 91 | 92 | companion object { 93 | fun create() : UserApi { 94 | val retrofit = HttpService.getRetrofitInstance() 95 | return retrofit.create(UserApi::class.java) 96 | } 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/Category.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | import org.litepal.crud.DataSupport 4 | import java.io.Serializable 5 | 6 | /** 7 | * Created by 98620 on 2018/4/7. 8 | */ 9 | 10 | data class Category(val id: Int, val csId: Int, var csName: String?) : DataSupport(), Serializable -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/Goods.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | import java.io.Serializable 6 | 7 | /** 8 | * 9 | * Created by 98620 on 2018/3/31. 10 | */ 11 | 12 | open class Goods : Serializable { 13 | @SerializedName("gName") 14 | var name: String? = null 15 | 16 | @SerializedName("gId") 17 | var id: Int = 0 18 | 19 | @SerializedName("gBuyPrice") 20 | var originPrice: String? = null 21 | 22 | @SerializedName("gSellPrice") 23 | var price: String? = null 24 | 25 | @SerializedName("gCoverImage") 26 | var coverImagePath: String? = null 27 | 28 | var imagesPath: Array? = null 29 | 30 | @SerializedName("desc") 31 | var description: String? = null 32 | 33 | @SerializedName("userImage") 34 | var userPortraitPath: String? = null 35 | 36 | @SerializedName("gMakeDate") 37 | var publishDate: String? = null 38 | 39 | var userId: Int = 0 40 | 41 | var categoryId: Int = 0 42 | 43 | override fun toString(): String { 44 | return "【商品名称】:" + name + 45 | "\n【商品价格】:" + price + 46 | "\n【描述】:" + description + 47 | "\n更多详细信息,就赶快来下载L.Free吧 " + 48 | "\nhttp://www.lfork.top" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/GoodsDetailInfo.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | 6 | /** 7 | * 8 | * Created by 98620 on 2018/8/29. 9 | */ 10 | 11 | class GoodsDetailInfo : Goods() { 12 | 13 | @SerializedName("username") 14 | val sellerName: String? = null 15 | 16 | val images: Array? = null 17 | 18 | val reviews: ArrayList? = null 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/IMUser.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | /** 4 | * 5 | * Created by 98620 on 2018/8/29. 6 | */ 7 | class IMUser(val id: Int) { 8 | var username: String = "" 9 | var password: String = "" 10 | override fun toString(): String { 11 | return "[{\"username\":\"$username\",\"id\":\"$id\"}]" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/Review.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.io.Serializable 5 | 6 | /** 7 | * 8 | * Created by 98620 on 2018/8/29. 9 | */ 10 | class Review(@field:SerializedName("rContent") 11 | var content: String?) : Serializable { 12 | 13 | @SerializedName("gId") 14 | var goodsId: String? = null 15 | 16 | var user: User? = null 17 | 18 | var userId: String? = null 19 | 20 | @SerializedName("rMakeDate") 21 | var time: String? = null 22 | 23 | @SerializedName("rId") 24 | var id: Int = 0 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/School.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | /** 4 | * 5 | * Created by 98620 on 2018/8/29. 6 | */ 7 | class School(val id: String, val schoolName: String = "??") { 8 | override fun toString(): String { 9 | return schoolName 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/base/entity/User.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.base.entity 2 | 3 | import org.litepal.annotation.Column 4 | import org.litepal.crud.DataSupport 5 | 6 | /** 7 | * 8 | * Created by 98620 on 2018/8/29. 9 | */ 10 | class User : DataSupport { 11 | var id: Int = 0 //储存在本地数据库里面的id 12 | 13 | @Column(unique = true, defaultValue = "unknown") //啊啊啊 14 | var userId: Int = 0 //用户的ID 15 | 16 | var studentId: String? = null //userId == studentId 17 | 18 | var userName: String? = null //用户姓名 19 | 20 | var userPassword: String? = null //用户密码 21 | 22 | var userEmail: String? = null //用户邮箱地址 23 | 24 | var userPhone: String? = null //用户电话号码 25 | 26 | var userAddress: String? = null //用户的住址 27 | 28 | var userImagePath: String? = null //用户头像文件存放路径 29 | 30 | var userDesc: String? = null //用户描述 31 | 32 | var userMakeDate: String? = null //用户修改或者注册时间 33 | 34 | var userSchool: School? = null 35 | 36 | var timestamp: Long = 0 37 | 38 | var isLogin: Boolean = false 39 | 40 | var isChatUser: Boolean = false 41 | 42 | constructor() {} 43 | 44 | /** 45 | * 注册的时候用 46 | */ 47 | constructor(userName: String, userPassword: String, userEmail: String, userPhone: String, userAddress: String, 48 | userImagePath: String, userDesc: String, userMakeDate: String) { 49 | this.userName = userName 50 | this.userPassword = userPassword 51 | this.userEmail = userEmail 52 | this.userPhone = userPhone 53 | this.userAddress = userAddress 54 | this.userImagePath = userImagePath 55 | this.userDesc = userDesc 56 | this.userMakeDate = userMakeDate 57 | } 58 | 59 | override fun toString(): String { 60 | return ("User [userId=" + userId + ", userName=" + userName + ", userPassword=" + userPassword + ", userEmail=" 61 | + userEmail + ", userPhone=" + userPhone + ", userAddress=" + userAddress + ", userImagePath=" 62 | + userImagePath + ", userDesc=" + userDesc + ", userMakeDate=" + userMakeDate + "]") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/community/CommunityDataSource.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.community; 2 | 3 | import com.lfork.a98620.lfree.data.DataSource; 4 | 5 | public interface CommunityDataSource extends DataSource { 6 | void getArticleList(String fromTime, GeneralCallback callback); 7 | void getCommentList(GeneralCallback callback, int articleId); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/community/local/CommunityLocalDataSource.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.community.local; 2 | 3 | import com.lfork.a98620.lfree.articlecontent.CommunityComment; 4 | import com.lfork.a98620.lfree.data.community.CommunityDataSource; 5 | import com.lfork.a98620.lfree.main.community.CommunityArticle; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class CommunityLocalDataSource implements CommunityDataSource { 11 | 12 | private static List articleList = new ArrayList<>(); 13 | 14 | public static void setArticleList(List articleList) { 15 | if (articleList.size()!= 0) { 16 | CommunityLocalDataSource.articleList.addAll(articleList); 17 | } 18 | } 19 | 20 | public static List getArticleList() { 21 | return articleList; 22 | } 23 | 24 | @Override 25 | public void getArticleList(String fromTime, GeneralCallback callback) {} 26 | 27 | @Override 28 | public void getCommentList(GeneralCallback callback, int articleId) {} 29 | 30 | public static CommunityArticle getLocalArticle(int articlId) { 31 | CommunityArticle itemViewModel = null; 32 | for (CommunityArticle item : articleList) { 33 | if (item.getArticleId() == articlId) { 34 | itemViewModel = item; 35 | break; 36 | } 37 | } 38 | return itemViewModel; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/goods/GoodsDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.goods 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import com.lfork.a98620.lfree.data.base.entity.Category 5 | import com.lfork.a98620.lfree.data.base.entity.Goods 6 | import com.lfork.a98620.lfree.data.base.entity.GoodsDetailInfo 7 | import com.lfork.a98620.lfree.data.base.entity.Review 8 | 9 | /** 10 | * 11 | * Created by 98620 on 2018/9/2. 12 | */ 13 | interface GoodsDataSource : DataSource { 14 | fun getGoodsList(callback: DataSource.GeneralCallback>, cursor: String, categoryId: Int) 15 | 16 | fun getUserGoodsList(callback: DataSource.GeneralCallback>, cursor: String, userId: String) 17 | 18 | fun getCategories(callback: DataSource.GeneralCallback>) 19 | 20 | fun getGoods(callback: DataSource.GeneralCallback, goodsId: Int) 21 | 22 | fun uploadGoods(callback: DataSource.GeneralCallback, g: Goods) 23 | 24 | fun goodsSearch(callback: DataSource.GeneralCallback>, keyword: String) 25 | 26 | fun deleteGoods(callback: DataSource.GeneralCallback, goodsId: Int) 27 | 28 | fun updateGoods(callback: DataSource.GeneralCallback, g: Goods) 29 | 30 | fun addReview(callback: DataSource.GeneralCallback, review: Review) 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/goods/local/GoodsLocalDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.goods.local 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import com.lfork.a98620.lfree.data.base.entity.Category 5 | import com.lfork.a98620.lfree.data.base.entity.Goods 6 | import com.lfork.a98620.lfree.data.base.entity.GoodsDetailInfo 7 | import com.lfork.a98620.lfree.data.base.entity.Review 8 | import com.lfork.a98620.lfree.data.goods.GoodsDataSource 9 | import org.litepal.crud.DataSupport 10 | 11 | /** 12 | * 13 | * Created by 98620 on 2018/9/2. 14 | */ 15 | object GoodsLocalDataSource : GoodsDataSource { 16 | override fun getGoodsList(callback: DataSource.GeneralCallback>, cursor: String, categoryId: Int) { 17 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 18 | } 19 | 20 | override fun getUserGoodsList(callback: DataSource.GeneralCallback>, cursor: String, userId: String) { 21 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 22 | } 23 | 24 | override fun getGoods(callback: DataSource.GeneralCallback, goodsId: Int) { 25 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 26 | } 27 | 28 | override fun deleteGoods(callback: DataSource.GeneralCallback, goodsId: Int) { 29 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 30 | } 31 | 32 | override fun uploadGoods(callback: DataSource.GeneralCallback, g: Goods) { 33 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 34 | } 35 | 36 | override fun goodsSearch(callback: DataSource.GeneralCallback>, keyword: String) { 37 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 38 | } 39 | 40 | override fun updateGoods(callback: DataSource.GeneralCallback, g: Goods) { 41 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 42 | } 43 | 44 | override fun addReview(callback: DataSource.GeneralCallback, review: Review) { 45 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 46 | } 47 | 48 | fun destroyInstance() { 49 | //do nothing here 50 | } 51 | 52 | override fun getCategories(callback: DataSource.GeneralCallback>) { 53 | val categories = DataSupport.findAll(Category::class.java) 54 | if (categories != null) { 55 | callback.succeed(categories) 56 | } else { 57 | callback.failed("本地数据为空") 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/imdata/IMDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.imdata 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import com.lfork.a98620.lfree.data.base.entity.User 5 | import com.lfork.a98620.lfree.imservice.request.LoginListener 6 | 7 | /** 8 | * 9 | * Created by 98620 on 2018/9/3. 10 | */ 11 | 12 | interface IMDataSource : DataSource { 13 | 14 | /** 15 | * 登录成功后,客户端会马上请求用户的详细信息(当然,不包含密码)。 //TODO请求完毕后需要更新TCP本地连接的用户信息 16 | */ 17 | fun login(user: User, listener: LoginListener) 18 | 19 | fun logout(userId: Int, result: DataSource.GeneralCallback) 20 | 21 | fun getChatUserList(callback: DataSource.GeneralCallback>) 22 | 23 | fun addChatUser(user: User, callback: DataSource.GeneralCallback) 24 | 25 | fun addChatUser(user: User, isExisted: Boolean, callback: DataSource.GeneralCallback) 26 | 27 | fun removeChatUser(userId: Int, callback: DataSource.GeneralCallback>) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/imdata/MessageDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.imdata 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import com.lfork.a98620.lfree.data.DataSource.GeneralCallback 5 | import com.lfork.a98620.lfree.imservice.MessageListener 6 | import com.lfork.a98620.lfree.imservice.message.Message 7 | import com.lfork.a98620.lfree.imservice.message.MessageContentType 8 | 9 | /** 10 | * 11 | * Created by 98620 on 2018/9/3. 12 | */ 13 | interface MessageDataSource : DataSource { 14 | 15 | /** 16 | * 首次打开界面的时候,加载已有的Message list。 17 | * @param id 用户的id , Group的ID, 或是系统的ID 18 | * @param type [MessageContentType] 19 | * @param callback 回调 20 | */ 21 | fun getMessages(id: Int, type: MessageContentType, callback: GeneralCallback>) 22 | 23 | /** 24 | * 将最新的一条消息推送到view界面 , 25 | */ 26 | fun setMessageListener(listener: MessageListener) 27 | 28 | 29 | /** 30 | * 前台把数据储存到消息仓库和消息队列, 然后再由信使从消息仓库拿走消息 31 | * local 负责储存本地消息 remote负责把消息发送到服务器 32 | * @param msg 需要发送的消息 33 | * @param callback 回调 34 | */ 35 | fun saveAndSendMessage(msg: Message, callback: GeneralCallback) 36 | 37 | 38 | /** 39 | * 删除消息记录 40 | * @param id 用户的id , Group的ID, 或是系统的ID 41 | * @param type [MessageContentType] 42 | */ 43 | fun clearMessages(id: Int, type: MessageContentType) 44 | 45 | //消息队列与消息仓库 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/imdata/local/IMLocalDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.imdata.local 2 | 3 | import com.lfork.a98620.lfree.data.DataSource.GeneralCallback 4 | import com.lfork.a98620.lfree.data.base.entity.User 5 | import com.lfork.a98620.lfree.data.imdata.IMDataSource 6 | import com.lfork.a98620.lfree.imservice.request.LoginListener 7 | import org.litepal.crud.DataSupport 8 | 9 | /** 10 | * 11 | * Created by 98620 on 2018/9/3. 12 | */ 13 | 14 | class IMLocalDataSource : IMDataSource { 15 | 16 | /** 17 | * 伪单例、不需要线程同步、懒汉模式 18 | */ 19 | companion object { 20 | private var INSTANCE: IMLocalDataSource? = null 21 | fun getInstance(): IMLocalDataSource { 22 | if (INSTANCE == null) { 23 | INSTANCE = IMLocalDataSource() 24 | } 25 | return INSTANCE as IMLocalDataSource 26 | } 27 | 28 | fun destroyInstance() { 29 | INSTANCE = null 30 | } 31 | } 32 | 33 | override fun login(user: User, listener: LoginListener) { 34 | } 35 | 36 | override fun logout(userId: Int, callback: GeneralCallback) { 37 | } 38 | 39 | override fun getChatUserList(callback: GeneralCallback>) { 40 | val userList = DataSupport.where("ischatuser=1").order("timestamp desc").find(User::class.java) 41 | if (userList != null) { 42 | callback.succeed(userList) 43 | } else { 44 | callback.failed("没有数据") 45 | } 46 | } 47 | 48 | override fun addChatUser(user: User, callback: GeneralCallback) { 49 | user.isChatUser = true 50 | user.timestamp = System.currentTimeMillis() 51 | user.save() 52 | callback.succeed("添加成功") 53 | } 54 | 55 | override fun addChatUser(user: User, isExisted: Boolean, callback: GeneralCallback) { 56 | } 57 | 58 | override fun removeChatUser(userId: Int, callback: GeneralCallback>) { 59 | DataSupport.deleteAll(User::class.java, "userid = ?", userId.toString() + "") 60 | callback.succeed(emptyList()) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/imdata/local/MessageLocalDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.imdata.local 2 | 3 | import com.lfork.a98620.lfree.data.DataSource.GeneralCallback 4 | import com.lfork.a98620.lfree.data.imdata.MessageDataSource 5 | import com.lfork.a98620.lfree.imservice.MessageListener 6 | import com.lfork.a98620.lfree.imservice.message.Message 7 | import com.lfork.a98620.lfree.imservice.message.MessageContentType 8 | import org.litepal.crud.DataSupport 9 | import org.litepal.crud.callback.FindMultiCallback 10 | 11 | /** 12 | * 13 | * Created by 98620 on 2018/9/3. 14 | */ 15 | class MessageLocalDataSource : MessageDataSource { 16 | 17 | companion object { 18 | private var INSTANCE: MessageLocalDataSource? = null 19 | fun getInstance(): MessageLocalDataSource { 20 | if (INSTANCE == null) { 21 | INSTANCE = MessageLocalDataSource() 22 | } 23 | return INSTANCE as MessageLocalDataSource 24 | } 25 | 26 | fun destroyInstance() { 27 | INSTANCE = null 28 | } 29 | } 30 | 31 | override fun getMessages(id: Int, type: MessageContentType, callback: GeneralCallback>) { 32 | DataSupport.where("receiverid=? or senderid=?", id.toString() + "", id.toString() + "").order("messageID") //messageId 实际上是message生成的时间 System.currentTimeMillis() 33 | .findAsync(Message::class.java) 34 | .listen(object : FindMultiCallback { 35 | override fun onFinish(t: List) { 36 | 37 | if (t.size < 1) { 38 | callback.failed("没有消息记录") 39 | } else { 40 | callback.succeed(t as List) 41 | } 42 | } 43 | }) 44 | 45 | } 46 | 47 | override fun setMessageListener(listener: MessageListener) { 48 | //消息监听交给 remote进行处理 49 | } 50 | 51 | override fun saveAndSendMessage(msg: Message, callback: GeneralCallback) { 52 | msg.saveAsync().listen { success -> 53 | if (success) { 54 | callback.succeed(Message()) 55 | } else { 56 | callback.failed("消息重复") 57 | } 58 | } 59 | 60 | } 61 | 62 | override fun clearMessages(id: Int, type: MessageContentType) { 63 | 64 | } 65 | 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/user/UserDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.user 2 | 3 | import com.lfork.a98620.lfree.data.DataSource 4 | import com.lfork.a98620.lfree.data.DataSource.GeneralCallback 5 | import com.lfork.a98620.lfree.data.base.entity.School 6 | import com.lfork.a98620.lfree.data.base.entity.User 7 | 8 | /** 9 | * 10 | * Created by 98620 on 2018/8/30. 11 | */ 12 | interface UserDataSource : DataSource{ 13 | /** 14 | * apply an account 15 | * @param callback call back with string result 16 | * @param user user information 17 | */ 18 | fun register(callback: GeneralCallback, user: User) 19 | 20 | /** 21 | * update user information 22 | * @param callback call back with string result 23 | * @param user user information 24 | */ 25 | fun updateUserInfo(callback: GeneralCallback, user: User) 26 | 27 | /** 28 | * update user photo 29 | * @param callback call back with string result 30 | * @param studentId user id 31 | * @param localFilePath local file path 32 | */ 33 | fun updateUserPortrait(callback: GeneralCallback, studentId: String, localFilePath: String) 34 | 35 | /** 36 | * do login 37 | * @param callback call back with User object 38 | * @param user user information 39 | */ 40 | fun login(callback: GeneralCallback, user: User) 41 | 42 | /** 43 | * 获取用户信息 userId为-1的时候表示获取当前用户信息 44 | * 当前用户信息需要存放在本地数据库(只保存部份关键信息) 45 | * @param callback . 46 | * @param userId userId 47 | */ 48 | fun getUserInfo(callback: GeneralCallback, userId: Int) 49 | 50 | /** 51 | * get schools information 52 | * @param callback call back with userSchool information list. 53 | */ 54 | fun getSchoolList(callback: GeneralCallback>) 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/data/user/local/UserLocalDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.data.user.local 2 | 3 | import android.util.Log 4 | import com.lfork.a98620.lfree.data.DataSource 5 | import com.lfork.a98620.lfree.data.base.entity.School 6 | import com.lfork.a98620.lfree.data.base.entity.User 7 | import com.lfork.a98620.lfree.data.user.UserDataSource 8 | import org.litepal.crud.DataSupport 9 | 10 | /** 11 | * 12 | * Created by 98620 on 2018/8/30. 13 | */ 14 | object UserLocalDataSource : UserDataSource { 15 | 16 | private val TAG = "IMRemoteDataSource" 17 | 18 | fun destroyInstance() { 19 | //do nothing here 20 | } 21 | 22 | override fun login(callback: DataSource.GeneralCallback, user: User) {} 23 | 24 | override fun register(callback: DataSource.GeneralCallback, user: User) { 25 | //do nothing here 26 | } 27 | 28 | fun getThisUser(callback: DataSource.GeneralCallback) { 29 | val userList = DataSupport.where("isLogin=?", "1").find(User::class.java) 30 | var user: User? = null 31 | if (userList != null && userList.size > 0) { 32 | user = userList[0] 33 | } 34 | 35 | if (user != null) { 36 | callback.succeed(user) 37 | } else { 38 | callback.failed("没有用户") 39 | } 40 | } 41 | 42 | fun saveThisUser(user: User): Boolean { 43 | try { 44 | DataSupport.deleteAll(User::class.java, "islogin=0 and userid=? ", user.userId.toString() + "") 45 | val result = user.save() 46 | Log.d(TAG, "saveThisUser: 用户信息本地更新成功$result") 47 | return result 48 | } catch (e: Exception) { 49 | return false 50 | } 51 | 52 | } 53 | 54 | override fun updateUserInfo(callback: DataSource.GeneralCallback, user: User) { 55 | 56 | try { 57 | DataSupport.deleteAll(User::class.java, "islogin=0 and userid=? ", user.userId.toString() + "") 58 | val result = user.save() 59 | Log.d(TAG, "saveThisUser: 用户信息本地更新成功$result") 60 | } catch (e: Exception) { 61 | } 62 | 63 | user.update(user.id.toLong()) 64 | } 65 | 66 | override fun updateUserPortrait(callback: DataSource.GeneralCallback, studentId: String, localFilePath: String) { 67 | 68 | } 69 | 70 | override fun getUserInfo(callback: DataSource.GeneralCallback, userId: Int) { 71 | val list = DataSupport.where("userid=?", userId.toString() + "").find(User::class.java) 72 | if (list != null && list.size > 0) { 73 | callback.succeed(list[0]) 74 | } else { 75 | callback.failed("没有数据") 76 | } 77 | } 78 | 79 | override fun getSchoolList(callback: DataSource.GeneralCallback>) { 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/goodsdetail/GoodsDetailNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.goodsdetail; 2 | 3 | import android.databinding.ObservableArrayList; 4 | 5 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 6 | 7 | import java.util.ArrayList; 8 | 9 | /** 10 | * Created by 98620 on 2018/5/9. 11 | */ 12 | public interface GoodsDetailNavigator extends ViewModelNavigator{ 13 | 14 | /** 15 | * 这里主要是把View下滑到最后一行 16 | */ 17 | void notifyReviewChanged(); 18 | 19 | void closeSoftKeyBoard(); 20 | 21 | void openUserInfo(int userId); 22 | 23 | void openChatWindow(String s, int userId); 24 | 25 | void openBigImages(ObservableArrayList images, int position); 26 | 27 | void refreshBanner(ArrayList images); 28 | 29 | void setActionBar(); 30 | 31 | void shareGoods(String str); 32 | 33 | void deleteGoods(boolean succeed); 34 | 35 | void deleteReview(boolean succeed, int reviewId); 36 | 37 | void updateGoods(int goodsId); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/goodsdetail/ReviewItemViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.goodsdetail; 2 | 3 | import android.databinding.ObservableBoolean; 4 | import android.databinding.ObservableField; 5 | import android.databinding.ObservableInt; 6 | 7 | import com.lfork.a98620.lfree.base.BaseViewModel; 8 | import com.lfork.a98620.lfree.data.base.entity.Review; 9 | import com.lfork.a98620.lfree.data.user.UserDataRepository; 10 | import com.lfork.a98620.lfree.base.Config; 11 | 12 | import java.lang.ref.WeakReference; 13 | 14 | /** 15 | * Created by 98620 on 2018/6/13. 16 | */ 17 | public class ReviewItemViewModel extends BaseViewModel{ 18 | 19 | public final ObservableField userPortraitPath = new ObservableField<>(); 20 | 21 | public final ObservableField index = new ObservableField<>(); //review id 22 | 23 | public final ObservableField reviewerName = new ObservableField<>(); 24 | 25 | public final ObservableField content = new ObservableField<>(); 26 | 27 | public final ObservableField time = new ObservableField<>(); 28 | 29 | public final ObservableBoolean isReviewedByThisUser = new ObservableBoolean(false); 30 | 31 | public final ObservableInt id = new ObservableInt(); 32 | 33 | private WeakReference navigator ; 34 | 35 | ReviewItemViewModel(Review review, GoodsDetailNavigator navigator) { 36 | this.navigator = new WeakReference<>(navigator); 37 | userPortraitPath.set(Config.ServerURL + "/image/" + review.getUser().getUserImagePath()); 38 | index.set(review.getGoodsId()); 39 | reviewerName.set(review.getUser().getUserName()); 40 | time.set(review.getTime()); 41 | content.set(review.getContent()); 42 | id.set(review.getId()); 43 | int reviewerId = review.getUser().getUserId(); 44 | if (reviewerId == UserDataRepository.INSTANCE.getUserId()) { 45 | isReviewedByThisUser.set(true); 46 | } 47 | } 48 | 49 | 50 | public void deleteReview(){ 51 | if (navigator != null && navigator.get() != null) { 52 | navigator.get().deleteReview(true, id.get()); 53 | } 54 | 55 | } 56 | 57 | @Override 58 | public void setNavigator(Object navigator) { 59 | super.setNavigator(navigator); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/goodsuploadupdate/GoodsCategoriesBinding.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.goodsuploadupdate; 2 | 3 | import android.databinding.BindingAdapter; 4 | import android.widget.ArrayAdapter; 5 | import android.widget.Spinner; 6 | 7 | import com.lfork.a98620.lfree.data.base.entity.Category; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by 98620 on 2018/6/2. 13 | */ 14 | public class GoodsCategoriesBinding { 15 | private static final String TAG = "GoodsListBinding"; 16 | @SuppressWarnings("unchecked") 17 | @BindingAdapter("categories_items") 18 | public static void setItems(Spinner spinner, List items) { 19 | ArrayAdapter arrayAdapter = new ArrayAdapter(spinner.getContext(), android.R.layout.simple_spinner_dropdown_item, items); 20 | spinner.setAdapter(arrayAdapter); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/goodsuploadupdate/GoodsUploadUpdateNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.goodsuploadupdate; 2 | 3 | import android.net.Uri; 4 | 5 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by 98620 on 2018/5/28. 11 | */ 12 | public interface GoodsUploadUpdateNavigator extends ViewModelNavigator { 13 | void uploadSucceed(String msg); 14 | 15 | void uploadFailed(String log); 16 | 17 | void deleteImage(int index); 18 | 19 | void showMyDialog(int count); 20 | 21 | void setDefaultCategory(int category); 22 | 23 | void setImages(List images); 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imagebrowser/ImageBrowserActivity.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imagebrowser; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.MenuItem; 9 | 10 | import com.github.chrisbanes.photoview.PhotoView; 11 | import com.lfork.a98620.lfree.R; 12 | import com.lfork.a98620.lfree.base.bindingadapter.ImageBinding; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Objects; 16 | 17 | /** 18 | * 图片浏览器 19 | */ 20 | public class ImageBrowserActivity extends AppCompatActivity { 21 | 22 | 23 | private ArrayList urls; 24 | private int position; 25 | 26 | private PhotoView photoView; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.image_browser_act); 32 | Intent intent = getIntent(); 33 | position = intent.getIntExtra("position", 0); 34 | Bundle bundle = intent.getBundleExtra("bundle"); 35 | urls = bundle.getStringArrayList("urls"); 36 | photoView = findViewById(R.id.big_image); 37 | 38 | if (urls != null && urls.size() > 0) { 39 | ImageBinding.setImageNoCache(photoView, urls.get(position)); 40 | } 41 | 42 | setupActionBar(); 43 | } 44 | 45 | 46 | private void setupActionBar(){ 47 | ActionBar actionBar = getSupportActionBar(); 48 | Objects.requireNonNull(actionBar).setDisplayShowTitleEnabled(true); 49 | actionBar.setTitle("原图查看"); 50 | actionBar.setDisplayHomeAsUpEnabled(true); // 决定左上角图标的右侧是否有向左的小箭头, true 51 | // 有小箭头,并且图标可以点击 52 | actionBar.setDisplayShowHomeEnabled(false); 53 | } 54 | 55 | @Override 56 | public boolean onOptionsItemSelected(MenuItem item) { 57 | 58 | switch (item.getItemId()) { 59 | case android.R.id.home: 60 | finish(); 61 | break; 62 | default: 63 | break; 64 | } 65 | return super.onOptionsItemSelected(item); 66 | } 67 | 68 | 69 | public static void actionStart(Context context, ArrayList urls, int position){ 70 | Intent intent = new Intent(context, ImageBrowserActivity.class); 71 | Bundle bundle = new Bundle(); 72 | bundle.putStringArrayList("urls", urls); 73 | intent.putExtra("bundle", bundle); 74 | intent.putExtra("position", position); 75 | context.startActivity(intent); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/Config.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice; 2 | 3 | public class Config { 4 | // public static String URL = "192.168.1.228"; 5 | // public static String URL = "192.168.1.63"; 6 | public static String URL = "www.lfork.top"; // 7 | 8 | private static boolean connected; //这个同tcp 的 connected保持一致 9 | 10 | public static boolean isConnected() { 11 | return connected; 12 | } 13 | 14 | public static void setConnected(boolean connected) { 15 | Config.connected = connected; 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/MessageListener.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice; 2 | 3 | ///** 4 | // * Created by 98620 on 2017/8/18. 5 | // */ 6 | 7 | import com.lfork.a98620.lfree.imservice.message.Message; 8 | 9 | public interface MessageListener { 10 | void onReceived(Message message); 11 | // void onSuccess(); 12 | // void onFailure(); 13 | // void onCanceled(); 14 | // void onPaused(); 15 | // void onProgress(int progress); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/MessageTask.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.lfork.a98620.lfree.imservice.message.Message; 6 | 7 | ///** 8 | // * Created by 98620 on 2017/8/18. 9 | // */ 10 | 11 | class MessageTask extends AsyncTask { 12 | 13 | private static final String TAG = "DownloadTask"; 14 | private long downloadedLength = 0; 15 | private static final int TYPE_SUCCESS = 0; 16 | private static final int TYPE_FAILED = 1; 17 | private static final int TYPE_PAUSED = 2; 18 | private static final int TYPE_CANCELED = 3; 19 | private static final int TYPE_DOWNLOADING = 4; 20 | private int DownloadStatus = TYPE_DOWNLOADING; 21 | 22 | private MessageListener listener; 23 | private boolean isCanceled = false; 24 | private boolean isPaused = false; 25 | private int lastProgress; 26 | private String address ; 27 | 28 | 29 | //传入参数为下载监听器, 随时监听下载任务的状态, 结合 publishProgress 和 onProgressUpdate 进行 UI刷新 30 | MessageTask(MessageListener listener, String address) { 31 | this.listener = listener; 32 | this.address = address; 33 | } 34 | 35 | @Override 36 | protected Integer doInBackground(String... strings) { 37 | return 0; 38 | } 39 | 40 | //在这里进行UI更新的调用。 配合listener 对下载过程中的状态进行监控 paused 41 | @Override 42 | protected void onProgressUpdate(Message... values) { 43 | super.onProgressUpdate(values); 44 | Message msg = values[0]; 45 | if (msg != null) { 46 | listener.onReceived(msg); 47 | } 48 | } 49 | 50 | 51 | //下载任务完毕后(Success Failure Canceled) 就执行这个方法 。 配合listener对下载完毕的状态进行监控 52 | @Override 53 | protected void onPostExecute(Integer status) { 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/UDPMessageMaid.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice; 2 | 3 | import android.util.Log; 4 | 5 | import com.lfork.a98620.lfree.data.imdata.remote.MessageRemoteDataSource; 6 | import com.lfork.a98620.lfree.imservice.message.Message; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 需要将服务器发来的消息进行分发。 分发给Repository 12 | */ 13 | public class UDPMessageMaid extends Thread { 14 | 15 | private static final String TAG = "UDPMessageMaid"; 16 | 17 | private boolean running; 18 | 19 | private MessageRemoteDataSource dataSource; 20 | 21 | private List messageReceiveQueue; //待处理的消息 22 | 23 | public UDPMessageMaid(MessageRemoteDataSource dataSource, List messageReceiveQueue) { 24 | this.dataSource = dataSource; 25 | this.messageReceiveQueue = messageReceiveQueue; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | Message message = null; 31 | setRunning(true); 32 | while (isRunning()) { 33 | Log.d(TAG, "run: UDPMaid运行中"); 34 | while (message == null) { 35 | if (messageReceiveQueue.size() > 0 && dataSource.getListener() != null) { 36 | message = messageReceiveQueue.remove(0); 37 | } else { 38 | try { 39 | sleep(100); //适当休眠,降低cpu负载 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | //处理信息:储存 + 发送 46 | dealMessage(message); 47 | message = null; 48 | } 49 | 50 | Log.d(TAG, "run: UDPMaid任务结束"); 51 | } 52 | 53 | /** 54 | * 把接收到的消息进行分类储存 ,信息记录(聊天记录). 信息记录 。然后再把这条消息发给接收者。 55 | * 先这样,先不管储存的事情,而是先把消息推送到前台 56 | * 57 | * @param message 58 | */ 59 | private void dealMessage(Message message) { 60 | dataSource.pushMessage(message); 61 | } 62 | 63 | /** 64 | * 如果客户端下线了, 那么就需要释放客户端在服务器所对应的处理线程 65 | */ 66 | public void close() { 67 | //这里需要将 clientID 和 messageQueue里面的内容进行保存 68 | setRunning(false); 69 | } 70 | 71 | 72 | public boolean isRunning() { 73 | return running; 74 | } 75 | 76 | private void setRunning(boolean running) { 77 | this.running = running; 78 | } 79 | 80 | public void addMessage(Message message) { 81 | messageReceiveQueue.add(message); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/message/Message.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.message; 2 | 3 | 4 | import com.lfork.a98620.lfree.util.JSONUtil; 5 | 6 | import org.litepal.annotation.Column; 7 | import org.litepal.crud.DataSupport; 8 | 9 | public class Message extends DataSupport{ 10 | 11 | private int senderID; //System的ID 为 0 , 如果是group(messageType为Group)的话, 这里的SenderID就是groupID 12 | 13 | private int receiverID; 14 | 15 | /** 16 | * messageId 实际上是message生成的时间 System.currentTimeMillis() 17 | */ 18 | @Column(unique = true, defaultValue = "unknown") 19 | private long messageID; 20 | 21 | private String content; 22 | 23 | private MessageStatus status; 24 | 25 | private MessageContentType contentType; 26 | 27 | private MessageType type; 28 | 29 | private int chatType; 30 | public final static int SendType = 0, ReceiveType = 1; 31 | 32 | public Message(String content, int chatType){ 33 | this.content = content; 34 | this.chatType = chatType; 35 | } 36 | 37 | public Message() { 38 | } 39 | 40 | 41 | public int getChatType(){ 42 | return chatType; 43 | } 44 | 45 | public void setChatType(int chatType) { 46 | this.chatType = chatType; 47 | } 48 | 49 | public MessageType getType() { 50 | return type; 51 | } 52 | 53 | public void setType(MessageType type) { 54 | this.type = type; 55 | } 56 | 57 | public int getSenderID() { 58 | return senderID; 59 | } 60 | 61 | public void setSenderID(int senderID) { 62 | this.senderID = senderID; 63 | } 64 | 65 | public int getReceiverID() { 66 | return receiverID; 67 | } 68 | 69 | public void setReceiverID(int receiverID) { 70 | this.receiverID = receiverID; 71 | } 72 | 73 | public long getMessageID() { 74 | return messageID; 75 | } 76 | 77 | public void setMessageID(long messageID) { 78 | this.messageID = messageID; 79 | } 80 | 81 | public String getContent() { 82 | return content; 83 | } 84 | 85 | public void setContent(String content) { 86 | this.content = content; 87 | } 88 | 89 | public MessageContentType getContentType() { 90 | return contentType; 91 | } 92 | 93 | public void setContentType(MessageContentType contentType) { 94 | this.contentType = contentType; 95 | } 96 | 97 | public MessageStatus getStatus() { 98 | return status; 99 | } 100 | 101 | public void setStatus(MessageStatus status) { 102 | this.status = status; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return JSONUtil.toJson(this); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/message/MessageContentType.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.message; 2 | 3 | public enum MessageContentType{ 4 | COMMUNICATION_USER , //用户的聊天信息(单纯的字符串) 5 | 6 | COMMUNICATION_GROUP, //群组的聊天信息(单纯的字符串) 7 | 8 | COMMAND, //系统命令(可见或者不可见) 9 | 10 | NOTIFICATION //系统通知_好友添加的请求 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/message/MessageHelper.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.message; 2 | 3 | import com.google.gson.reflect.TypeToken; 4 | import com.lfork.a98620.lfree.util.JSONUtil; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.DatagramPacket; 8 | 9 | public class MessageHelper { 10 | // public static UDPConnectionInfo UDPConnectionInfoParse(DatagramPacket dgp) { 11 | // InetAddress address = dgp.getAddress(); 12 | // int port = dgp.getPort(); 13 | // return new UDPConnectionInfo(address, port); 14 | // } 15 | 16 | public static Message messageParse(DatagramPacket dgp) { 17 | // Message message = null; 18 | // 19 | // byte[] bs = new byte[1000]; 20 | // 21 | // DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dgp.getData(), 0, dgp.getLength())); 22 | // 23 | // String msg = null; 24 | // try { 25 | // while (dis.available() > 0) { 26 | // // reads characters encoded with modified UTF-8 27 | // int index = dis.read(bs); 28 | // msg = Arrays.toString(bs); 29 | // // print 30 | // print( msg + " "); 31 | // } 32 | // 33 | // } catch (IOException e) { 34 | // e.printStackTrace(); 35 | // } 36 | // 37 | // 38 | // //不对这里还需要将 字符串的message解析为Message对象才行 39 | // // String str = new String(dgp.getData(), 0, dgp.getLength(), "utf-8"); 40 | // print("UDPConnection.startReceiveListener(): 接收到的信息:" + msg); 41 | // message = JSONUtil.parseJson(msg, new TypeToken() { 42 | // }); 43 | // 44 | // //不对这里还需要将 字符串的message解析为Message对象才行 45 | // return message; 46 | //// 47 | Message message = null; 48 | try { 49 | String str = new String(dgp.getData(), 0, dgp.getLength(), "utf-8"); 50 | // print("UDPConnection.startReceiveListener(): 接收到的信息:" + str ); 51 | message = JSONUtil.parseJson(str, new TypeToken(){}); 52 | } catch (UnsupportedEncodingException e) { 53 | e.printStackTrace(); 54 | } 55 | 56 | //不对这里还需要将 字符串的message解析为Message对象才行 57 | return message; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/message/MessageStatus.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.message; 2 | 3 | public enum MessageStatus{ 4 | SENT, 5 | 6 | SENT_FAILED, 7 | 8 | SENDING, 9 | 10 | RECEIVED; 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/message/MessageType.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.message; 2 | 3 | public enum MessageType { 4 | FEEDBACK, 5 | CONNECTION_INFO, 6 | NORMAL_MESSAGE 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/request/LoginListener.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.request; 2 | 3 | import com.lfork.a98620.lfree.data.base.entity.User; 4 | 5 | public interface LoginListener { 6 | void succeed(User user); 7 | // void passwordError(); 8 | // 9 | // void noSuchUser(); 10 | // 11 | // void connectError(); 12 | void failed(String log); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/request/RegisterListener.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.request; 2 | 3 | public interface RegisterListener { 4 | void succeed(); 5 | 6 | void failed(String log); 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/request/Result.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.request; 2 | 3 | public class Result { 4 | 5 | private int code; 6 | 7 | private String message; 8 | 9 | private T data; 10 | 11 | public int getCode() { 12 | return code; 13 | } 14 | 15 | public void setCode(int code) { 16 | this.code = code; 17 | } 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public T getData() { 28 | return data; 29 | } 30 | 31 | public void setData(T data) { 32 | this.data = data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/imservice/request/UserRequestType.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.imservice.request; 2 | 3 | /** 4 | * 这个文件在客户端和服务器需要保持一致 5 | */ 6 | public enum UserRequestType { 7 | 8 | DO_LOGIN(0), 9 | 10 | DO_REGISTER(1), 11 | 12 | DO_LOGOUT(15), 13 | 14 | GET_USER_INFO(2), 15 | 16 | UPDATE_USER_INFO(3), 17 | 18 | ADD_FRIEND(4), 19 | 20 | DELETE_FRIEND(5), 21 | 22 | GET_FRIEND_INFO(6), 23 | 24 | UPDATE_FRIEND_INFO(7), 25 | 26 | ADD_GROUP(8), 27 | 28 | DELETE_GROUP(9), 29 | 30 | UPDATE_GROUP(10), 31 | 32 | STRAT_MESSAGE_LISTENER(11), 33 | 34 | GET_FRIEND_LIST(12), 35 | 36 | GET_USERS(13), 37 | 38 | ALIVE_TEST(14); 39 | 40 | private int value; 41 | 42 | UserRequestType(int i) { 43 | this.value = i; 44 | } 45 | 46 | public void setValue(int value) { 47 | this.value = value; 48 | } 49 | 50 | public int getValue() { 51 | return value; 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/login/LoginNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.login; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | /** 6 | * 7 | * @author 98620 8 | * @date 2018/7/11 9 | */ 10 | public interface LoginNavigator extends ViewModelNavigator { 11 | void loginSucceed(); 12 | 13 | void loginFailed(String log); 14 | 15 | void openRegisterAct(); 16 | 17 | void openForgetPasswordAct(); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/chatlist/ChatListFragmentViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.chatlist; 2 | 3 | import android.content.Context; 4 | import android.databinding.ObservableArrayList; 5 | import android.databinding.ObservableBoolean; 6 | 7 | import com.lfork.a98620.lfree.base.BaseViewModel; 8 | import com.lfork.a98620.lfree.base.FreeApplication; 9 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 10 | import com.lfork.a98620.lfree.data.DataSource; 11 | import com.lfork.a98620.lfree.data.base.entity.User; 12 | import com.lfork.a98620.lfree.data.imdata.IMDataRepository; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by 98620 on 2018/3/31. 19 | */ 20 | 21 | public class ChatListFragmentViewModel extends BaseViewModel { 22 | 23 | public final ObservableArrayList mItems = new ObservableArrayList<>(); 24 | 25 | public final ObservableBoolean dataIsLoading = new ObservableBoolean(true); 26 | 27 | public final ObservableBoolean dataIsEmpty = new ObservableBoolean(true); 28 | 29 | private IMDataRepository repository; 30 | 31 | private ViewModelNavigator navigator; 32 | 33 | ChatListFragmentViewModel(Context context) { 34 | super(context); 35 | } 36 | 37 | private void getChatList() { 38 | FreeApplication.executeThreadInDefaultThreadPool(() -> { 39 | repository = IMDataRepository.Companion.getInstance(); 40 | repository.getChatUserList(new DataSource.GeneralCallback>() { 41 | @Override 42 | public void succeed(List data) { 43 | //这里要在ui线程里面执行数据的更新操作 44 | ArrayList items = new ArrayList<>(); 45 | for (User u : data) { 46 | ChatListItemViewModel item = new ChatListItemViewModel(getContext(), u); 47 | items.add(item); 48 | dataIsEmpty.set(false); 49 | } 50 | mItems.clear(); 51 | mItems.addAll(items); 52 | dataIsLoading.set(false); 53 | 54 | } 55 | 56 | @Override 57 | public void failed(String log) { 58 | showToast(log); 59 | } 60 | }); 61 | }); 62 | } 63 | 64 | @Override 65 | public void start() { 66 | getChatList(); 67 | } 68 | 69 | @Override 70 | public void onDestroy() { 71 | super.onDestroy(); 72 | navigator = null; 73 | } 74 | 75 | public void setNavigator(ChatListItemNavigator navigator) { 76 | super.setNavigator(navigator); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/chatlist/ChatListItemNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.chatlist; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | /** 6 | * Created by 98620 on 2018/4/22. 7 | */ 8 | public interface ChatListItemNavigator extends com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator { 9 | 10 | void openChatWindow(int userId, String userName); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/chatlist/ChatListItemViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.chatlist; 2 | 3 | import android.content.Context; 4 | import android.databinding.ObservableField; 5 | 6 | import com.lfork.a98620.lfree.base.BaseViewModel; 7 | import com.lfork.a98620.lfree.data.base.entity.User; 8 | import com.lfork.a98620.lfree.base.Config; 9 | 10 | import java.lang.ref.WeakReference; 11 | 12 | /** 13 | * Created by 98620 on 2018/4/9. 14 | */ 15 | 16 | public class ChatListItemViewModel extends BaseViewModel { 17 | 18 | public final ObservableField username = new ObservableField<>(); 19 | 20 | public final ObservableField newMessage = new ObservableField<>(); 21 | 22 | public final ObservableField newMessageTime = new ObservableField<>("没有消息"); 23 | 24 | public final ObservableField imageUrl = new ObservableField<>(); 25 | 26 | private int userId; 27 | 28 | public WeakReference reference; 29 | 30 | ChatListItemViewModel(Context context, User user) { 31 | super(context); 32 | 33 | username.set(user.getUserName()); 34 | imageUrl.set(Config.ServerURL + "/image" + user.getUserImagePath()); 35 | userId = user.getUserId(); 36 | } 37 | 38 | public void onClick() { 39 | if (reference != null && reference.get() != null) { 40 | reference.get().openChatWindow(userId, username.get()); 41 | } 42 | } 43 | 44 | 45 | @Override 46 | public void setNavigator(Object navigator) { 47 | super.setNavigator(navigator); 48 | reference = new WeakReference<>((ChatListItemNavigator) navigator); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/community/CommunityArticle.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.community; 2 | 3 | import com.lfork.a98620.lfree.base.BaseViewModel; 4 | 5 | import java.util.List; 6 | 7 | public class CommunityArticle extends BaseViewModel { 8 | private String article; 9 | private int articleId; 10 | private int publisherId; //发布人id 11 | private String articleTime; 12 | private List imageUriList; 13 | private String headImgUri; 14 | private String headName; 15 | 16 | public String getHeadImgUri() { 17 | return headImgUri; 18 | } 19 | 20 | public void setHeadImgUri(String headImgUri) { 21 | this.headImgUri = headImgUri; 22 | } 23 | 24 | public String getHeadName() { 25 | return headName; 26 | } 27 | 28 | public void setHeadName(String headName) { 29 | this.headName = headName; 30 | } 31 | 32 | public String getArticle() { 33 | return article; 34 | } 35 | 36 | public void setArticle(String article) { 37 | this.article = article; 38 | } 39 | 40 | public int getArticleId() { 41 | return articleId; 42 | } 43 | 44 | public void setArticleId(int articleId) { 45 | this.articleId = articleId; 46 | } 47 | 48 | public int getPublisherId() { 49 | return publisherId; 50 | } 51 | 52 | public void setPublisherId(int publisherId) { 53 | this.publisherId = publisherId; 54 | } 55 | 56 | public String getArticleTime() { 57 | return articleTime; 58 | } 59 | 60 | public void setArticleTime(String articleTime) { 61 | this.articleTime = articleTime; 62 | } 63 | 64 | public List getImageUriList() { 65 | return imageUriList; 66 | } 67 | 68 | public void setImageUriList(List imageUriList) { 69 | this.imageUriList = imageUriList; 70 | } 71 | 72 | public String getUrl() { 73 | return "http://imyth.top:8080/community_server/getcommunitycomment?articleId=" + articleId; 74 | } 75 | 76 | @Override 77 | public void start() { 78 | 79 | } 80 | 81 | @Override 82 | public void onDestroy() { 83 | super.onDestroy(); 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/community/CommunityArticleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.community; 2 | 3 | import android.databinding.DataBindingUtil; 4 | import android.databinding.ViewDataBinding; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.ViewGroup; 9 | 10 | import com.lfork.a98620.lfree.BR; 11 | import com.lfork.a98620.lfree.R; 12 | 13 | import java.util.List; 14 | 15 | public class CommunityArticleAdapter extends RecyclerView.Adapter { 16 | 17 | private List itemViewModelList; 18 | 19 | public CommunityArticleAdapter(List itemViewModelList) { 20 | this.itemViewModelList = itemViewModelList; 21 | } 22 | 23 | @NonNull 24 | @Override 25 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 26 | return ViewHolder.create(LayoutInflater.from(parent.getContext()), parent, viewType); 27 | } 28 | 29 | @Override 30 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 31 | holder.bindTo(itemViewModelList.get(position)); 32 | } 33 | 34 | @Override 35 | public int getItemCount() { 36 | return itemViewModelList.size(); 37 | } 38 | 39 | static class ViewHolder extends RecyclerView.ViewHolder { 40 | 41 | ViewDataBinding binding; 42 | 43 | public ViewHolder(ViewDataBinding binding) { 44 | super(binding.getRoot()); 45 | this.binding = binding; 46 | } 47 | 48 | static ViewHolder create(LayoutInflater inflater, ViewGroup parent, int type) { 49 | ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.main_community_frag_recycler_view_item, parent, false); 50 | return new ViewHolder(binding); 51 | } 52 | 53 | public void bindTo(CommunityArticle itemViewModel) { 54 | binding.setVariable(BR.viewModel, itemViewModel); 55 | binding.executePendingBindings(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/community/CommunityBindingAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.community; 2 | 3 | import android.content.Intent; 4 | import android.databinding.BindingAdapter; 5 | import android.view.View; 6 | 7 | import com.lfork.a98620.lfree.articlecontent.ArticleContentActivity; 8 | import com.lfork.a98620.lfree.userinfo.UserInfoActivity; 9 | import com.lfork.a98620.lfree.util.ShareUtil; 10 | 11 | public class CommunityBindingAdapter { 12 | 13 | @BindingAdapter("android:toUserInfoActivity") 14 | public static void toUserInfoActivity(View view, int userId) { 15 | view.setOnClickListener((view1) -> { 16 | Intent intent = new Intent(view1.getContext(), UserInfoActivity.class); 17 | intent.putExtra("user_id", userId); 18 | view1.getContext().startActivity(intent); 19 | }); 20 | } 21 | 22 | @BindingAdapter("android:toArticleContentActivity") 23 | public static void toArticleContentActivity(View view, int articleId) { 24 | view.setOnClickListener((view1) -> { 25 | Intent intent = new Intent(view1.getContext(), ArticleContentActivity.class); 26 | intent.putExtra("articleId", articleId); 27 | intent.putExtra("fromCommentButton", false); 28 | view1.getContext().startActivity(intent); 29 | }); 30 | } 31 | 32 | @BindingAdapter("android:shareTo") 33 | public static void shareTo(View view, String url) { 34 | view.setOnClickListener((view1) -> { 35 | ShareUtil.shareTextBySystem(view.getContext(), url, "分享到"); 36 | }); 37 | } 38 | 39 | @BindingAdapter("android:toArticleComment") 40 | public static void toArticleComment(View view, int articleId) { 41 | view.setOnClickListener((view1) -> { 42 | Intent intent = new Intent(view.getContext(), ArticleContentActivity.class); 43 | intent.putExtra("articleId", articleId); 44 | intent.putExtra("fromCommentButton", true); 45 | view1.getContext().startActivity(intent); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/community/CommunityCallback.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.community; 2 | 3 | public interface CommunityCallback { 4 | void callback(Object data, int type); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/community/CommunityFragmentViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.community; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.lfork.a98620.lfree.base.BaseViewModel; 7 | import com.lfork.a98620.lfree.data.DataSource; 8 | import com.lfork.a98620.lfree.data.community.remote.CommunityRemoteDataSource; 9 | 10 | import static com.yalantis.ucrop.UCropFragment.TAG; 11 | 12 | public class CommunityFragmentViewModel extends BaseViewModel { 13 | 14 | @Override 15 | public void start() { 16 | 17 | } 18 | 19 | @Override 20 | public void onDestroy() { 21 | super.onDestroy(); 22 | } 23 | 24 | CommunityFragmentViewModel(Context context) { 25 | super(context); 26 | } 27 | 28 | public void loadData(String fromTime, CommunityCallback callback) { 29 | Log.d(TAG, "loadData: 我要加载数据了"); 30 | new Thread(() -> { 31 | CommunityRemoteDataSource.getINSTANCE().getArticleList(fromTime, new DataSource.GeneralCallback() { 32 | @Override 33 | public void succeed(Object data) { 34 | Log.d(TAG, "succeed: 我加载成功了,马上回调了"); 35 | callback.callback(data, 1); 36 | } 37 | 38 | @Override 39 | public void failed(String log) { 40 | Log.d(TAG, "failed: " + log); 41 | Log.d(TAG, "failed: 我加载失败了,还是回调吧"); 42 | callback.callback(0, 2); 43 | } 44 | }); 45 | }).start(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/GoodsItemNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.index; 2 | 3 | /** 4 | * Created by 98620 on 2018/6/4. 5 | */ 6 | interface GoodsItemNavigator { 7 | 8 | void openGoodsDetail(int goodsId, int categoryId); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/GoodsItemViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.index; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.lfork.a98620.lfree.base.viewmodel.GoodsViewModel; 7 | import com.lfork.a98620.lfree.data.base.entity.Goods; 8 | 9 | import java.lang.ref.WeakReference; 10 | 11 | /** 12 | * 13 | * Created by 98620 on 2018/3/31. 14 | */ 15 | 16 | public class GoodsItemViewModel extends GoodsViewModel{ 17 | 18 | // This navigator is s wrapped in a WeakReference to avoid leaks because it has references to an 19 | // activity. There's no straightforward way to clear it for each item in a list adapter. 20 | 21 | @Nullable 22 | private WeakReference mNavigator; 23 | 24 | private GoodsItemViewModel(Context context, Goods g, int categoryId) { 25 | super(context, g, categoryId); 26 | } 27 | 28 | GoodsItemViewModel(Context context, Goods g) { 29 | this(context, g, 0); 30 | } 31 | 32 | 33 | public void onClick(){ 34 | int goodsId = getId(); 35 | if (goodsId == 0) { 36 | // Click happened before goods was loaded, no-op. 37 | return; 38 | } 39 | if (mNavigator != null && mNavigator.get() != null) { 40 | mNavigator.get().openGoodsDetail(goodsId, getCategoryId()); 41 | } 42 | } 43 | 44 | public void setNavigator(GoodsItemNavigator mNavigator) { 45 | this.mNavigator = new WeakReference<>(mNavigator); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/GoodsRecyclerViewItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.index; 2 | 3 | import android.databinding.DataBindingUtil; 4 | import android.support.annotation.NonNull; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | 8 | import com.lfork.a98620.lfree.base.adapter.RecyclerViewItemAdapter; 9 | import com.lfork.a98620.lfree.databinding.CommonGoodsRecycleItemBinding; 10 | 11 | /** 12 | * 13 | * Created by 98620 on 2018/3/31. 14 | */ 15 | 16 | class GoodsRecyclerViewItemAdapter extends RecyclerViewItemAdapter { 17 | 18 | private GoodsItemNavigator mGoodsItemNavigator; 19 | 20 | private PagerDataRefreshListener listener; 21 | 22 | 23 | GoodsRecyclerViewItemAdapter(GoodsItemNavigator mGoodsItemNavigator,int layoutId) { 24 | super(layoutId); 25 | this.mGoodsItemNavigator = mGoodsItemNavigator; 26 | } 27 | 28 | @NonNull 29 | @Override 30 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 31 | CommonGoodsRecycleItemBinding binding = DataBindingUtil.inflate(LayoutInflater 32 | .from(parent.getContext()), getLayoutId(), parent, false); 33 | 34 | ViewHolder holder = new ViewHolder(binding.getRoot()); 35 | holder.setBinding(binding); 36 | return holder; 37 | 38 | } 39 | 40 | @Override 41 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 42 | super.onBindViewHolder(holder, position); 43 | GoodsItemViewModel viewModel = (GoodsItemViewModel)getItems().get(position); 44 | viewModel.setNavigator(mGoodsItemNavigator); 45 | 46 | if (position + 1 == getItemCount()) { 47 | listener.startRefreshing(); 48 | } 49 | if (position > 10) { 50 | listener.onDown(); 51 | } 52 | } 53 | 54 | //滑动到最后 55 | 56 | public PagerDataRefreshListener getListener() { 57 | return listener; 58 | } 59 | 60 | public void setListener(PagerDataRefreshListener listener) { 61 | this.listener = listener; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/IndexFragmentNavigator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lfork.a98620.lfree.main.index; 18 | 19 | /** 20 | * Defines the navigation actions that can be called from the Details screen. 21 | * 现在先不忙优化,先把im写完先 22 | */ 23 | public interface IndexFragmentNavigator { 24 | 25 | void openSearchActivity(); 26 | 27 | void openWebClient(String url); 28 | //ppt文档心得体会 源码 29 | // 数据库 配置文件 30 | // 需求文档 31 | // 概要设计 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/PagerDataRefreshListener.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.index; 2 | 3 | /** 4 | * Created by 98620 on 2018/5/5. 5 | */ 6 | public interface PagerDataRefreshListener { 7 | void startRefreshing(); 8 | 9 | void endRefresh(); 10 | 11 | /** 12 | * 数据滑动到最下面了 13 | */ 14 | void onDown(); 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/PagerItemViewNavigator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.lfork.a98620.lfree.main.index; 18 | 19 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 20 | 21 | /** 22 | * Defines the navigation actions that can be called from the Details screen. 23 | */ 24 | public interface PagerItemViewNavigator extends ViewModelNavigator { 25 | void refreshEnd(); 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/index/PagersDataBinding.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.index; 2 | 3 | import android.databinding.BindingAdapter; 4 | import android.support.v4.view.ViewPager; 5 | 6 | import com.lfork.a98620.lfree.data.base.entity.Category; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Created by 98620 on 2018/6/2. 12 | */ 13 | public class PagersDataBinding { 14 | @SuppressWarnings("unchecked") 15 | @BindingAdapter("tabs") 16 | public static void setTabs(ViewPager viewPager, List items) { 17 | // MyViewPagerAdapter adapter = (MyViewPagerAdapter) viewPager.getAdapter(); 18 | PagerItemAdapter adapter = (PagerItemAdapter) viewPager.getAdapter(); 19 | if (adapter != null) 20 | { 21 | adapter.replaceData(items, viewPager); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/myinfo/MyInfoFragmentNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.myinfo; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | /** 6 | * Created by 98620 on 2018/6/23. 7 | */ 8 | public interface MyInfoFragmentNavigator extends ViewModelNavigator { 9 | void openMyGoods(); 10 | 11 | void openSettings(); 12 | 13 | void openUserInfoDetail(); 14 | 15 | void logoff(); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/myinfo/MyInfoFragmentViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.myinfo; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.lfork.a98620.lfree.base.viewmodel.UserViewModel; 6 | import com.lfork.a98620.lfree.data.DataSource; 7 | import com.lfork.a98620.lfree.data.base.entity.User; 8 | import com.lfork.a98620.lfree.data.user.UserDataRepository; 9 | import com.lfork.a98620.lfree.main.MainActivity; 10 | import com.lfork.a98620.lfree.base.Config; 11 | 12 | /** 13 | * Created by 98620 on 2018/4/5. 14 | */ 15 | 16 | public class MyInfoFragmentViewModel extends UserViewModel { 17 | 18 | private MyInfoFragmentNavigator navigator; 19 | 20 | MyInfoFragmentViewModel(MainActivity context) { 21 | super(context); 22 | } 23 | 24 | private void getUserInfo() { 25 | UserDataRepository repository = UserDataRepository.INSTANCE; 26 | repository.getUserInfo(new DataSource.GeneralCallback() { 27 | @Override 28 | public void succeed(User data) { 29 | setUser(data); 30 | } 31 | @Override 32 | public void failed(String log) { 33 | showToast(log); 34 | } 35 | },repository.getUserId()); 36 | 37 | } 38 | 39 | private void setUser(User user){ 40 | username.set(user.getUserName()); 41 | if (TextUtils.isEmpty(user.getUserDesc())) { 42 | description.set("该用户还没有自我介绍...."); 43 | } else { 44 | description.set(user.getUserDesc()); 45 | } 46 | imageUrl.set(Config.ServerURL + "/image" + user.getUserImagePath()); 47 | 48 | } 49 | 50 | public void onQuit() { 51 | if (navigatorIsNotNull()) { 52 | navigator.logoff(); 53 | } 54 | 55 | } 56 | 57 | public void openSettings() { 58 | if(navigatorIsNotNull()){ 59 | navigator.openSettings(); 60 | } 61 | } 62 | 63 | public void openUserInfoDetail() { 64 | if(navigatorIsNotNull()){ 65 | navigator.openUserInfoDetail(); 66 | } 67 | 68 | } 69 | 70 | public void openMyGoods() { 71 | if(navigatorIsNotNull()){ 72 | navigator.openMyGoods(); 73 | } 74 | } 75 | 76 | private boolean navigatorIsNotNull(){ 77 | return navigator != null; 78 | 79 | } 80 | 81 | public void setNavigator(MyInfoFragmentNavigator navigator) { 82 | super.setNavigator(navigator); 83 | this.navigator = navigator; 84 | } 85 | 86 | @Override 87 | public void start() { 88 | getUserInfo(); 89 | } 90 | 91 | @Override 92 | public void onDestroy() { 93 | super.onDestroy(); 94 | navigator = null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/main/publishinfo/PublishInfoFragment.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.main.publishinfo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | 12 | import com.lfork.a98620.lfree.R; 13 | import com.lfork.a98620.lfree.goodsuploadupdate.GoodsUploadUpdateActivity; 14 | import com.lfork.a98620.lfree.publisharticle.PublishArticleActivity; 15 | 16 | import java.util.Objects; 17 | 18 | public class PublishInfoFragment extends Fragment { 19 | private static final String TAG = "PublishInfoFragment"; 20 | 21 | @Override 22 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 23 | Bundle savedInstanceState) { 24 | View view = inflater.inflate(R.layout.main_goods_upload_frag, container, false); 25 | Button upload = view.findViewById(R.id.btn_upload); 26 | upload.setOnClickListener(view1 -> { 27 | GoodsUploadUpdateActivity.openUploadActivityForResult(getActivity()); 28 | }); 29 | 30 | Button publishArticle = view.findViewById(R.id.btn_publish_article); 31 | publishArticle.setOnClickListener((view1) -> { 32 | Intent intent = new Intent(getContext(), PublishArticleActivity.class); 33 | Objects.requireNonNull(getActivity()).startActivityForResult(intent, 1); 34 | }); 35 | // Inflate the layout for this fragment 36 | return view; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/mygoods/MyGoodsActivityNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.mygoods; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | /** 6 | * Created by 98620 on 2018/5/5. 7 | */ 8 | interface MyGoodsActivityNavigator extends ViewModelNavigator { 9 | void refreshFinished(String log); 10 | 11 | void loadMoreFinished(String log); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/mygoods/MyGoodsItemNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.mygoods; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | public interface MyGoodsItemNavigator extends ViewModelNavigator { 6 | void openGoodsDetail(int goodsId, int categoryId); 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/mygoods/MyGoodsItemViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.mygoods; 2 | 3 | import android.content.Context; 4 | 5 | import com.lfork.a98620.lfree.base.viewmodel.GoodsViewModel; 6 | import com.lfork.a98620.lfree.data.base.entity.Goods; 7 | 8 | import java.lang.ref.WeakReference; 9 | 10 | /** 11 | * Created by 98620 on 2018/5/5. 12 | */ 13 | public class MyGoodsItemViewModel extends GoodsViewModel{ 14 | 15 | 16 | 17 | private WeakReference reference; 18 | 19 | MyGoodsItemViewModel(Context context, Goods g) { 20 | super(context, g); 21 | 22 | } 23 | 24 | 25 | 26 | @Override 27 | public void onClick(){ 28 | if (reference != null && reference.get() != null) 29 | reference.get().openGoodsDetail(getId(), getCategoryId()); 30 | 31 | } 32 | 33 | @Override 34 | public void setNavigator(Object navigator) { 35 | super.setNavigator(navigator); 36 | this.reference = new WeakReference<>((MyGoodsItemNavigator)navigator); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/register/RegisterNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.register; 2 | 3 | import com.lfork.a98620.lfree.data.base.entity.School; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 98620 on 2018/6/13. 9 | */ 10 | public interface RegisterNavigator { 11 | void setupSpinner(List data); 12 | 13 | void success(String result); 14 | 15 | void failed(String result); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/searchresult/GoodsSearchItemViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.searchresult; 2 | 3 | import android.content.Context; 4 | 5 | import com.lfork.a98620.lfree.base.viewmodel.GoodsViewModel; 6 | import com.lfork.a98620.lfree.data.base.entity.Goods; 7 | 8 | import java.lang.ref.WeakReference; 9 | 10 | /** 11 | * Created by 98620 on 2018/4/14. 12 | */ 13 | 14 | public class GoodsSearchItemViewModel extends GoodsViewModel { 15 | 16 | private WeakReference reference; 17 | 18 | public GoodsSearchItemViewModel(Context context, Goods g) { 19 | super(context, g); 20 | } 21 | 22 | public void setNavigator(GoodsSearchNavigator navigator) { 23 | super.setNavigator(navigator); 24 | reference = new WeakReference<>(navigator); 25 | } 26 | 27 | public void onClick(){ 28 | if (reference != null && reference.get() != null) { 29 | reference.get().openGoodsDetail(getId(), getCategoryId()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/searchresult/GoodsSearchNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.searchresult; 2 | 3 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 4 | 5 | /** 6 | * Created by 98620 on 2018/6/26. 7 | */ 8 | public interface GoodsSearchNavigator extends ViewModelNavigator{ 9 | void openGoodsDetail(int goodsId,int categoryId); 10 | 11 | void cancelSearch(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/settings/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.settings 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.ActionBar 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.Menu 7 | import android.view.MenuItem 8 | import com.lfork.a98620.lfree.R 9 | import java.util.* 10 | 11 | class SettingsActivity : AppCompatActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.settings_act) 15 | setupActionBar() 16 | } 17 | 18 | private fun setupActionBar() { 19 | val actionBar = supportActionBar 20 | Objects.requireNonNull(actionBar).setDisplayShowTitleEnabled(true) 21 | actionBar!!.title = "设置" 22 | // 决定左上角图标的右侧是否有向左的小箭头, true 23 | actionBar.setDisplayHomeAsUpEnabled(true) 24 | // 有小箭头,并且图标可以点击 25 | actionBar.setDisplayShowHomeEnabled(false) 26 | } 27 | 28 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 29 | // getMenuInflater().inflate(R.menu.common_action_bar, menu); 30 | // MenuItem item = menu.getItem(0); 31 | // item.setTitle("编辑"); 32 | return true 33 | } 34 | 35 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 36 | when (item.itemId) { 37 | android.R.id.home -> finish() 38 | // case R.id.menu1: 39 | // Intent intent = new Intent(UserInfoThisActivity.this, UserInfoEditActivity.class); 40 | // startActivityForResult(intent, 4); 41 | else -> { 42 | } 43 | } 44 | return super.onOptionsItemSelected(item) 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/userinfo/UserInfoViewModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.userinfo; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.lfork.a98620.lfree.base.viewmodel.UserViewModel; 7 | import com.lfork.a98620.lfree.base.viewmodel.ViewModelNavigator; 8 | import com.lfork.a98620.lfree.data.DataSource; 9 | import com.lfork.a98620.lfree.data.base.entity.User; 10 | import com.lfork.a98620.lfree.data.user.UserDataRepository; 11 | import com.lfork.a98620.lfree.base.Config; 12 | 13 | /** 14 | * Created by 98620 on 2018/4/13. 15 | */ 16 | 17 | public class UserInfoViewModel extends UserViewModel { 18 | 19 | 20 | private ViewModelNavigator navigator; 21 | 22 | private int userId; 23 | 24 | UserInfoViewModel(Context context, int userId) { 25 | super(context); 26 | this.userId = userId; 27 | } 28 | 29 | @Override 30 | public void start() { 31 | getUserInfo(); 32 | } 33 | 34 | private void getUserInfo() { 35 | UserDataRepository repository = UserDataRepository.INSTANCE; 36 | repository.getUserInfo(new DataSource.GeneralCallback() { 37 | @Override 38 | public void succeed(User user) { 39 | username.set(user.getUserName()); 40 | if (TextUtils.isEmpty(user.getUserDesc())) { 41 | description.set("该用户还没有自我介绍...."); 42 | } else { 43 | description.set(user.getUserDesc()); 44 | } 45 | imageUrl.set(Config.ServerURL + "/image" + user.getUserImagePath()); 46 | email.set(user.getUserEmail()); 47 | phone.set(user.getUserPhone()); 48 | studentNumber.set(user.getUserId() + ""); 49 | 50 | if (user.getUserSchool() == null) { 51 | school.set("cuit"); 52 | } else { 53 | school.set(user.getUserSchool().getSchoolName()); 54 | } 55 | 56 | 57 | } 58 | @Override 59 | public void failed(String log) { 60 | if (navigator != null) { 61 | navigator.showToast(log); 62 | } 63 | } 64 | }, userId); 65 | } 66 | 67 | 68 | public int getUserId() { 69 | return userId; 70 | } 71 | 72 | 73 | 74 | @Override 75 | public void onDestroy() { 76 | super.onDestroy(); 77 | navigator = null; 78 | } 79 | 80 | public void setNavigator(ViewModelNavigator navigator) { 81 | this.navigator = navigator; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/userinfoedit/UserInfoEditNavigator.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.userinfoedit; 2 | 3 | import com.lfork.a98620.lfree.data.base.entity.School; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by 98620 on 2018/6/13. 9 | */ 10 | public interface UserInfoEditNavigator { 11 | void setupSpinner(List data, int currentSchoolId); 12 | 13 | void success(String result); 14 | 15 | void failed(String result); 16 | 17 | void backToUserInfoAct(int result, String log); 18 | 19 | void showMessage(String msg); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/JSONUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.reflect.TypeToken; 5 | 6 | /** en? 7 | * Created by 98620 on 2018/2/1. 8 | */ 9 | 10 | public class JSONUtil { 11 | /** 12 | * 13 | * @param jsonData 符合JSON语法规则的字符串 14 | * @param token 传递参数的时候这样写:new TypeToken() {}, 比如:parseJson(str1, new TypeToken>>(){}) 15 | * 泛型会被擦除, 所以Token需要单独传参数 16 | * @return fromJson会自动根据JSONData的内容转化为POJO 或者是List 17 | */ 18 | public static T parseJson(String jsonData, TypeToken token) { 19 | try { 20 | return new Gson().fromJson(jsonData, token.getType()); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | return null; 24 | } 25 | } 26 | 27 | public static String toJson(T object){ 28 | try { 29 | return new Gson().toJson(object); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | return null; 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/LFreeGlideModel.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import com.bumptech.glide.annotation.GlideModule; 4 | import com.bumptech.glide.module.AppGlideModule; 5 | 6 | /** 7 | * 8 | * Created by 98620 on 2018/3/23. 9 | */ 10 | 11 | @GlideModule 12 | public class LFreeGlideModel extends AppGlideModule { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/Print.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import android.util.Log; 4 | 5 | public class Print { 6 | private static final String TAG = "Print"; 7 | public static void print(String content){ 8 | Log.d(TAG, "print: " + content); 9 | } 10 | 11 | public static void print(Object content){ 12 | Log.d(TAG, "print: " + content); 13 | } 14 | 15 | public static void print(String Tag, String content){ 16 | Log.d(Tag, "print: " + content); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/QMUI/QMUILangHelper.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util.QMUI; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author cginechen 11 | * @date 2016-03-17 12 | */ 13 | public class QMUILangHelper { 14 | 15 | /** 16 | * 获取数值的位数,例如9返回1,99返回2,999返回3 17 | * 18 | * @param number 要计算位数的数值,必须>0 19 | * @return 数值的位数,若传的参数小于等于0,则返回0 20 | */ 21 | public static int getNumberDigits(int number) { 22 | if (number <= 0) return 0; 23 | return (int) (Math.log10(number) + 1); 24 | } 25 | 26 | 27 | public static int getNumberDigits(long number) { 28 | if (number <= 0) return 0; 29 | return (int) (Math.log10(number) + 1); 30 | } 31 | 32 | /** 33 | * 规范化价格字符串显示的工具类 34 | * 35 | * @param price 价格 36 | * @return 保留两位小数的价格字符串 37 | */ 38 | public static String regularizePrice(float price) { 39 | return String.format(Locale.CHINESE, "%.2f", price); 40 | } 41 | 42 | /** 43 | * 规范化价格字符串显示的工具类 44 | * 45 | * @param price 价格 46 | * @return 保留两位小数的价格字符串 47 | */ 48 | public static String regularizePrice(double price) { 49 | return String.format(Locale.CHINESE, "%.2f", price); 50 | } 51 | 52 | 53 | public static boolean isNullOrEmpty(@Nullable CharSequence string) { 54 | return string == null || string.length() == 0; 55 | } 56 | 57 | public static void close(Closeable c) { 58 | if (c != null) { 59 | try { 60 | c.close(); 61 | } catch (IOException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | } 66 | 67 | public static boolean objectEquals(Object a, Object b) { 68 | return (a == b) || (a != null && a.equals(b)); 69 | } 70 | 71 | public static int constrain(int amount, int low, int high) { 72 | return amount < low ? low : (amount > high ? high : amount); 73 | } 74 | 75 | public static float constrain(float amount, float low, float high) { 76 | return amount < low ? low : (amount > high ? high : amount); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/QMUI/QMUILog.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util.QMUI; 2 | 3 | /** 4 | * 5 | * @author cginechen 6 | * @date 2016-08-11 7 | */ 8 | public class QMUILog { 9 | public interface QMUILogDelegate { 10 | void e(final String tag, final String msg, final Object ... obj); 11 | void w(final String tag, final String msg, final Object ... obj); 12 | void i(final String tag, final String msg, final Object ... obj); 13 | void d(final String tag, final String msg, final Object ... obj); 14 | void printErrStackTrace(String tag, Throwable tr, final String format, final Object ... obj); 15 | } 16 | 17 | private static QMUILogDelegate sDelegete = null; 18 | 19 | public static void setDelegete(QMUILogDelegate delegete) { 20 | sDelegete = delegete; 21 | } 22 | 23 | public static void e(final String tag, final String msg, final Object ... obj) { 24 | if (sDelegete != null) { 25 | sDelegete.e(tag, msg, obj); 26 | } 27 | } 28 | 29 | public static void w(final String tag, final String msg, final Object ... obj) { 30 | if (sDelegete != null) { 31 | sDelegete.w(tag, msg, obj); 32 | } 33 | } 34 | 35 | public static void i(final String tag, final String msg, final Object ... obj) { 36 | if (sDelegete != null) { 37 | sDelegete.i(tag, msg, obj); 38 | } 39 | } 40 | 41 | public static void d(final String tag, final String msg, final Object ... obj) { 42 | if (sDelegete != null) { 43 | sDelegete.d(tag, msg, obj); 44 | } 45 | } 46 | 47 | public static void printErrStackTrace(String tag, Throwable tr, final String format, final Object ... obj) { 48 | if (sDelegete != null) { 49 | sDelegete.printErrStackTrace(tag, tr, format, obj); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/ShareUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | 8 | /** 9 | * Created by 98620 on 2018/6/20. 10 | */ 11 | public class ShareUtil { 12 | private static final String TAG = "ShareUtil"; 13 | public static void shareTextBySystem(Context context, String text, String tips){ 14 | if (context == null || TextUtils.isEmpty(text) || TextUtils.isEmpty(tips)) { 15 | Log.d(TAG, "shareTextBySystem: 参数不能为空"); 16 | return; 17 | } 18 | Intent intent = new Intent(); 19 | intent.setAction(Intent.ACTION_SEND) 20 | .setType("text/plain"); 21 | intent.putExtra(Intent.EXTRA_TEXT, text); 22 | context.startActivity(Intent.createChooser(intent, tips)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/SharedPrefUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | /** 4 | * 5 | * @author 98620 6 | * @date 2018/7/11 7 | */ 8 | public class SharedPrefUtil { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/ThreadUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | /** 4 | * Created by 98620 on 2018/7/15. 5 | */ 6 | public class ThreadUtil { 7 | 8 | void getFixedThreadPool(){ 9 | // Executors.newFixedThreadPool(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import android.text.format.DateFormat; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * Created by 98620 on 2018/6/13. 9 | */ 10 | public class TimeUtil { 11 | public static String getStandardTime(){ 12 | return DateFormat.format("yyyy-MM-dd HH:mm:ss", new Date()).toString(); 13 | } 14 | 15 | public static String getBiggestTime(){ 16 | return DateFormat.format("9999-01-02 13:44:44", new Date()).toString(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import android.content.Context; 4 | import android.os.Looper; 5 | import android.widget.Toast; 6 | 7 | /** 8 | * Created by 98620 on 2018/4/14. 9 | */ 10 | 11 | public class ToastUtil { 12 | public static void showLong(Context context, String content){ 13 | if (!Thread.currentThread().getName().equals("main")) { 14 | if (Looper.myLooper() == null) 15 | { 16 | Looper.prepare(); 17 | } 18 | } 19 | Toast.makeText(context, content, Toast.LENGTH_LONG).show(); 20 | } 21 | 22 | public static void showShort(Context context, String content){ 23 | if (!Thread.currentThread().getName().equals("main")) { //不能在非主线程里面直接Toast Can't create handler inside thread that has not called Looper.prepare() 24 | if (Looper.myLooper() == null) 25 | { 26 | Looper.prepare(); 27 | } 28 | } 29 | Toast.makeText(context, content, Toast.LENGTH_SHORT).show(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/UserValidation.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | import android.text.TextUtils; 3 | 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | public class UserValidation { 8 | /** 9 | * 所运用的正则表达式的集合: 10 | * userId 的正则表达式:"-?[1-9]\\d*" (数字) 11 | * userName的正则表达式:"[A-Za-z0-9_\\-\\u4e00-\\u9fa5]+" () 12 | * userPassword 的正则表达式:"^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$" (只能位数字或者字母) //8位到16位 13 | * userEmail 的正则表达式:"\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}" 14 | * userPhone 的正则表达式:"0?(13|14|15|18)[0-9]{9}" 15 | * 16 | */ 17 | 18 | private static final String regex_UserId = "[1-9]\\d{9}"; 19 | 20 | private static final String regex_UserName = "[A-Za-z0-9_\\-\\u4e00-\\u9fa5]{5,16}"; 21 | 22 | private static final String regex_UserPassword = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$"; 23 | 24 | private static final String regex_UserEmail = "\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}"; 25 | 26 | private static final String regex_UserPhone = "0?(13|14|15|18)[0-9]{9}"; 27 | 28 | // 对注册时的数据进行验证 29 | public static String RegisterValidation(String userId, String userName, String userPassword, String passwordRepeat) { 30 | 31 | if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(userName) || TextUtils.isEmpty(userPassword) || TextUtils.isEmpty(passwordRepeat)) { 32 | return "请输入完整的注册信息"; 33 | } 34 | 35 | if (!RegexValidation(userId, regex_UserId)) { 36 | return "学号必须是10位"; 37 | } 38 | 39 | if (!RegexValidation(userName, regex_UserName)) { 40 | return "用户名不符合规范"; 41 | } 42 | 43 | if (!RegexValidation(userPassword, regex_UserPassword)) { 44 | return "密码不符合规范"; 45 | } 46 | 47 | 48 | if (!userPassword.equals(passwordRepeat) ) { 49 | return "两次输入的密码必须相同"; 50 | } 51 | 52 | return null; 53 | } 54 | 55 | // 对登录的数据进行验证 56 | public static boolean LoginValidation(String userId, String userPassword) { 57 | return RegexValidation(userId, regex_UserId) && RegexValidation(userPassword, regex_UserPassword); 58 | } 59 | 60 | // 对修改用户信息后保存操作之前的数据进行修改 61 | public static boolean SaveValidation(String userId, String userName, String userPassword, String userEmail, 62 | String userPhone) { 63 | return RegexValidation(userId, regex_UserId) && RegexValidation(userName, regex_UserName) 64 | && RegexValidation(userPassword, regex_UserPassword) && RegexValidation(userEmail, regex_UserEmail) 65 | && RegexValidation(userPhone, regex_UserPhone); 66 | } 67 | 68 | // 传入要验证的字段,以及需要的正则表达式, 进行字段的验证 69 | private static boolean RegexValidation(String args, String regex) { 70 | Pattern pattern = Pattern.compile(regex); 71 | Matcher matcher = pattern.matcher(args); 72 | System.out.println(matcher.matches()); 73 | return matcher.matches(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util; 2 | 3 | import android.content.Context; 4 | 5 | import com.lfork.a98620.lfree.base.FreeApplication; 6 | 7 | /** 8 | * Created by 98620 on 2018/7/11. 9 | */ 10 | class Utils { 11 | public static Context getApp() { 12 | return FreeApplication.getContext(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/util/ui/MyItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.util.ui; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | 10 | public class MyItemDecoration extends RecyclerView.ItemDecoration{ 11 | private int halfSpace; 12 | private Paint paint; 13 | /** 14 | * @param space item之间的间隙 15 | */ 16 | public MyItemDecoration(int space, Context context, int color) { 17 | setSpace(space); 18 | paint = new Paint(); 19 | paint.setAntiAlias(true);//抗锯齿 20 | paint.setColor(color);//设置背景色 21 | } 22 | public void setSpace(int space) { 23 | this.halfSpace = space / 2; 24 | } 25 | /** 26 | * 27 | * 重写onDraw 方法以实现recyclerview的item之间的间隙的背景 28 | * @param c 画布 29 | * @param parent 使用该 ItemDecoration 的 RecyclerView 对象实例 30 | * @param state 使用该 ItemDecoration 的 RecyclerView 对象实例的状态 31 | */ 32 | @Override 33 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 34 | super.onDraw(c, parent, state); 35 | int outLeft, outTop, outRight, outBottom,viewLeft,viewTop,viewRight,viewBottom; 36 | int childCount = parent.getChildCount(); 37 | for (int i = 0; i < childCount; i++) { 38 | View view = parent.getChildAt(i); 39 | viewLeft = view.getLeft(); 40 | viewTop = view.getTop(); 41 | viewRight = view.getRight(); 42 | viewBottom = view.getBottom(); 43 | // item外层的rect在RecyclerView中的坐标 44 | outLeft = viewLeft - halfSpace; 45 | outTop = viewTop - halfSpace; 46 | outRight = viewRight + halfSpace; 47 | outBottom = viewBottom + halfSpace; 48 | //item 上方的矩形 49 | c.drawRect(outLeft, outTop, outRight,viewTop, paint); 50 | //item 左边的矩形 51 | c.drawRect(outLeft,viewTop,viewLeft,viewBottom,paint); 52 | //item 右边的矩形 53 | c.drawRect(viewRight,viewTop,outRight,viewBottom,paint); 54 | //item 下方的矩形 55 | c.drawRect(outLeft,viewBottom,outRight,outBottom,paint); 56 | } 57 | } 58 | @Override 59 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 60 | outRect.top = halfSpace; 61 | outRect.bottom = halfSpace; 62 | outRect.left = halfSpace; 63 | outRect.right = halfSpace; 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lfork/a98620/lfree/welcome/WelcomeActivity.java: -------------------------------------------------------------------------------- 1 | package com.lfork.a98620.lfree.welcome; 2 | 3 | import android.content.Intent; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 12 | import com.lfork.a98620.lfree.R; 13 | import com.lfork.a98620.lfree.base.FreeApplication; 14 | import com.lfork.a98620.lfree.login.LoginActivity; 15 | import com.lfork.a98620.lfree.util.GlideOptions; 16 | 17 | public class WelcomeActivity extends AppCompatActivity { 18 | 19 | private static final String TAG = "WelcomeActivity"; 20 | private WelcomeActivity welcomeActivity; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.welcome_act); 26 | ImageView welcome = findViewById(R.id.welcome_image); 27 | GlideOptions options = GlideOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE).skipMemoryCache(true); 28 | Glide.with(this).load(R.drawable.welcome_pic).apply(options).into(welcome); 29 | welcomeActivity = this; 30 | hideSystemNavigationBar(); 31 | 32 | FreeApplication.getDefaultThreadPool().execute(() -> { 33 | try { 34 | Thread.sleep(2000); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | runOnUiThread(() -> { 39 | Intent intent = new Intent(welcomeActivity, LoginActivity.class); 40 | welcomeActivity.startActivity(intent); 41 | welcomeActivity.finish(); 42 | }); 43 | }); 44 | 45 | 46 | } 47 | 48 | private void hideSystemNavigationBar() { 49 | if (Build.VERSION.SDK_INT >= 19) { 50 | View decorView = getWindow().getDecorView(); 51 | int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 52 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN; 53 | decorView.setSystemUiVisibility(uiOptions); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-hdpi/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-hdpi/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/goods_upload_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-hdpi/goods_upload_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-mdpi/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-mdpi/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/goods_upload_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-mdpi/goods_upload_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/user_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-v24/user_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/user_email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-v24/user_email.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/user_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-v24/user_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/user_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-v24/user_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xhdpi/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xhdpi/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/goods_upload_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xhdpi/goods_upload_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xxhdpi/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xxhdpi/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/goods_upload_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xxhdpi/goods_upload_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xxxhdpi/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable-xxxhdpi/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/background.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/chatwindow_mesage_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/chatwindow_mesage_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/chatwindow_message_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/chatwindow_message_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/dark_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_upward_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_comment_message.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_comment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_in.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_like_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_like_in.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_like_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_like_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_share_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_share_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_community_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_community_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_contacts_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_goods_details.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_goods_kinds.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_goods_location.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_goods_name.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_main_publish_new_community.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_main_publish_new_goods.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mygoods_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_mygoods_box.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_school.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/ic_school.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_school_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_talk_notalk.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/login_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/login_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/login_shape_user_rectangle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_community_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_goods_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_goods_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_goods_in.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_goods_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_goods_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_ic_search_grey_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_ic_search_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_index_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_index_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_my_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_my_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_my_in.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_my_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_my_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_publish.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_shape_search_rectangle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_talk_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_talk_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_talk_in.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_talk_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/main_talk_side.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/my_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/my_data.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/my_mygoods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/my_mygoods.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/my_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/my_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/photo_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/photo_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/red.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/trash.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/trash2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/trash2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_default_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_default_0.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_default_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_default_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_email.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_no.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/user_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/user_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/welcome_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfork/l.free-android/c855156fe649766570f03d6e0129a95fc7c530d3/app/src/main/res/drawable/welcome_pic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_publish_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 17 | 18 | 22 | 23 | 29 | 30 | 36 | 37 | 38 | 42 | 43 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/chat_window_msg_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 16 | 17 | 22 | 23 | 24 | 25 | 32 | 33 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/community_comment_include.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | 16 | 21 | 22 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/goods_detail_seller_include.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 19 | 20 | 30 | 31 | 40 | 41 | 52 | 53 | 54 | 55 | 56 |