├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.MD ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── com │ │ └── zyfdroid │ │ └── tomatoclock │ │ ├── ClockActivity.java │ │ ├── MainActivity.java │ │ ├── Program.java │ │ ├── TimeOutReceiver.java │ │ ├── model │ │ └── TimeEntry.java │ │ └── util │ │ ├── AndroidUtils.java │ │ ├── ICallback.java │ │ └── SpUtils.java │ └── res │ ├── drawable-hdpi │ ├── ic_delete.png │ ├── ic_list_icon.png │ ├── ic_menu_add.png │ ├── ic_menu_settings.png │ ├── ic_menu_start.png │ ├── ic_stat_clock.png │ └── ic_stop.png │ ├── drawable-xhdpi │ ├── ic_delete.png │ ├── ic_launcher.png │ ├── ic_list_icon.png │ ├── ic_menu_add.png │ ├── ic_menu_settings.png │ ├── ic_menu_start.png │ ├── ic_stat_clock.png │ └── ic_stop.png │ ├── drawable │ ├── bg_fab.xml │ ├── bg_fab_clock.xml │ ├── bg_progress.xml │ ├── bg_ripple.xml │ └── progress_border.xml │ └── layout │ ├── activity_clock.xml │ ├── activity_main.xml │ ├── adapter_time_entry.xml │ └── dialog_add.xml ├── build.gradle ├── 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/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # 番茄钟APP 2 | - 3 | 4 | [点我下载](https://github.com/ZYFDroid/android-tomato-clock/releases) 5 | 6 | 如果你有什么好的时间组合想加入app的,可以再b站发私信或者在这里提issue -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.2" 6 | defaultConfig { 7 | applicationId "com.zyfdroid.tomatoclock" 8 | minSdkVersion 21 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | testCompile 'junit:junit:4.12' 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\WorldSkills2020\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/ClockActivity.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock; 2 | 3 | import android.app.Activity; 4 | import android.app.AlarmManager; 5 | import android.app.AlertDialog; 6 | import android.app.KeyguardManager; 7 | import android.app.Notification; 8 | import android.app.NotificationManager; 9 | import android.app.PendingIntent; 10 | import android.content.Context; 11 | import android.content.DialogInterface; 12 | import android.content.Intent; 13 | import android.graphics.BitmapFactory; 14 | import android.os.Bundle; 15 | import android.os.Handler; 16 | import android.os.PowerManager; 17 | import android.util.Log; 18 | import android.view.View; 19 | import android.view.animation.AccelerateDecelerateInterpolator; 20 | import android.view.animation.DecelerateInterpolator; 21 | import android.view.animation.Interpolator; 22 | import android.widget.FrameLayout; 23 | import android.widget.LinearLayout; 24 | import android.widget.ProgressBar; 25 | import android.widget.TextView; 26 | 27 | import com.zyfdroid.tomatoclock.model.TimeEntry; 28 | import com.zyfdroid.tomatoclock.util.SpUtils; 29 | 30 | import java.util.Date; 31 | import java.util.List; 32 | 33 | public class ClockActivity extends Activity { 34 | 35 | static ClockActivity mInstance = null; 36 | 37 | FrameLayout activity_clock = null; 38 | LinearLayout clockBackground = null; 39 | ProgressBar progressTime = null; 40 | TextView txtClockTime = null; 41 | TextView txtClockDescription = null; 42 | 43 | void initUi(){ 44 | activity_clock = (FrameLayout)findViewById(R.id.activity_clock); 45 | clockBackground = (LinearLayout)findViewById(R.id.clockBackground); 46 | progressTime = (ProgressBar)findViewById(R.id.progressTime); 47 | txtClockTime = (TextView)findViewById(R.id.txtClockTime); 48 | txtClockDescription = (TextView)findViewById(R.id.txtClockDescription); 49 | } 50 | 51 | 52 | public void onStopClick(View v){ 53 | new AlertDialog.Builder(this).setTitle("停止番茄钟").setMessage("是否停止番茄钟?") 54 | .setPositiveButton("是的", new DialogInterface.OnClickListener() { 55 | @Override 56 | public void onClick(DialogInterface dialog, int which) { 57 | SpUtils.setStatus(false); 58 | SpUtils.setStartTime(-1); 59 | PendingIntent pendingIntent = PendingIntent.getBroadcast(ClockActivity.this, 0, new Intent(ClockActivity.this, TimeOutReceiver.class), 0); 60 | AlarmManager.AlarmClockInfo next = alarmManager.getNextAlarmClock(); 61 | if (null != next) { 62 | alarmManager.cancel(pendingIntent); 63 | } 64 | startActivity(new Intent(ClockActivity.this,MainActivity.class)); 65 | finish(); 66 | } 67 | }).setNegativeButton("不是",null).create().show(); 68 | } 69 | 70 | Handler hWnd = new Handler(); 71 | Runnable updateRunnable = new Runnable() { 72 | @Override 73 | public void run() { 74 | updateTime(); 75 | hWnd.postDelayed(updateRunnable,16); 76 | } 77 | }; 78 | 79 | AlarmManager alarmManager = null; 80 | 81 | @Override 82 | protected void onCreate(Bundle savedInstanceState) { 83 | super.onCreate(savedInstanceState); 84 | mInstance = this; 85 | setContentView(R.layout.activity_clock); 86 | initUi(); 87 | alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE); 88 | startTime = SpUtils.getStartTime();//获取开始时间,作为计算当前阶段的参考 89 | entries = SpUtils.getCurrent(); 90 | hWnd.postDelayed(updateRunnable,16); 91 | if(getIntent().getBooleanExtra("notification",false)){ 92 | requireNotification(); 93 | } 94 | doUpdateAlarmClock(); 95 | } 96 | 97 | @Override 98 | protected void onDestroy() { 99 | super.onDestroy(); 100 | hWnd.removeCallbacks(updateRunnable); 101 | mInstance = null; 102 | } 103 | 104 | public void requireNotification(){ 105 | TimeEntry entry = getCurrentTimeEntry(); 106 | NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 107 | Notification notification = new Notification.Builder(this) 108 | .setContentTitle("番茄钟") //设置标题 109 | .setContentText(entry.getName()+"的时间到了!") //设置内容 110 | .setWhen(System.currentTimeMillis()) //设置时间 111 | .setSmallIcon(R.drawable.ic_stat_clock) //设置小图标 只能使用alpha图层的图片进行设置 112 | .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher)) //设置大图标 113 | //.setContentIntent(pi) 114 | .setAutoCancel(true) 115 | .setDefaults(Notification.DEFAULT_ALL) 116 | .setShowWhen(true) 117 | .build(); 118 | manager.notify(1,notification); 119 | wakeUpAndUnlock(this); 120 | doUpdateAlarmClock(); 121 | } 122 | 123 | long startTime = -1; 124 | List entries = null; 125 | 126 | long cycleDuration = -1; 127 | 128 | 129 | 130 | TimeEntry getCurrentTimeEntry(){ 131 | long elapsedTime = System.currentTimeMillis() - startTime; 132 | if(cycleDuration <0){ 133 | cycleDuration=0;//获取周期总长度 134 | for (TimeEntry entry: 135 | entries) { 136 | cycleDuration += entry.getDuration() * 1000L; 137 | } 138 | 139 | } 140 | long currentCycleElapsed = elapsedTime % cycleDuration;//当前周期的时间段 141 | long temp=0; 142 | TimeEntry last = entries.get(0); 143 | for (TimeEntry entry: 144 | entries) { 145 | temp += entry.getDuration() * 1000L; 146 | if(temp > currentCycleElapsed){ 147 | return entry; 148 | } 149 | last = entry; 150 | } 151 | return last; 152 | } 153 | 154 | //获取当前事件剩余时间 155 | long getEliminateTime(){ 156 | long elapsedTime = System.currentTimeMillis() - startTime; 157 | if(cycleDuration <0){ 158 | cycleDuration=0;//获取周期总长度 159 | for (TimeEntry entry: 160 | entries) { 161 | cycleDuration += entry.getDuration() * 1000L; 162 | } 163 | 164 | } 165 | long currentCycleElapsed = elapsedTime % cycleDuration;//当前周期的时间段 166 | long temp = currentCycleElapsed; 167 | for (TimeEntry entry: 168 | entries) { 169 | temp -= entry.getDuration() * 1000L; 170 | if(temp < 0){ 171 | return -temp; 172 | } 173 | } 174 | return -temp; 175 | } 176 | 177 | String long2TimeText(long l){ 178 | long totalseconds = l / 1000; 179 | long minute = totalseconds / 60; 180 | long second = totalseconds % 60; 181 | return String.format("%02d:%02d",minute,second); 182 | } 183 | 184 | Interpolator accelerate = new AccelerateDecelerateInterpolator(); 185 | Interpolator deaccelerate = new DecelerateInterpolator(); 186 | 187 | public void updateTime(){ 188 | TimeEntry current = getCurrentTimeEntry(); 189 | long eliminate = getEliminateTime(); 190 | long elapsedTime = current.getDuration() * 1000L - eliminate; 191 | txtClockDescription.setText(current.getName()); 192 | clockBackground.setBackgroundColor(current.getBackgroundColor()); 193 | txtClockTime.setText(long2TimeText(eliminate)); 194 | 195 | progressTime.setMax(current.getDuration() * 100); 196 | progressTime.setProgress(current.getDuration() * 100 - (int) (eliminate / 10)); 197 | 198 | float animationX = 1; 199 | float animationSize=1; 200 | if(eliminate<667){ 201 | animationX =(eliminate) / 667f; 202 | animationSize =2f- accelerate.getInterpolation(animationX); 203 | } 204 | if(elapsedTime < 667){ 205 | animationX =(elapsedTime) / 667f; 206 | animationSize = 0.5f + 0.5f * deaccelerate.getInterpolation(animationX); 207 | } 208 | 209 | Interpolator ip = new AccelerateDecelerateInterpolator(); 210 | 211 | clockBackground.setAlpha(animationX); 212 | clockBackground.setScaleX(animationSize); 213 | clockBackground.setScaleY(animationSize); 214 | } 215 | 216 | 217 | void updateAlarmClock(){ 218 | synchronized (alarmManager) { 219 | long nextTime = getEliminateTime() + System.currentTimeMillis(); 220 | PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, TimeOutReceiver.class), 0); 221 | AlarmManager.AlarmClockInfo next = alarmManager.getNextAlarmClock(); 222 | if (null != next) { 223 | if (nextTime == next.getTriggerTime()) { 224 | return; 225 | } else { 226 | alarmManager.cancel(pendingIntent); 227 | } 228 | } 229 | AlarmManager.AlarmClockInfo current = new AlarmManager.AlarmClockInfo(nextTime, pendingIntent); 230 | Log.d("MyAlarm","Set an alarm clock at "+new Date(nextTime).toString()); 231 | alarmManager.setAlarmClock(current, pendingIntent); 232 | } 233 | } 234 | 235 | void doUpdateAlarmClock(){ 236 | new Thread(){ 237 | @Override 238 | public void run() { 239 | updateAlarmClock(); 240 | } 241 | }.start(); 242 | } 243 | 244 | 245 | public static void wakeUpAndUnlock(Context context){ 246 | 247 | //获取电源管理器对象 248 | PowerManager pm=(PowerManager) context.getSystemService(Context.POWER_SERVICE); 249 | //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag 250 | PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | 251 | PowerManager.SCREEN_BRIGHT_WAKE_LOCK,"bright"); 252 | //点亮屏幕 253 | wl.acquire(); 254 | //释放 255 | wl.release(); 256 | } 257 | 258 | 259 | 260 | } 261 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.app.Dialog; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.graphics.Color; 10 | import android.os.Bundle; 11 | import android.text.TextUtils; 12 | import android.util.TypedValue; 13 | import android.view.Gravity; 14 | import android.view.LayoutInflater; 15 | import android.view.Menu; 16 | import android.view.MenuItem; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.widget.ArrayAdapter; 20 | import android.widget.Button; 21 | import android.widget.EditText; 22 | import android.widget.ImageButton; 23 | import android.widget.ImageView; 24 | import android.widget.LinearLayout; 25 | import android.widget.ListView; 26 | import android.widget.SeekBar; 27 | import android.widget.TextView; 28 | import android.widget.Toast; 29 | 30 | import com.zyfdroid.tomatoclock.model.TimeEntry; 31 | import com.zyfdroid.tomatoclock.util.AndroidUtils; 32 | import com.zyfdroid.tomatoclock.util.ICallback; 33 | import com.zyfdroid.tomatoclock.util.SpUtils; 34 | 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | 38 | public class MainActivity extends Activity { 39 | 40 | TimeEntryAdapter mAdapter = null; 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | if(SpUtils.getStatus()){ 46 | startActivity(new Intent(this,ClockActivity.class)); 47 | finish(); 48 | } 49 | 50 | setContentView(R.layout.activity_main); 51 | ((ListView)findViewById(R.id.listMain)).setAdapter(mAdapter = new TimeEntryAdapter(new ArrayList())); 52 | mAdapter.addAll(SpUtils.getCurrent()); 53 | 54 | 55 | } 56 | 57 | @Override 58 | protected void onPause() { 59 | super.onPause(); 60 | SpUtils.saveCurrent(mAdapter.toList()); 61 | } 62 | 63 | @Override 64 | public boolean onCreateOptionsMenu(Menu menu) { 65 | menu.add("预设").setIcon(R.drawable.ic_menu_settings).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 66 | @Override 67 | public boolean onMenuItemClick(MenuItem item) { 68 | 69 | new AlertDialog.Builder(MainActivity.this).setItems(new String[]{"默认模式","调试用"}, new DialogInterface.OnClickListener() { 70 | @Override 71 | public void onClick(DialogInterface dialog, int which) { 72 | if(which==0) { 73 | mAdapter.clear(); 74 | mAdapter.add(new TimeEntry("学习", 30 * 60, 0xFF43341B)); 75 | mAdapter.add(new TimeEntry("休息", 5 * 60, 0xFFF05E1C)); 76 | mAdapter.add(new TimeEntry("活动", 6 * 60, 0xFF90B44B)); 77 | } 78 | if(which==1) { 79 | mAdapter.clear(); 80 | mAdapter.add(new TimeEntry("1", 10, 0xFF43341B)); 81 | mAdapter.add(new TimeEntry("2", 15, 0xFFF05E1C)); 82 | mAdapter.add(new TimeEntry("3", 8, 0xFF90B44B)); 83 | } 84 | 85 | 86 | } 87 | }).setTitle("选择预设时间表").create().show(); 88 | 89 | return true; 90 | } 91 | }); 92 | 93 | menu.add("添加").setIcon(R.drawable.ic_menu_add).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 94 | @Override 95 | public boolean onMenuItemClick(MenuItem item) { 96 | onAddClick(null); 97 | return true; 98 | } 99 | }); 100 | 101 | menu.add("开始").setIcon(R.drawable.ic_menu_start).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 102 | @Override 103 | public boolean onMenuItemClick(MenuItem item) { 104 | if(mAdapter.getCount()<1){ 105 | Toast.makeText(MainActivity.this, "没有添加事件条目。", Toast.LENGTH_SHORT).show(); 106 | return true; 107 | } 108 | new AlertDialog.Builder(MainActivity.this).setTitle("启动番茄钟").setMessage("是否启动番茄钟?") 109 | .setPositiveButton("是的", new DialogInterface.OnClickListener() { 110 | @Override 111 | public void onClick(DialogInterface dialog, int which) { 112 | SpUtils.setStatus(true); 113 | SpUtils.setStartTime(System.currentTimeMillis()); 114 | startActivity(new Intent(MainActivity.this,ClockActivity.class)); 115 | finish(); 116 | } 117 | }).setNegativeButton("不是",null).create().show(); 118 | return true; 119 | } 120 | }); 121 | 122 | return super.onCreateOptionsMenu(menu); 123 | } 124 | 125 | 126 | 127 | public void onAddClick(View view) { 128 | new AddItemDialog(this, new ICallback() { 129 | @Override 130 | public void onCallback(TimeEntry value) { 131 | mAdapter.add(value); 132 | } 133 | }).show(); 134 | } 135 | 136 | class TimeEntryAdapter extends ArrayAdapter{ 137 | 138 | class TimeEntryViewHolder{ 139 | TextView txtItemText; 140 | ImageButton btnDelete; 141 | LinearLayout itemBackground; 142 | } 143 | 144 | public TimeEntryAdapter(List objects) { 145 | super(MainActivity.this, R.layout.adapter_time_entry,R.id.txtItemText, objects); 146 | } 147 | 148 | @Override 149 | public View getView(int position, View convertView, ViewGroup parent) { 150 | TimeEntryViewHolder holder = new TimeEntryViewHolder(); 151 | View v = null; 152 | if(convertView == null) 153 | { 154 | LayoutInflater inflater = getLayoutInflater(); 155 | v = inflater.inflate(R.layout.adapter_time_entry,null); 156 | holder.itemBackground = v.findViewById(R.id.itemBackground); 157 | holder.txtItemText = v.findViewById(R.id.txtItemText); 158 | holder.btnDelete = v.findViewById(R.id.btnDeleteItem); 159 | v.setTag(holder); 160 | } 161 | else 162 | { 163 | v = (LinearLayout) convertView; 164 | holder = (TimeEntryViewHolder) v.getTag(); 165 | } 166 | 167 | TimeEntry item = getItem(position); 168 | int minute = item.getDuration() / 60; 169 | holder.itemBackground.setBackgroundColor(item.getBackgroundColor()); 170 | holder.txtItemText.setText(item.getName()+" "+minute+"分钟"); 171 | holder.btnDelete.setOnClickListener(new ItemDeleter(item)); 172 | 173 | return v; 174 | } 175 | 176 | class ItemDeleter implements View.OnClickListener{ 177 | TimeEntry target; 178 | 179 | public ItemDeleter(TimeEntry target) { 180 | this.target = target; 181 | } 182 | 183 | @Override 184 | public void onClick(View v) { 185 | TimeEntryAdapter.this.remove(target); 186 | TimeEntryAdapter.this.notifyDataSetChanged(); 187 | } 188 | } 189 | 190 | public List toList(){ 191 | ArrayList result = new ArrayList<>(); 192 | for (int i = 0; i < getCount(); i++) { 193 | result.add(getItem(i)); 194 | } 195 | return result; 196 | } 197 | } 198 | 199 | class AddItemDialog extends Dialog{ 200 | 201 | public AddItemDialog(Context context,ICallback callback) { 202 | super(context); 203 | this.callback = callback; 204 | } 205 | 206 | ICallback callback; 207 | 208 | final int[] availableColors = { 209 | 0xFFE87A90, 210 | 0xFFF05E1C, 211 | 0xFF43341B, 212 | 0xFF90B44B, 213 | 0xFF1B813E, 214 | 0xFF33A6B8, 215 | 0xFF005CAF, 216 | 0xFF6A4C9C, 217 | 0xFFC1328E, 218 | 0xFF91989F, 219 | 0xFF3A3226, 220 | 0xFF434343, 221 | 0xFF080808 222 | }; 223 | 224 | final String[] predefines = { 225 | "学习","休息","活动","工作" 226 | //先弄这么多 227 | }; 228 | 229 | private int _selectedColor = 0xFFE87A90; 230 | 231 | @Override 232 | protected void onCreate(Bundle savedInstanceState) { 233 | super.onCreate(savedInstanceState); 234 | setContentView(R.layout.dialog_add); 235 | setTitle("添加时间段"); 236 | initUi(); 237 | 238 | btnYushe.setOnClickListener(new View.OnClickListener() { 239 | @Override 240 | public void onClick(View v) { 241 | new AlertDialog.Builder(getContext()).setItems(predefines, new OnClickListener() { 242 | @Override 243 | public void onClick(DialogInterface dialog, int which) { 244 | txtDescription.setText(predefines[which]); 245 | } 246 | }).create().show(); 247 | } 248 | }); 249 | numTime.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 250 | @Override 251 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 252 | valueChanged(seekBar.getProgress()+5); 253 | } 254 | 255 | @Override 256 | public void onStartTrackingTouch(SeekBar seekBar) { 257 | valueChanged(seekBar.getProgress()+5); 258 | 259 | } 260 | 261 | @Override 262 | public void onStopTrackingTouch(SeekBar seekBar) { 263 | valueChanged(seekBar.getProgress()+5); 264 | 265 | } 266 | 267 | void valueChanged(int value){ 268 | txtDurationText.setText("时长:"+(value)+"分钟"); 269 | } 270 | }); 271 | btnTimeMinus.setTag("-1"); 272 | btnTimePlus.setTag("1"); 273 | View.OnClickListener modifySeekbar = new View.OnClickListener() { 274 | @Override 275 | public void onClick(View v) { 276 | int delta = Integer.parseInt(v.getTag().toString()); 277 | numTime.setProgress(numTime.getProgress()+delta); 278 | } 279 | }; 280 | btnTimePlus.setOnClickListener(modifySeekbar); 281 | btnTimeMinus.setOnClickListener(modifySeekbar); 282 | 283 | View.OnClickListener colorPicker = new View.OnClickListener() { 284 | @Override 285 | public void onClick(View v) { 286 | _selectedColor = Integer.parseInt(v.getTag().toString()); 287 | for (TextView vi : 288 | colorPickerViews) { 289 | vi.setText(" "); 290 | } 291 | ((TextView)v).setText("√"); 292 | } 293 | }; 294 | 295 | int _4dp = AndroidUtils.dip2px(getContext(),4); 296 | 297 | for(int i=0;i colorPickerViews = new ArrayList<>(); 337 | 338 | Button btnConfirm = null; 339 | Button btnCancel = null; 340 | LinearLayout colorPickerPanel = null; 341 | Button btnTimePlus = null; 342 | SeekBar numTime = null; 343 | Button btnTimeMinus = null; 344 | TextView txtDurationText = null; 345 | Button btnYushe = null; 346 | EditText txtDescription = null; 347 | 348 | //ohhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 349 | 350 | void initUi(){ 351 | btnConfirm = (Button)findViewById(R.id.btnConfirm); 352 | btnCancel = (Button)findViewById(R.id.btnCancel); 353 | colorPickerPanel = (LinearLayout)findViewById(R.id.colorPickerPanel); 354 | btnTimePlus = (Button)findViewById(R.id.btnTimePlus); 355 | numTime = (SeekBar)findViewById(R.id.numTime); 356 | btnTimeMinus = (Button)findViewById(R.id.btnTimeMinus); 357 | txtDurationText = (TextView)findViewById(R.id.txtDurationText); 358 | btnYushe = (Button)findViewById(R.id.btnYushe); 359 | txtDescription = (EditText)findViewById(R.id.txtDescription); 360 | } 361 | 362 | 363 | 364 | 365 | } 366 | 367 | } 368 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/Program.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock; 2 | 3 | import android.app.Application; 4 | 5 | import com.zyfdroid.tomatoclock.util.SpUtils; 6 | 7 | /** 8 | * Created by WorldSkills2020 on 2/23/2020. 9 | */ 10 | 11 | public class Program extends Application { 12 | 13 | public static final String ACTION_CLOCK="com.zyfdroid.tomatoclock.ACTION_CLOCK"; 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | SpUtils.init(this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/TimeOutReceiver.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.PowerManager; 7 | 8 | public class TimeOutReceiver extends BroadcastReceiver { 9 | @Override 10 | public void onReceive(Context context, Intent intent) { 11 | if(null==ClockActivity.mInstance){ 12 | Intent i = new Intent(context,ClockActivity.class); 13 | i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 14 | i.putExtra("notification",true); 15 | context.startActivity(i); 16 | } 17 | else{ 18 | ClockActivity.mInstance.requireNotification(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/model/TimeEntry.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock.model; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | /** 7 | * Created by WorldSkills2020 on 2/23/2020. 8 | */ 9 | 10 | public class TimeEntry { 11 | String name; 12 | // 秒 13 | int duration; 14 | int backgroundColor; 15 | 16 | public TimeEntry(String name, int duration, int backgroundColor) { 17 | this.name = name; 18 | this.duration = duration; 19 | this.backgroundColor = backgroundColor; 20 | } 21 | 22 | public static TimeEntry fromJsonObject(JSONObject obj) throws JSONException { 23 | return new TimeEntry(obj.getString("name"),obj.getInt("duration"),obj.getInt("backgroundcolor")); 24 | } 25 | 26 | public JSONObject toJsonObject() throws JSONException { 27 | JSONObject obj = new JSONObject(); 28 | obj.put("name",name); 29 | obj.put("duration",duration); 30 | obj.put("backgroundcolor",backgroundColor); 31 | return obj; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public void setName(String name) { 39 | this.name = name; 40 | } 41 | 42 | public int getDuration() { 43 | return duration; 44 | } 45 | 46 | public void setDuration(int duration) { 47 | this.duration = duration; 48 | } 49 | 50 | public int getBackgroundColor() { 51 | return backgroundColor; 52 | } 53 | 54 | public void setBackgroundColor(int backgroundColor) { 55 | this.backgroundColor = backgroundColor; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/util/AndroidUtils.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by WorldSkills2020 on 2/23/2020. 7 | */ 8 | 9 | public class AndroidUtils { 10 | 11 | public static int dip2px(Context context, float dpValue) { 12 | float scale = context.getResources().getDisplayMetrics().density; 13 | return (int) (dpValue * scale + 0.5f); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/util/ICallback.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock.util; 2 | 3 | /** 4 | * Created by WorldSkills2020 on 2/23/2020. 5 | */ 6 | 7 | public interface ICallback { 8 | public void onCallback(T value); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/zyfdroid/tomatoclock/util/SpUtils.java: -------------------------------------------------------------------------------- 1 | package com.zyfdroid.tomatoclock.util; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.widget.Toast; 6 | 7 | import com.zyfdroid.tomatoclock.model.TimeEntry; 8 | 9 | import org.json.JSONArray; 10 | import org.json.JSONException; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by WorldSkills2020 on 2/23/2020. 17 | */ 18 | 19 | public class SpUtils { 20 | private static SharedPreferences sp = null; 21 | private static Context global; 22 | public static void init(Context ctx){ 23 | global = ctx.getApplicationContext(); 24 | sp = global.getSharedPreferences("default",Context.MODE_PRIVATE); 25 | } 26 | 27 | public static List getCurrent(){ 28 | ArrayList al = new ArrayList<>(); 29 | try { 30 | JSONArray jarr = new JSONArray(sp.getString("current","[]")); 31 | for (int i = 0; i < jarr.length(); i++) { 32 | al.add(TimeEntry.fromJsonObject(jarr.getJSONObject(i))); 33 | } 34 | } catch (JSONException e) { 35 | //不可能出现的情况 36 | Toast.makeText(global, "这不可能,你一定是做了什么修改,你这个肮脏的黑客", Toast.LENGTH_SHORT).show(); 37 | e.printStackTrace(); 38 | } 39 | return al; 40 | } 41 | 42 | public static void saveCurrent(List data){ 43 | JSONArray jsonArray = new JSONArray(); 44 | try { 45 | for (int i = 0; i < data.size(); i++) { 46 | jsonArray.put(data.get(i).toJsonObject()); 47 | } 48 | } catch (JSONException e) { 49 | //不可能出现的情况 50 | Toast.makeText(global, "不可能的情况发生了", Toast.LENGTH_SHORT).show(); 51 | e.printStackTrace(); 52 | } 53 | sp.edit().putString("current",jsonArray.toString()).commit(); 54 | } 55 | 56 | public static boolean getStatus(){ 57 | return sp.getBoolean("on",false); 58 | } 59 | public static void setStatus(boolean value){ 60 | sp.edit().putBoolean("on",value).commit(); 61 | } 62 | 63 | public static long getStartTime(){ 64 | return sp.getLong("startTime",-1); 65 | } 66 | public static void setStartTime(long value){ 67 | sp.edit().putLong("startTime",value).commit(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_list_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_list_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_menu_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_menu_start.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stat_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_stat_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-hdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_list_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_list_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_menu_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_menu_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_menu_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_menu_start.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_stat_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_stat_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZYFDroid/android-tomato-clock/faf2860ddd6d72e1f1742157f3c4f3903bda0454/app/src/main/res/drawable-xhdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_fab.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_fab_clock.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_clock.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 25 | 26 | 33 | 34 | 40 | 47 | 48 | 49 | 50 | 51 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 18 | 19 |